/************************************************************************/
/* */
/* Bakslash -- Provide C-style "\" escape encode/decode */
/* */
/* Although this module pretends to be a generic, reusable */
/* module, it is in fact specific to the interface offered */
/* by "grep" in more than a few ways. Requires some more */
/* interface routines and/or configuration options to be */
/* more useful. */
/* */
/* (Note for the pedantic: I've used "Bakslash" instead of */
/* "Backslash" since I'm trying to keep a strict one-to-one */
/* correspondence between module names and file names.) */
/* */
/* The implementation of this module could be optimised by */
/* using the Grouse FSA. behoffski has not done so because */
/* this is an after-hours project and he's focussing on the */
/* major function instead of nuances. Would be nice, though. */
/* */
/* Copyright (C) Grouse Software 1995-9. All rights reserved. */
/* Written for Grouse by behoffski (Brenton Hoff). */
/* */
/* Free software: no warranty; use anywhere is ok; spread the */
/* sources; note any mods; share variations and derivatives */
/* (including sending to behoffski@grouse.com.au). */
/* */
/************************************************************************/
#include "ascii.h"
#include "bakslash.h"
#include <compdef.h>
#include "ctype.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#define HEX2BYTE(ch) ((BYTE) (((ch)<='9') ? (ch)-'0' : tolower(ch) - 'a' + 10))
/************************************************************************/
/* */
/* Decode -- Convert text containing \ escapes to binary */
/* */
/************************************************************************/
public_scope BYTE
Bakslash_Decode(CHAR **ppLine)
{
CHAR *pLine = *ppLine;
CHAR ch;
/*Default to consuming one character*/
*ppLine = pLine + 1;
switch (*pLine) {
case '\\':
/*"\" literal*/
return (BYTE) '\\';
break;
case 'a':
/*Alert (bell)*/
return (BYTE) '\a';
break;
case 'b':
/*Backspace*/
return (BYTE) '\b';
break;
case 'f':
/*Form feed*/
return (BYTE) '\f';
break;
case 'n':
/*Newline*/
return (BYTE) '\n';
break;
case 'r':
/*Carriage return*/
return (BYTE) '\r';
break;
case 't':
/*Horizontal tab*/
return (BYTE) '\t';
break;
case 'v':
/*Vertical tab*/
return (BYTE) '\v';
break;
case 'x':
case 'X':
/*One- or two-digit hex sequence*/
ch = *++pLine;
if (! isxdigit(ch)) {
/*?? Not properly formed... treat as escaped "x"?*/
return (BYTE) pLine[-1];
}
/*Does the sequence contain two digits?*/
if (isxdigit(pLine[1])) {
/*Yes, consume them and decode now*/
*ppLine += 2;
/*?? Should consume ALL hex digits*/
return (HEX2BYTE(ch) << 4) | HEX2BYTE(pLine[1]);
} else {
/*No, consume one digit and return conversion*/
*ppLine += 1;
return HEX2BYTE(pLine[0]);
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
/*First digit of octal sequence... is second also octal?*/
ch = *++pLine;
if ((ch < '0') || (ch > '7')) {
/*No, merely single octal digit*/
return (BYTE) (pLine[-1] - '0');
}
/*Two-digit sequence... are all three chars one octal number?*/
if ((pLine[-1] > '3') || (pLine[1] < '0') ||
(pLine[1] > '7')) {
/*No, report two-digit code*/
*ppLine += 1;
return ((((BYTE) (pLine[-1] - '0')) << 3) |
((BYTE) (ch - '0')));
}
/*Three-digit octal sequence found*/
*ppLine += 2;
return (((BYTE) (pLine[-1] - '0')) << 6) |
(((BYTE) ( ch - '0')) << 3) |
((BYTE) ( pLine[1] - '0'));
break;
case NUL:
/*Unexpected end of line*/
fprintf(stderr, "%s: trailing backslash\n",
"ggrep");
exit(2);
break;
default:
/*Return character WITHOUT special meaning*/
return (BYTE) *pLine;
}
/*NOTREACHED*/
return 0xff;
} /*Decode*/
/************************************************************************/
/* */
/* DecodeLine -- Edit line to replace escape seq's */
/* */
/* Returns FALSE if the decoding was abandoned for any reason. */
/* */
/************************************************************************/
public_scope BOOL
Bakslash_DecodeLine(CHAR *pLine)
{
CHAR *pDecoded = pLine;
for (;;) {
switch (*pLine) {
case NUL:
/*End of line*/
*pDecoded = NUL;
return TRUE;
break;
case '\\':
/*Start of escape sequence found*/
pLine++;
*pDecoded++ = Bakslash_Decode(&pLine);
break;
default:
/*Copy literal to decoded string*/
*pDecoded++ = *pLine++;
break;
}
}
return TRUE;
} /*DecodeLine*/
/************************************************************************/
/* */
/* EncodeByte -- Provide printable encoding for byte */
/* */
/* Encoding will be typically two to no more than six bytes. */
/* */
/************************************************************************/
public_scope void
Bakslash_EncodeByte(BYTE b, CHAR *pEncoding)
{
/*Select encoding according to value*/
switch (b) {
case NUL:
strcpy(pEncoding, "\\0");
break;
case BEL:
strcpy(pEncoding, "\\a");
break;
case BS:
strcpy(pEncoding, "\\b");
break;
case FF:
strcpy(pEncoding, "\\f");
break;
case CR:
strcpy(pEncoding, "\\r");
break;
case LF:
strcpy(pEncoding, "\\n");
break;
case TAB:
strcpy(pEncoding, "\\t");
break;
case VT:
strcpy(pEncoding, "\\v");
break;
case '\\':
strcpy(pEncoding, "\\\\");
break;
case '"':
strcpy(pEncoding, "\\\"");
break;
case '\'':
strcpy(pEncoding, "\\'");
break;
default:
/*Is the character printable?*/
if (isprint(b)) {
/*Yes, report it as-is*/
sprintf(pEncoding, "%c", b);
break;
}
/*Report character as a \x escape*/
sprintf(pEncoding, "\\x%02x", b);
break;
}
} /*EncodeByte*/
/************************************************************************/
/* */
/* Init -- Prepare module for operation */
/* */
/************************************************************************/
public_scope void
Bakslash_Init(void)
{
/*No initialisation required*/
} /*Init*/