X-Git-Url: https://secure.softndesign.org/git/?a=blobdiff_plain;f=hexdump.c;h=02814449497c964194fcbd51abc6f53e08e42c1d;hb=HEAD;hp=c146b63797a4bd65a3c514a6da8db929d43240ee;hpb=4c4a10dd292a9c2316db808f90e7f33b7dc46aca;p=hexdump.git diff --git a/hexdump.c b/hexdump.c index c146b63..0281444 100644 --- a/hexdump.c +++ b/hexdump.c @@ -3,6 +3,7 @@ /* linker: debug.o */ #include +#include #include #include #include @@ -20,19 +21,28 @@ #define BUFFERSIZE 256 #define NBCOLS 8 #define NBDIGITS 6 +#define SEQLEN 32 /* gobal variables */ int nbcols = NBCOLS; int nbdigits = NBDIGITS; -int offset = 1; +int offset = 0; char buffer[BUFFERSIZE] = {0}; FILE *fin = NULL; -int addrfile = 0; +long int addrfile = 0; FILE *fout = NULL; char *progname = NULL; +/* type definitions */ + +typedef struct { + char *sequence; + char bytes[SEQLEN]; + int length; +} sequence_t; + /* help function */ int usage (int ret) @@ -46,9 +56,10 @@ int usage (int ret) fprintf (fd, " -o: output file\n"); fprintf (fd, " -v: verbose level (%d)\n", verbose); fprintf (fd, "\n"); - fprintf (fd, "commands: [/hstr/|0xaddr] [a hstr] [d nb|-] [i hstr] [p nb|-] [s/h1/h2/[g]]\n"); - fprintf (fd, " 0x: move to address addr\n"); - fprintf (fd, " //: move to hexa stringi hstr\n"); + fprintf (fd, "commands: [/hstr/|addr|+nb] [a hstr] [d nb|-] [i hstr] [p nb|-] [s/h1/h2/[g]]\n"); + fprintf (fd, " addr: move to address (0... octal, [1-9]... deci, 0x... hexa)\n"); + fprintf (fd, " +nb: move to offset (0... octal, [1-9]... deci, 0x... hexa)\n"); + fprintf (fd, " //: move to hexa string hstr\n"); fprintf (fd, " a : append hexa string hstr to current address\n"); fprintf (fd, " d : delete nb bytes (- until end file)\n"); fprintf (fd, " i : insert hexa string hstr to current address\n"); @@ -60,7 +71,7 @@ int usage (int ret) /* get number of digits */ -int getnbdigits (long int l) { +unsigned int getnbdigits (unsigned long int l) { int n = 0; while (l) { n += 2; @@ -71,12 +82,12 @@ int getnbdigits (long int l) { /* print a line */ -void printline (char *buffer, int nb, int addr) { +void printline (char *buffer, int nb, unsigned long int addr) { int i; - printf ("0x%0*x:", nbdigits, addr); + printf ("0x%0*lx:", nbdigits, addr); for (i = 0; i < nb; i++) { - printf (" %02x", buffer[i]); + printf (" %02x", (unsigned char)buffer[i]); } for (i = nb; i < nbcols; i++) { printf (" "); @@ -100,23 +111,22 @@ int writefile (char *pt, int nb) { /* search sequence function */ -int searchseq (char *seq) { +int searchseq (sequence_t *seq) { char *pt = buffer; int nb = 0; int i, j; int valid = 0; - int len = strlen (seq); - VERBOSE (DEBUG, printf ("search sequence: %s\n", seq)); + VERBOSE (DEBUG, printf ("search sequence: %s\n", seq->sequence)); while (!feof (fin)) { int nbread = fread (pt, 1, BUFFERSIZE - (pt - buffer), fin); nb += nbread; pt = buffer; - for (i = 0; i < nb - len; i++) { + for (i = 0; i < nb - seq->length; i++) { valid = 1; - for (j = 0; (j < len) && (valid); j++) { - if (pt[i + j] != seq[j]) { + for (j = 0; (j < seq->length) && (valid); j++) { + if (pt[i + j] != seq->bytes[j]) { valid = 0; } } @@ -126,32 +136,82 @@ int searchseq (char *seq) { } if (!valid) { - writefile (buffer, nb - len); + writefile (buffer, nb - seq->length); offset = 0; - addrfile += nb - len; - for (i = 0; i < len; i++) { - buffer[i] = buffer[nb - len + i]; + addrfile += nb - seq->length; + for (i = 0; i < seq->length; i++) { + buffer[i] = buffer[nb - seq->length + i]; } - pt = buffer + len; - nb = len; + pt = buffer + seq->length; + nb = seq->length; } else { writefile (buffer, i); - offset = len; + offset = seq->length; addrfile += i; fseek (fin, i - nb, SEEK_CUR); - VERBOSE (DEBUG, printf ("found sequence (%d)\n", i - nb)); + VERBOSE (DEBUG, printf ("found sequence at 0x%0*lx\n", getnbdigits (addrfile), addrfile)); return 0; } } if (!valid) { writefile (buffer, nb); - addrfile += len; + addrfile += seq->length; + } + + return 1; +} + +/* go to address function */ + +int gotoaddr (long int addr) { + char buffer[BUFFERSIZE] = {0}; + + if (addr == -1) { + addr = LONG_MAX; + } else if (addrfile > addr) { + return 1; + } + + VERBOSE (DEBUG, printf ("look for address: 0x%04lx\n", addr)); + while (!feof (fin)) { + int nbtoread = (addrfile + BUFFERSIZE > addr) ? addr - addrfile : BUFFERSIZE; + int nbread = fread (buffer, 1, nbtoread, fin); + writefile (buffer, nbread); + addrfile += nbread; + if (addrfile == addr) { + return 0; + } } return 1; } +/* insert sequence function */ + +int insertseq (sequence_t *seq) { + char buffer[BUFFERSIZE] = {0}; + + VERBOSE (DEBUG, printf ("insert (%d): '%s'\n", offset, seq->sequence); + int i; + for (i = 0; i < seq->length; i++) { + char c = seq->bytes[i]; + printf (" 0x%02x (%c)", c, ((c >= 32) && (c < 127)) ? c : '.'); + }; + printf ("\n")); + if (offset > 0) { + int nbread = fread (buffer, 1, offset, fin); + if (nbread != offset) { + return 1; + } + writefile (buffer, offset); + offset = 0; + } + writefile (seq->bytes, seq->length); + + return 0; +} + /* hexadecimal dump function */ int hexdump (int len) { @@ -204,17 +264,55 @@ int hexdump (int len) { return 0; } +/* parse octal string */ + +long int octal (char *s, int n) { + int i; + unsigned long int l = 0; + for (i = 0; i < n; i++) { + if ((s[i] >= '0') && (s[i] < '8')) { + l = l * 8 + s[i] - '0'; + } else { + return -1; + } + } + return l; +} + +/* parse hexa string */ + +long int hexa (char *s, int n) { + int i; + unsigned long int l = 0; + for (i = 0; i < n; i++) { + l *= 16; + if ((s[i] >= '0') && (s[i] <= '9')) { + l += s[i] - '0'; + } else if ((s[i] >= 'A') && (s[i] <= 'F')) { + l += s[i] + 10 - 'A'; + } else if ((s[i] >= 'a') && (s[i] <= 'f')) { + l += s[i] + 10 - 'a'; + } else { + return -1; + } + } + return l; +} + /* special character function */ -char *specialchar (char *s) { +int specialchar (char *s, char *b) { int i = 0, j = 0; while (s[i] != 0) { + if (j == SEQLEN) { + return 0; + } if (s[i] != '\\') { - s[j++] = s[i++]; + b[j++] = s[i++]; continue; } - int l = 0; + int l = -1; switch (s[i + 1]) { case 'a': l = 0x07; i += 2; break; case 'b': l = 0x08; i += 2; break; @@ -224,6 +322,7 @@ char *specialchar (char *s) { case 'r': l = 0x0d; i += 2; break; case 't': l = 0x09; i += 2; break; case 'v': l = 0x0b; i += 2; break; + case '/': l = '/'; i += 2; break; case '\\': l = '\\'; i += 2; break; case '\'': l = '\''; i += 2; break; case '"': l = '"'; i += 2; break; @@ -231,42 +330,127 @@ char *specialchar (char *s) { case '1': case '2': case '3': - if ((s[i + 2] >= '0') && (s[i + 2] <= '9') && - (s[i + 3] >= '0') && (s[i + 3] <= '9')) { - l = (s[i + 1] - '0') * 8 * 8 + (s[i + 2] - '0') * 8 + s[i + 3] - '0'; - i += 4; + l = octal (s + i + 1, 3); + if (l == -1) { + VERBOSE (WARNING, fprintf (stderr, "incorrect special char (\\%c%c%c)\n", s[i + 1], s[i + 2], s[i + 3])); } + i += 4; break; case 'x': - if ((((s[i + 2] >= '0') && (s[i + 2] <= '9')) || - ((s[i + 2] >= 'A') && (s[i + 2] <= 'F')) || - ((s[i + 2] >= 'a') && (s[i + 2] <= 'f'))) && - (((s[i + 3] >= '0') && (s[i + 3] <= '9')) || - ((s[i + 3] >= 'A') && (s[i + 3] <= 'F')) || - ((s[i + 3] >= 'a') && (s[i + 3] <= 'f')))) { - l = s[i + 2] - '0'; - if (s[i + 2] >= 'a') { - l += '0' + 10 - 'a'; - } else if (s[i + 2] >= 'A') { - l += '0' + 10 - 'A'; - } - l = l * 16 + s[i + 3] - '0'; - if (s[i + 3] >= 'a') { - l += '0' + 10 - 'a'; - } else if (s[i + 3] >= 'A') { - l += '0' + 10 - 'A'; - } - i += 4; + l = hexa (s + i + 2, 2); + if (l == -1) { + VERBOSE (WARNING, fprintf (stderr, "incorrect special char (\\x%c%c)\n", s[i + 2], s[i + 3])); } + i += 4; break; default: + VERBOSE (WARNING, fprintf (stderr, "incorrect special char (\\%c)\n", s[i + 1])); + i += 2; + break; + } + if (l != -1) { + VERBOSE (DEBUG, printf("l: 0x%02x '%c'\n", l, l)); + b[j++] = l; + } + } + + return j; +} + +/* remove space function */ + +void removespace (char *s, char **p) { + while (*s) { + if ((*s == ' ') || (*s == '\t')) { + s++; + } else { + break; + } + } + if (p != NULL) { + *p = s; + } +} + +/* get pattern function */ + +int getpattern (sequence_t *seq, char *s, char **p) { + + seq->sequence = s; + seq->length = 0; + + while (*s) { + if ((*s == '\\') && ((s[1] == '/') || (s[1] == '\\'))) { + s++; + } else if (*s == '/') { + *s++ = 0; + break; } - VERBOSE (DEBUG, printf("l: 0x%02x '%c'\n", l, l)); - s[j++] = (l != 0) ? l : s[i++]; + s++; + } + seq->length = specialchar (seq->sequence, seq->bytes); + + if (p != NULL) { + *p = s; } - s[j] = '\0'; - return s; + return (seq->length == 0); +} + +/* get hexa sequence function */ + +int gethexaseq (sequence_t *seq, char *s, char **p) { + int i = 0; + + seq->sequence = s; + seq->length = 0; + + while (*s) { + if (((*s >= '0') && (*s <= '9')) || + ((*s >= 'A') && (*s <= 'F')) || + ((*s >= 'a') && (*s <= 'f'))) { + s++; + i++; + if (i % 2 == 0) { + seq->bytes[seq->length] = hexa (seq->sequence + 2 * seq->length, 2); + if (seq->bytes[seq->length] == -1) { + return 1; + } + seq->length++; + } + } else { + break; + } + } + + if (p != NULL) { + *p = s; + } + + return (seq->length == 0) || (i % 2 == 1); +} + +/* get length function */ + +long int getlength (char *s, char **p) { + + while (*s != '\0') { + if ((*s == ' ') || (*s == '\t')) { + s++; + } else if ((*s >= '0') && (*s <= '9')) { + return strtol (s, p, 10); + } else if (*s == '-') { + if (p != NULL) { + *p = s + 1; + } + return -1; + } else { + VERBOSE (ERROR, fprintf (stderr, "unknown length (%s)\n", s)); + return 0; + } + } + + return 0; } /* main function */ @@ -277,9 +461,10 @@ int main (int argc, char *argv[]) char *input = NULL; char *output = NULL; char *commands = NULL; - int printlen = -1; - char *seq = NULL; - char *addr = NULL; + long int length = -1; + sequence_t seq = {0}; + unsigned long int addr = 0; + char c; /* get basename */ char *pt = progname = argv[0]; @@ -301,12 +486,14 @@ int main (int argc, char *argv[]) case 'e': arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; if (arg) { - arg = specialchar (arg); + //commands = (commands == NULL) ? arg : + // strcat (strcat (commands, " "), arg); if (commands == NULL) { commands = arg; } else { - strcat (commands, " "); - strcat (commands, arg); + char *tmp = (char *) malloc (strlen (arg) + 1); + strcat (strcat (commands, " "), strcpy (tmp, arg)); + free (tmp); } } break; @@ -339,14 +526,13 @@ int main (int argc, char *argv[]) } /* check input */ + fin = stdin; if (input) { fin = fopen (input, "rb"); if (!fin) { VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", input)); return 1; } - } else { - fin = stdin; } /* check output */ @@ -364,78 +550,159 @@ int main (int argc, char *argv[]) /* get file size */ if (fin != stdin) { fseek (fin, 0 , SEEK_END); - long int filesize = ftell (fin); + unsigned long int filesize = ftell (fin); fseek (fin, 0 , SEEK_SET); nbdigits = getnbdigits (filesize); } if (commands == NULL) { + VERBOSE (DEBUG, printf ("no command\n")); hexdump (-1); } else { VERBOSE (DEBUG, printf ("commands: %s\n", commands)); while ((*commands != '\0') && (rc == 0)) { - switch (*commands++) { + switch (c = *commands++) { case ' ': case '\t': break; - case '/': /* read patern */ - seq = commands; - while (*commands) { - if (*commands == '/') { - *commands++ = 0; - break; + case '/': /* search pattern */ + rc = getpattern (&seq, commands, &commands); + if (rc == 0) { + rc = searchseq (&seq); + if (rc == 1) { + VERBOSE (ERROR, fprintf (stderr, "can't find pattern '%s'\n", seq.sequence)); } + } else { + VERBOSE (ERROR, fprintf (stderr, "erroneous pattern \"%s'\n", seq.sequence)); + } + break; + + case '0': /* read address */ + if (*commands == 'x') { commands++; + addr = strtol (commands, &commands, 16); + } else { + addr = strtol (commands, &commands, 8); } - if (*seq != 0) { - rc = searchseq (seq); + if (addr) { + rc = gotoaddr (addr); + if (rc == 1) { + VERBOSE (ERROR, fprintf (stderr, "can't find address (0x%0*lx)\n", getnbdigits (addr), addr)); + } } else { - VERBOSE (ERROR, fprintf (stderr, "no sequence definied\n")); + VERBOSE (ERROR, fprintf (stderr, "erroneous address\n")); rc = 1; } + offset = 0; break; - case '0': /* read address */ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': /* read address */ + commands--; + addr = strtol (commands, &commands, 10); + if ((*commands != 0) && (*commands != ' ')) { + VERBOSE (ERROR, fprintf (stderr, "erroneous address ()\n")); + rc = 1; + } else { + rc = gotoaddr (addr); + if (rc == 1) { + VERBOSE (ERROR, fprintf (stderr, "can't find address (0x%0*lx)\n", getnbdigits (addr), addr)); + } + offset = 0; + } break; case 'a': /* append mode */ - break; - - case 'd': /* delete mode */ - break; + offset = 0; + /* fall through */ case 'i': /* insert mode */ + removespace (commands, &commands); + rc = gethexaseq (&seq, commands, &commands); + if (rc == 0) { + rc = insertseq (&seq); + if (rc == 1) { + VERBOSE (ERROR, fprintf (stderr, "can't jump (%d)\n", offset)); + } + } else { + VERBOSE (ERROR, fprintf (stderr, "erroneous sequence '%s'\n", seq.sequence)); + } + offset = 0; break; + case '+': /* relative move */ + /* fall through */ + + case 'd': /* delete mode */ + /* fall through */ + case 'p': /* print mode */ - printlen = -1; - while (*commands != '\0') { - if ((*commands == ' ') || (*commands == '\t')) { - commands++; - } else if ((*commands >= '0') && (*commands <= '9')) { - printlen = strtol (commands, &commands, 10); + length = getlength (commands, &commands); + if (length == 0){ + VERBOSE (ERROR, fprintf (stderr, "erroneous length\n")); + rc = 1; + } else { + switch (c) { + case '+': + rc = gotoaddr ((length > 0) ? addrfile + length : -1); + if (rc == 1) { + VERBOSE (ERROR, fprintf (stderr, "can't find address (0x%0*lx)\n", getnbdigits (addr), addr)); + } break; - } else if (*commands == '-') { - printlen = -1; - commands++; + + case 'd': + fseek (fin, length, SEEK_CUR); break; - } else { - VERBOSE (ERROR, fprintf (stderr, "unkown print lenght (%s)\n", commands)); - rc = 1; + + case 'p': + hexdump (length); break; } } - if (rc == 0) { - hexdump (printlen); - } + offset = 0; break; case 's': /* substitute mode */ + if (*commands == '/') { + rc = getpattern (&seq, ++commands, &commands); + if (rc == 0) { + rc = searchseq (&seq); + if (rc == 0) { + fseek (fin, offset, SEEK_CUR); + rc = gethexaseq (&seq, commands, &commands); + commands++; + if (rc == 0) { + offset = 0; + rc = insertseq (&seq); + if (rc == 1) { + VERBOSE (ERROR, fprintf (stderr, "can't jump (%d)\n", offset)); + } + } else { + VERBOSE (ERROR, fprintf (stderr, "erroneous sequence '%s'\n", seq.sequence)); + } + } else { + VERBOSE (ERROR, fprintf (stderr, "can't find pattern '%s'\n", seq.sequence)); + } + } else { + VERBOSE (ERROR, fprintf (stderr, "erroneous pattern '%s'\n", seq.sequence)); + } + } else { + VERBOSE (ERROR, fprintf (stderr, "erroneous sequence '%s'\n", seq.sequence)); + rc = 1; + } + offset = 0; break; default: - VERBOSE (ERROR, fprintf (stderr, "unknown command (%c)\n", commands[-1])); + VERBOSE (ERROR, fprintf (stderr, "unknown command '%c'\n", commands[-1])); rc = 1; } } @@ -459,16 +726,53 @@ int main (int argc, char *argv[]) } // test: hexdump.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }' +// test: hexdump.exe foo 2>&1 | grep -q 'invalid option' +// test: hexdump.exe -n 2>&1 | grep -q 'missing number of columns' +// test: hexdump.exe -v 2>&1 | grep -q 'missing verbose level' // test: hexdump.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }' // test: hexdump.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }' // test: hexdump.exe -i hexdump.c | grep -q '0x[0-9a-f]*: ' +// test: hexdump.exe -i hexdump.ko 2>&1 | grep -q "can't open file" +// test: hexdump.exe -i hexdump.c -o ko/test.c 2>&1 | grep -q "can't open file" +// test: cat hexdump.c | hexdump.exe -n 3 | head -2 | tail -1 | grep -q '0x000003: 64 65 70 dep' // test: hexdump.exe -i hexdump.c -n 3 | head -2 | tail -1 | grep -q '0x0003: 64 65 70 dep' +// test: hexdump.exe -i hexdump.c -v 3 -n 8 | grep -q 'no command' // test: hexdump.exe -i hexdump.c -o test.c -e 'p 200' | tail -1 | grep -q '0x00c0:' -// test: cmp hexdump.c test.c -// test: rm test.c -// test: hexdump.exe -i hexdump.c -e ' /cflags/ p 16 /debug/ p 8' | grep -q '0x0019: 2a 2f 0a 2f 2a 20 6c 69 \*/\./\* li' -// test: hexdump.exe -i hexdump.c -o test.c -e ' /cflags/ p 16 /debug/ p 8' | grep -q '0x0027: 64 65 62 75 67 2e 6f 20 debug.o' -// test: cmp hexdump.c test.c -// test: rm test.c +// test: cmp hexdump.c test.c; x=$?; rm test.c; test x$x = x0 +// test: hexdump.exe -i hexdump.c -n 8 -e ' /cflags/ p 17 /debug/ p 8' | grep -q '0x0019: 2a 2f 0a 2f 2a 20 6c 69 \*\/\./\* li' +// test: hexdump.exe -i hexdump.c -e ' /\099\411\xgg\y/' 2>&1 | grep -c 'incorrect special char' | xargs test 4 -eq +// test: hexdump.exe -i hexdump.c -o test.c -e ' /cfl\x61gs/ p 16 /d\145bug/ p 8' | grep -q '0x0027: 64 65 62 75 67 2e 6f 20 debug.o' +// test: cmp hexdump.c test.c; x=$?; rm test.c; test x$x = x0 +// test: hexdump.exe -i hexdump.c -e ' /\n/ p 8' | grep -q '0x000d: 0a 2f 2a 20 63 66 6c 61 \./\* cfla' +// test: hexdump.exe -i hexdump.c -o test.c -e ' /\a\b\e\f\r\t\v/ p 8'; x=$?; test x$x = x1 +// test: cmp hexdump.c test.c; x=$?; rm test.c; test x$x = x0 +// test: hexdump.exe -i hexdump.c -v 3 -e " /\'/" -e ' /\"/' -e ' /\\/' -e ' /\x2a/' -e ' /\x3A/' | grep l: | wc -l | xargs test 5 = +// test: hexdump.exe -i hexdump.c -e ' /\n\/* vim:/ p -' | grep -q ': 74 3a 20 2a 2f 0a *t: \*\/\.' +// test: hexdump.exe -i hexdump.c -e 'p go_to_end' 2>&1 | grep -q 'unknown length' +// test: hexdump.exe -i hexdump.c -e ' /\x41BCD/' 2>&1 | grep -q "can't find pattern" +// test: hexdump.exe -i hexdump.c -e ' //' 2>&1 | grep -q 'erroneous pattern' +// test: hexdump.exe -i hexdump.c -e 'foo' 2>&1 | grep -q 'unknown command' +// test: hexdump.exe -i hexdump.c -e '0x20 p 8 64 p 8 0200 p 16' | grep -q '0x0080:' +// test: hexdump.exe -i hexdump.c -e '07777777' 2>&1 | grep -q "can't find address" +// test: hexdump.exe -i hexdump.c -e '0xFFFFFF' 2>&1 | grep -q "can't find address" +// test: hexdump.exe -i hexdump.c -e '99999999' 2>&1 | grep -q "can't find address" +// test: hexdump.exe -i hexdump.c -e '+9999999' 2>&1 | grep -q "can't find address" +// test: hexdump.exe -i hexdump.c -e '09' 2>&1 | grep -q 'erroneous address' +// test: hexdump.exe -i hexdump.c -e '0xg' 2>&1 | grep -q 'erroneous address' +// test: hexdump.exe -i hexdump.c -e '1a' 2>&1 | grep -q 'erroneous address' +// test: hexdump.exe -i hexdump.c -o test.c -e ' /cflags/ a 414e5a /link/ i 2F333B' +// test: grep -q '[A]NZcflags' test.c && grep -q '[l]ink/3;er' test.c; x=$?; rm test.c; test x$x = x0 +// test: hexdump.exe -i hexdump.c -e ' /cflags/ a 414e5' 2>&1 | grep -q 'erroneous sequence' +// test: hexdump.exe -i hexdump.c -o test.c -e ' /lags/ d 2' +// test: grep -q '[c]fgs' test.c; x=$?; rm test.c; test x$x = x0 +// test: hexdump.exe -i hexdump.c -o test.c -e ' /lags/ +2 i 2041' +// test: grep -q '[c]fla Ags:' test.c; x=$?; rm test.c; test x$x = x0 +// test: hexdump.exe -i hexdump.c -o test.c -e ' s/lags/2041/' +// test: grep -q '[c]f A:' test.c; x=$?; rm test.c; test x$x = x0 +// test: hexdump.exe -i hexdump.c -e ' s' 2>&1 | grep -q 'erroneous sequence' +// test: hexdump.exe -i hexdump.c -e ' s//' 2>&1 | grep -q 'erroneous pattern' +// test: hexdump.exe -i hexdump.c -e ' s/\x41BCD/2041/' 2>&1 | grep -q "can't find pattern" +// test: hexdump.exe -i hexdump.c -e ' s/cflags/414e5/' 2>&1 | grep -q 'erroneous sequence' +// test: hexdump.exe -i hexdump.exe | grep -q 'ffff'; test x$? = x1 /* vim: set ts=4 sw=4 et: */