/* linker: debug.o */
#include <assert.h>
+#include <limits.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
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;
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");
/* get number of digits */
-int getnbdigits (long int l) {
+unsigned int getnbdigits (unsigned long int l) {
int n = 0;
while (l) {
n += 2;
/* 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 (" ");
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;
}
}
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) {
long int octal (char *s, int n) {
int i;
- long int l = 0;
+ unsigned long int l = 0;
for (i = 0; i < n; i++) {
- if ((s[i] >= '0') && (s[i] <= '9')) {
+ if ((s[i] >= '0') && (s[i] < '8')) {
l = l * 8 + s[i] - '0';
} else {
return -1;
long int hexa (char *s, int n) {
int i;
- long int l = 0;
+ unsigned long int l = 0;
for (i = 0; i < n; i++) {
l *= 16;
if ((s[i] >= '0') && (s[i] <= '9')) {
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;
case '2':
case '3':
l = octal (s + i + 1, 3);
- if (l != -1) {
- i += 4;
+ 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':
l = hexa (s + i + 2, 2);
- if (l != -1) {
- i += 4;
+ 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;
}
- b[j++] = (l != -1) ? l : s[i++];
}
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;
+ }
+ s++;
+ }
+ seq->length = specialchar (seq->sequence, seq->bytes);
+
+ if (p != NULL) {
+ *p = 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 */
int main (int argc, char *argv[])
char *input = NULL;
char *output = NULL;
char *commands = NULL;
- int printlen = -1;
+ long int length = -1;
sequence_t seq = {0};
- char *addr = NULL;
+ unsigned long int addr = 0;
+ char c;
/* get basename */
char *pt = progname = argv[0];
case 'e':
arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
if (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;
}
/* 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 */
/* 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.sequence = 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);
}
- seq.length = specialchar (seq.sequence, seq.bytes);
- if (seq.length != 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, "incorrect sequence (%s)\n", seq.sequence));
+ 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 length (%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;
}
}
}
// 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; x=$?; rm test.c; test x$x = x0
-// test: hexdump.exe -i hexdump.c -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 -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 -e ' /\"/' -e " /\\'/" -e ' /\\/'
+// 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: */