16 #define CEIL(x, y) (((x) + (y) - 1) / (y))
17 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
18 #define MAX(x, y) (((x) > (y)) ? (x) : (y))
20 //#define BUFFERSIZE 4096
21 #define BUFFERSIZE 256
29 int nbdigits
= NBDIGITS
;
32 char buffer
[BUFFERSIZE
] = {0};
34 long int addrfile
= 0;
36 char *progname
= NULL
;
38 /* type definitions */
50 FILE *fd
= ret
? stderr
: stdout
;
51 fprintf (fd
, "usage: %s [-i file] [-h] [-n nbcols] [-o file] [-v]\n", progname
);
52 fprintf (fd
, " -i: input file\n");
53 fprintf (fd
, " -h: help message\n");
54 fprintf (fd
, " -n: number of columns\n");
55 fprintf (fd
, " -e: commands\n");
56 fprintf (fd
, " -o: output file\n");
57 fprintf (fd
, " -v: verbose level (%d)\n", verbose
);
59 fprintf (fd
, "commands: [/hstr/|addr|+nb] [a hstr] [d nb|-] [i hstr] [p nb|-] [s/h1/h2/[g]]\n");
60 fprintf (fd
, " addr: move to address (0... octal, [1-9]... deci, 0x... hexa)\n");
61 fprintf (fd
, " +nb: move to offset (0... octal, [1-9]... deci, 0x... hexa)\n");
62 fprintf (fd
, " //: move to hexa string hstr\n");
63 fprintf (fd
, " a : append hexa string hstr to current address\n");
64 fprintf (fd
, " d : delete nb bytes (- until end file)\n");
65 fprintf (fd
, " i : insert hexa string hstr to current address\n");
66 fprintf (fd
, " p : print nb bytes (- until end file)\n");
67 fprintf (fd
, " s : substitute h1 by h2 (g for globally)\n");
72 /* get number of digits */
74 unsigned int getnbdigits (unsigned long int l
) {
85 void printline (char *buffer
, int nb
, unsigned long int addr
) {
88 printf ("0x%0*lx:", nbdigits
, addr
);
89 for (i
= 0; i
< nb
; i
++) {
90 printf (" %02x", (unsigned char)buffer
[i
]);
92 for (i
= nb
; i
< nbcols
; i
++) {
96 for (i
= 0; i
< nb
; i
++) {
98 printf ("%c", (c
> 31) && (c
< 127) ? c
: '.');
103 /* write file function */
105 int writefile (char *pt
, int nb
) {
107 fwrite (pt
, 1, nb
, fout
);
112 /* search sequence function */
114 int searchseq (sequence_t
*seq
) {
120 VERBOSE (DEBUG
, printf ("search sequence: %s\n", seq
->sequence
));
122 while (!feof (fin
)) {
123 int nbread
= fread (pt
, 1, BUFFERSIZE
- (pt
- buffer
), fin
);
126 for (i
= 0; i
< nb
- seq
->length
; i
++) {
128 for (j
= 0; (j
< seq
->length
) && (valid
); j
++) {
129 if (pt
[i
+ j
] != seq
->bytes
[j
]) {
139 writefile (buffer
, nb
- seq
->length
);
141 addrfile
+= nb
- seq
->length
;
142 for (i
= 0; i
< seq
->length
; i
++) {
143 buffer
[i
] = buffer
[nb
- seq
->length
+ i
];
145 pt
= buffer
+ seq
->length
;
148 writefile (buffer
, i
);
149 offset
= seq
->length
;
151 fseek (fin
, i
- nb
, SEEK_CUR
);
152 VERBOSE (DEBUG
, printf ("found sequence at 0x%0*lx\n", getnbdigits (addrfile
), addrfile
));
158 writefile (buffer
, nb
);
159 addrfile
+= seq
->length
;
165 /* go to address function */
167 int gotoaddr (long int addr
) {
168 char buffer
[BUFFERSIZE
] = {0};
172 } else if (addrfile
> addr
) {
176 VERBOSE (DEBUG
, printf ("look for address: 0x%04lx\n", addr
));
177 while (!feof (fin
)) {
178 int nbtoread
= (addrfile
+ BUFFERSIZE
> addr
) ? addr
- addrfile
: BUFFERSIZE
;
179 int nbread
= fread (buffer
, 1, nbtoread
, fin
);
180 writefile (buffer
, nbread
);
182 if (addrfile
== addr
) {
190 /* insert sequence function */
192 int insertseq (sequence_t
*seq
) {
193 char buffer
[BUFFERSIZE
] = {0};
195 VERBOSE (DEBUG
, printf ("insert (%d): '%s'\n", offset
, seq
->sequence
);
197 for (i
= 0; i
< seq
->length
; i
++) {
198 char c
= seq
->bytes
[i
];
199 printf (" 0x%02x (%c)", c
, ((c
>= 32) && (c
< 127)) ? c
: '.');
203 int nbread
= fread (buffer
, 1, offset
, fin
);
204 if (nbread
!= offset
) {
207 writefile (buffer
, offset
);
210 writefile (seq
->bytes
, seq
->length
);
215 /* hexadecimal dump function */
217 int hexdump (int len
) {
218 char buffer
[BUFFERSIZE
] = {0};
224 while (!feof (fin
)) {
225 int nbtoread
= BUFFERSIZE
- (pt
- buffer
);
226 if ((len
> 0) && (nbtoread
> len
)) {
229 int nbread
= fread (pt
, 1, nbtoread
, fin
);
237 while ((nb
- (int)(pt
- buffer
)) / nbcols
> 0) {
238 printline (pt
, nbcols
, addrfile
);
239 writefile (pt
, nbcols
);
244 /* copy end buffer */
246 for (i
= 0; i
< nb
; i
++) {
251 /* end partial reading */
259 printline (buffer
, nb
, addrfile
);
260 writefile (buffer
, nb
);
267 /* parse octal string */
269 long int octal (char *s
, int n
) {
271 unsigned long int l
= 0;
272 for (i
= 0; i
< n
; i
++) {
273 if ((s
[i
] >= '0') && (s
[i
] < '8')) {
274 l
= l
* 8 + s
[i
] - '0';
282 /* parse hexa string */
284 long int hexa (char *s
, int n
) {
286 unsigned long int l
= 0;
287 for (i
= 0; i
< n
; i
++) {
289 if ((s
[i
] >= '0') && (s
[i
] <= '9')) {
291 } else if ((s
[i
] >= 'A') && (s
[i
] <= 'F')) {
292 l
+= s
[i
] + 10 - 'A';
293 } else if ((s
[i
] >= 'a') && (s
[i
] <= 'f')) {
294 l
+= s
[i
] + 10 - 'a';
302 /* special character function */
304 int specialchar (char *s
, char *b
) {
317 case 'a': l
= 0x07; i
+= 2; break;
318 case 'b': l
= 0x08; i
+= 2; break;
319 case 'e': l
= 0x1b; i
+= 2; break;
320 case 'f': l
= 0x0c; i
+= 2; break;
321 case 'n': l
= 0x0a; i
+= 2; break;
322 case 'r': l
= 0x0d; i
+= 2; break;
323 case 't': l
= 0x09; i
+= 2; break;
324 case 'v': l
= 0x0b; i
+= 2; break;
325 case '/': l
= '/'; i
+= 2; break;
326 case '\\': l
= '\\'; i
+= 2; break;
327 case '\'': l
= '\''; i
+= 2; break;
328 case '"': l
= '"'; i
+= 2; break;
333 l
= octal (s
+ i
+ 1, 3);
335 VERBOSE (WARNING
, fprintf (stderr
, "incorrect special char (\\%c%c%c)\n", s
[i
+ 1], s
[i
+ 2], s
[i
+ 3]));
340 l
= hexa (s
+ i
+ 2, 2);
342 VERBOSE (WARNING
, fprintf (stderr
, "incorrect special char (\\x%c%c)\n", s
[i
+ 2], s
[i
+ 3]));
347 VERBOSE (WARNING
, fprintf (stderr
, "incorrect special char (\\%c)\n", s
[i
+ 1]));
352 VERBOSE (DEBUG
, printf("l: 0x%02x '%c'\n", l
, l
));
360 /* remove space function */
362 void removespace (char *s
, char **p
) {
364 if ((*s
== ' ') || (*s
== '\t')) {
375 /* get pattern function */
377 int getpattern (sequence_t
*seq
, char *s
, char **p
) {
383 if ((*s
== '\\') && ((s
[1] == '/') || (s
[1] == '\\'))) {
385 } else if (*s
== '/') {
391 seq
->length
= specialchar (seq
->sequence
, seq
->bytes
);
397 return (seq
->length
== 0);
400 /* get hexa sequence function */
402 int gethexaseq (sequence_t
*seq
, char *s
, char **p
) {
409 if (((*s
>= '0') && (*s
<= '9')) ||
410 ((*s
>= 'A') && (*s
<= 'F')) ||
411 ((*s
>= 'a') && (*s
<= 'f'))) {
415 seq
->bytes
[seq
->length
] = hexa (seq
->sequence
+ 2 * seq
->length
, 2);
416 if (seq
->bytes
[seq
->length
] == -1) {
430 return (seq
->length
== 0) || (i
% 2 == 1);
433 /* get length function */
435 long int getlength (char *s
, char **p
) {
438 if ((*s
== ' ') || (*s
== '\t')) {
440 } else if ((*s
>= '0') && (*s
<= '9')) {
441 return strtol (s
, p
, 10);
442 } else if (*s
== '-') {
448 VERBOSE (ERROR
, fprintf (stderr
, "unknown length (%s)\n", s
));
458 int main (int argc
, char *argv
[])
463 char *commands
= NULL
;
464 long int length
= -1;
465 sequence_t seq
= {0};
466 unsigned long int addr
= 0;
470 char *pt
= progname
= argv
[0];
472 if ((*pt
== '/') || (*pt
== '\\')) {
479 char *arg
= *(++argv
);
481 VERBOSE (ERROR
, fprintf (stderr
, "%s: invalid option -- %s\n", progname
, arg
));
487 arg
= (arg
[2]) ? arg
+ 2 : (--argc
> 0) ? *(++argv
) : NULL
;
489 //commands = (commands == NULL) ? arg :
490 // strcat (strcat (commands, " "), arg);
491 if (commands
== NULL
) {
494 char *tmp
= (char *) malloc (strlen (arg
) + 1);
495 strcat (strcat (commands
, " "), strcpy (tmp
, arg
));
501 input
= (arg
[2]) ? arg
+ 2 : (--argc
> 0 ) ? *(++argv
) : NULL
;
504 arg
= (arg
[2]) ? arg
+ 2 : (--argc
> 0) ? *(++argv
) : NULL
;
506 VERBOSE (ERROR
, fprintf (stderr
, "%s: missing number of columns\n", progname
));
512 output
= (arg
[2]) ? arg
+ 2 : (--argc
> 0 ) ? *(++argv
) : NULL
;
515 arg
= (arg
[2]) ? arg
+ 2 : (--argc
> 0) ? *(++argv
) : NULL
;
517 VERBOSE (ERROR
, fprintf (stderr
, "%s: missing verbose level\n", progname
));
520 verbose
= atoi (arg
);
524 return usage (c
!= 'h');
531 fin
= fopen (input
, "rb");
533 VERBOSE (ERROR
, fprintf (stderr
, "error: can't open file '%s'\n", input
));
540 fout
= fopen (output
, "wb");
542 VERBOSE (ERROR
, fprintf (stderr
, "error: can't open file '%s'\n", output
));
552 fseek (fin
, 0 , SEEK_END
);
553 unsigned long int filesize
= ftell (fin
);
554 fseek (fin
, 0 , SEEK_SET
);
555 nbdigits
= getnbdigits (filesize
);
558 if (commands
== NULL
) {
559 VERBOSE (DEBUG
, printf ("no command\n"));
562 VERBOSE (DEBUG
, printf ("commands: %s\n", commands
));
563 while ((*commands
!= '\0') && (rc
== 0)) {
564 switch (c
= *commands
++) {
569 case '/': /* search pattern */
570 rc
= getpattern (&seq
, commands
, &commands
);
572 rc
= searchseq (&seq
);
574 VERBOSE (ERROR
, fprintf (stderr
, "can't find pattern '%s'\n", seq
.sequence
));
577 VERBOSE (ERROR
, fprintf (stderr
, "erroneous pattern \"%s'\n", seq
.sequence
));
581 case '0': /* read address */
582 if (*commands
== 'x') {
584 addr
= strtol (commands
, &commands
, 16);
586 addr
= strtol (commands
, &commands
, 8);
589 rc
= gotoaddr (addr
);
591 VERBOSE (ERROR
, fprintf (stderr
, "can't find address (0x%0*lx)\n", getnbdigits (addr
), addr
));
594 VERBOSE (ERROR
, fprintf (stderr
, "erroneous address\n"));
608 case '9': /* read address */
610 addr
= strtol (commands
, &commands
, 10);
611 if ((*commands
!= 0) && (*commands
!= ' ')) {
612 VERBOSE (ERROR
, fprintf (stderr
, "erroneous address ()\n"));
615 rc
= gotoaddr (addr
);
617 VERBOSE (ERROR
, fprintf (stderr
, "can't find address (0x%0*lx)\n", getnbdigits (addr
), addr
));
623 case 'a': /* append mode */
627 case 'i': /* insert mode */
628 removespace (commands
, &commands
);
629 rc
= gethexaseq (&seq
, commands
, &commands
);
631 rc
= insertseq (&seq
);
633 VERBOSE (ERROR
, fprintf (stderr
, "can't jump (%d)\n", offset
));
636 VERBOSE (ERROR
, fprintf (stderr
, "erroneous sequence '%s'\n", seq
.sequence
));
641 case '+': /* relative move */
644 case 'd': /* delete mode */
647 case 'p': /* print mode */
648 length
= getlength (commands
, &commands
);
650 VERBOSE (ERROR
, fprintf (stderr
, "erroneous length\n"));
655 rc
= gotoaddr ((length
> 0) ? addrfile
+ length
: -1);
657 VERBOSE (ERROR
, fprintf (stderr
, "can't find address (0x%0*lx)\n", getnbdigits (addr
), addr
));
662 fseek (fin
, length
, SEEK_CUR
);
673 case 's': /* substitute mode */
674 if (*commands
== '/') {
675 rc
= getpattern (&seq
, ++commands
, &commands
);
677 rc
= searchseq (&seq
);
679 fseek (fin
, offset
, SEEK_CUR
);
680 rc
= gethexaseq (&seq
, commands
, &commands
);
684 rc
= insertseq (&seq
);
686 VERBOSE (ERROR
, fprintf (stderr
, "can't jump (%d)\n", offset
));
689 VERBOSE (ERROR
, fprintf (stderr
, "erroneous sequence '%s'\n", seq
.sequence
));
692 VERBOSE (ERROR
, fprintf (stderr
, "can't find pattern '%s'\n", seq
.sequence
));
695 VERBOSE (ERROR
, fprintf (stderr
, "erroneous pattern '%s'\n", seq
.sequence
));
698 VERBOSE (ERROR
, fprintf (stderr
, "erroneous sequence '%s'\n", seq
.sequence
));
705 VERBOSE (ERROR
, fprintf (stderr
, "unknown command '%c'\n", commands
[-1]));
712 if ((rc
== 0) && (fout
!= NULL
)) {
713 while (!feof (fin
)) {
714 int nbread
= fread (buffer
, 1, BUFFERSIZE
, fin
);
716 fwrite (buffer
, 1, nbread
, fout
);
722 if (fin
) fclose (fin
);
723 if (fout
) fclose (fout
);
728 // test: hexdump.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
729 // test: hexdump.exe foo 2>&1 | grep -q 'invalid option'
730 // test: hexdump.exe -n 2>&1 | grep -q 'missing number of columns'
731 // test: hexdump.exe -v 2>&1 | grep -q 'missing verbose level'
732 // test: hexdump.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }'
733 // test: hexdump.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
734 // test: hexdump.exe -i hexdump.c | grep -q '0x[0-9a-f]*: '
735 // test: hexdump.exe -i hexdump.ko 2>&1 | grep -q "can't open file"
736 // test: hexdump.exe -i hexdump.c -o ko/test.c 2>&1 | grep -q "can't open file"
737 // test: cat hexdump.c | hexdump.exe -n 3 | head -2 | tail -1 | grep -q '0x000003: 64 65 70 dep'
738 // test: hexdump.exe -i hexdump.c -n 3 | head -2 | tail -1 | grep -q '0x0003: 64 65 70 dep'
739 // test: hexdump.exe -i hexdump.c -v 3 -n 8 | grep -q 'no command'
740 // test: hexdump.exe -i hexdump.c -o test.c -e 'p 200' | tail -1 | grep -q '0x00c0:'
741 // test: cmp hexdump.c test.c; x=$?; rm test.c; test x$x = x0
742 // 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'
743 // test: hexdump.exe -i hexdump.c -e ' /\099\411\xgg\y/' 2>&1 | grep -c 'incorrect special char' | xargs test 4 -eq
744 // 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'
745 // test: cmp hexdump.c test.c; x=$?; rm test.c; test x$x = x0
746 // test: hexdump.exe -i hexdump.c -e ' /\n/ p 8' | grep -q '0x000d: 0a 2f 2a 20 63 66 6c 61 \./\* cfla'
747 // test: hexdump.exe -i hexdump.c -o test.c -e ' /\a\b\e\f\r\t\v/ p 8'; x=$?; test x$x = x1
748 // test: cmp hexdump.c test.c; x=$?; rm test.c; test x$x = x0
749 // test: hexdump.exe -i hexdump.c -v 3 -e " /\'/" -e ' /\"/' -e ' /\\/' -e ' /\x2a/' -e ' /\x3A/' | grep l: | wc -l | xargs test 5 =
750 // test: hexdump.exe -i hexdump.c -e ' /\n\/* vim:/ p -' | grep -q ': 74 3a 20 2a 2f 0a *t: \*\/\.'
751 // test: hexdump.exe -i hexdump.c -e 'p go_to_end' 2>&1 | grep -q 'unknown length'
752 // test: hexdump.exe -i hexdump.c -e ' /\x41BCD/' 2>&1 | grep -q "can't find pattern"
753 // test: hexdump.exe -i hexdump.c -e ' //' 2>&1 | grep -q 'erroneous pattern'
754 // test: hexdump.exe -i hexdump.c -e 'foo' 2>&1 | grep -q 'unknown command'
755 // test: hexdump.exe -i hexdump.c -e '0x20 p 8 64 p 8 0200 p 16' | grep -q '0x0080:'
756 // test: hexdump.exe -i hexdump.c -e '07777777' 2>&1 | grep -q "can't find address"
757 // test: hexdump.exe -i hexdump.c -e '0xFFFFFF' 2>&1 | grep -q "can't find address"
758 // test: hexdump.exe -i hexdump.c -e '99999999' 2>&1 | grep -q "can't find address"
759 // test: hexdump.exe -i hexdump.c -e '+9999999' 2>&1 | grep -q "can't find address"
760 // test: hexdump.exe -i hexdump.c -e '09' 2>&1 | grep -q 'erroneous address'
761 // test: hexdump.exe -i hexdump.c -e '0xg' 2>&1 | grep -q 'erroneous address'
762 // test: hexdump.exe -i hexdump.c -e '1a' 2>&1 | grep -q 'erroneous address'
763 // test: hexdump.exe -i hexdump.c -o test.c -e ' /cflags/ a 414e5a /link/ i 2F333B'
764 // test: grep -q '[A]NZcflags' test.c && grep -q '[l]ink/3;er' test.c; x=$?; rm test.c; test x$x = x0
765 // test: hexdump.exe -i hexdump.c -e ' /cflags/ a 414e5' 2>&1 | grep -q 'erroneous sequence'
766 // test: hexdump.exe -i hexdump.c -o test.c -e ' /lags/ d 2'
767 // test: grep -q '[c]fgs' test.c; x=$?; rm test.c; test x$x = x0
768 // test: hexdump.exe -i hexdump.c -o test.c -e ' /lags/ +2 i 2041'
769 // test: grep -q '[c]fla Ags:' test.c; x=$?; rm test.c; test x$x = x0
770 // test: hexdump.exe -i hexdump.c -o test.c -e ' s/lags/2041/'
771 // test: grep -q '[c]f A:' test.c; x=$?; rm test.c; test x$x = x0
772 // test: hexdump.exe -i hexdump.c -e ' s' 2>&1 | grep -q 'erroneous sequence'
773 // test: hexdump.exe -i hexdump.c -e ' s//' 2>&1 | grep -q 'erroneous pattern'
774 // test: hexdump.exe -i hexdump.c -e ' s/\x41BCD/2041/' 2>&1 | grep -q "can't find pattern"
775 // test: hexdump.exe -i hexdump.c -e ' s/cflags/414e5/' 2>&1 | grep -q 'erroneous sequence'
776 // test: hexdump.exe -i hexdump.exe | grep -q 'ffff'; test x$? = x1
778 /* vim: set ts=4 sw=4 et: */