code cleaning
[hexdump.git] / hexdump.c
CommitLineData
a1ab98f9
LM
1/* depend: */
2/* cflags: */
3/* linker: debug.o */
4
5#include <assert.h>
a1ab98f9
LM
6#include <malloc.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include "debug.h"
12
13/* macros */
14
15#define CEIL(x, y) (((x) + (y) - 1) / (y))
16#define MIN(x, y) (((x) < (y)) ? (x) : (y))
17#define MAX(x, y) (((x) > (y)) ? (x) : (y))
18
19//#define BUFFERSIZE 4096
20#define BUFFERSIZE 256
21#define NBCOLS 8
4c4a10dd 22#define NBDIGITS 6
a1ab98f9
LM
23
24/* gobal variables */
25
4c4a10dd
LM
26int nbcols = NBCOLS;
27int nbdigits = NBDIGITS;
28int offset = 1;
29
30char buffer[BUFFERSIZE] = {0};
ce305529 31FILE *fin = NULL;
4c4a10dd 32int addrfile = 0;
ce305529 33FILE *fout = NULL;
a1ab98f9
LM
34char *progname = NULL;
35
36/* help function */
37
4c4a10dd 38int usage (int ret)
a1ab98f9
LM
39{
40 FILE *fd = ret ? stderr : stdout;
41 fprintf (fd, "usage: %s [-i file] [-h] [-n nbcols] [-o file] [-v]\n", progname);
5272fae8
LM
42 fprintf (fd, " -i: input file\n");
43 fprintf (fd, " -h: help message\n");
44 fprintf (fd, " -n: number of columns\n");
45 fprintf (fd, " -e: commands\n");
46 fprintf (fd, " -o: output file\n");
47 fprintf (fd, " -v: verbose level (%d)\n", verbose);
48 fprintf (fd, "\n");
49 fprintf (fd, "commands: [/hstr/|0xaddr] [a hstr] [d nb|-] [i hstr] [p nb|-] [s/h1/h2/[g]]\n");
50 fprintf (fd, " 0x: move to address addr\n");
51 fprintf (fd, " //: move to hexa stringi hstr\n");
52 fprintf (fd, " a : append hexa string hstr to current address\n");
53 fprintf (fd, " d : delete nb bytes (- until end file)\n");
54 fprintf (fd, " i : insert hexa string hstr to current address\n");
55 fprintf (fd, " p : print nb bytes (- until end file)\n");
56 fprintf (fd, " s : substitute h1 by h2 (g for globally)\n");
a1ab98f9 57
4c4a10dd 58 return ret;
a1ab98f9
LM
59}
60
61/* get number of digits */
62
63int getnbdigits (long int l) {
64 int n = 0;
65 while (l) {
66 n += 2;
67 l /= 256;
68 }
69 return n;
70}
71
72/* print a line */
73
4c4a10dd 74void printline (char *buffer, int nb, int addr) {
a1ab98f9
LM
75 int i;
76
77 printf ("0x%0*x:", nbdigits, addr);
78 for (i = 0; i < nb; i++) {
79 printf (" %02x", buffer[i]);
80 }
81 for (i = nb; i < nbcols; i++) {
82 printf (" ");
83 }
84 printf (" ");
85 for (i = 0; i < nb; i++) {
86 char c = buffer[i];
87 printf ("%c", (c > 31) && (c < 127) ? c : '.');
88 }
89 printf ("\n");
90}
91
ce305529 92/* write file function */
a1ab98f9 93
ce305529
LM
94int writefile (char *pt, int nb) {
95 if (fout) {
96 fwrite (pt, 1, nb, fout);
97 }
98 return 1;
99}
100
4c4a10dd
LM
101/* search sequence function */
102
103int searchseq (char *seq) {
104 char *pt = buffer;
105 int nb = 0;
106 int i, j;
107 int valid = 0;
108 int len = strlen (seq);
109
110 VERBOSE (DEBUG, printf ("search sequence: %s\n", seq));
111
112 while (!feof (fin)) {
113 int nbread = fread (pt, 1, BUFFERSIZE - (pt - buffer), fin);
114 nb += nbread;
115 pt = buffer;
116 for (i = 0; i < nb - len; i++) {
117 valid = 1;
118 for (j = 0; (j < len) && (valid); j++) {
119 if (pt[i + j] != seq[j]) {
120 valid = 0;
121 }
122 }
123 if (valid) {
124 break;
125 }
126 }
127
128 if (!valid) {
129 writefile (buffer, nb - len);
130 offset = 0;
131 addrfile += nb - len;
132 for (i = 0; i < len; i++) {
133 buffer[i] = buffer[nb - len + i];
134 }
135 pt = buffer + len;
136 nb = len;
137 } else {
138 writefile (buffer, i);
139 offset = len;
140 addrfile += i;
141 fseek (fin, i - nb, SEEK_CUR);
142 VERBOSE (DEBUG, printf ("found sequence (%d)\n", i - nb));
143 return 0;
144 }
145 }
146
147 if (!valid) {
148 writefile (buffer, nb);
149 addrfile += len;
150 }
151
152 return 1;
153}
154
ce305529
LM
155/* hexadecimal dump function */
156
4c4a10dd 157int hexdump (int len) {
a1ab98f9
LM
158 char buffer[BUFFERSIZE] = {0};
159 int i;
160
161 char *pt = buffer;
162
a1ab98f9
LM
163 int nb = 0;
164 while (!feof (fin)) {
5272fae8
LM
165 int nbtoread = BUFFERSIZE - (pt - buffer);
166 if ((len > 0) && (nbtoread > len)) {
167 nbtoread = len;
168 }
169 int nbread = fread (pt, 1, nbtoread, fin);
170 if (len > 0) {
171 len -= nbread;
172 }
173 nb += nbread;
a1ab98f9
LM
174 pt = buffer;
175
176 /* print line */
177 while ((nb - (int)(pt - buffer)) / nbcols > 0) {
4c4a10dd 178 printline (pt, nbcols, addrfile);
ce305529 179 writefile (pt, nbcols);
4c4a10dd 180 addrfile += nbcols;
a1ab98f9 181 pt += nbcols;
a1ab98f9
LM
182 }
183
184 /* copy end buffer */
185 nb -= pt - buffer;
186 for (i = 0; i < nb; i++) {
187 buffer[i] = pt[i];
188 }
189 pt = buffer + nb;
5272fae8
LM
190
191 /* end partial reading */
192 if (len == 0) {
193 break;
194 }
a1ab98f9
LM
195 }
196
197 /* last line */
198 if (nb > 0) {
4c4a10dd
LM
199 printline (buffer, nb, addrfile);
200 writefile (buffer, nb);
201 addrfile += nb;
a1ab98f9
LM
202 }
203
204 return 0;
205}
206
47db4fc7
LM
207/* parse octal string */
208
209long int octal (char *s, int n) {
210 int i;
211 long int l = 0;
212 for (i = 0; i < n; i++) {
213 if ((s[i] >= '0') && (s[i] <= '9')) {
214 l = l * 8 + s[i] - '0';
215 } else {
216 return -1;
217 }
218 }
219 return l;
220}
221
222/* parse hexa string */
223
224long int hexa (char *s, int n) {
225 int i;
226 long int l = 0;
227 for (i = 0; i < n; i++) {
228 l *= 16;
229 if ((s[i] >= '0') && (s[i] <= '9')) {
230 l += s[i] - '0';
231 } else if ((s[i] >= 'A') && (s[i] <= 'F')) {
232 l += s[i] + 10 - 'A';
233 } else if ((s[i] >= 'a') && (s[i] <= 'f')) {
234 l += s[i] + 10 - 'a';
235 } else {
236 return -1;
237 }
238 }
239 return l;
240}
241
4c4a10dd
LM
242/* special character function */
243
244char *specialchar (char *s) {
245 int i = 0, j = 0;
246 while (s[i] != 0) {
247 if (s[i] != '\\') {
248 s[j++] = s[i++];
249 continue;
250 }
251
47db4fc7 252 int l = -1;
4c4a10dd
LM
253 switch (s[i + 1]) {
254 case 'a': l = 0x07; i += 2; break;
255 case 'b': l = 0x08; i += 2; break;
256 case 'e': l = 0x1b; i += 2; break;
257 case 'f': l = 0x0c; i += 2; break;
258 case 'n': l = 0x0a; i += 2; break;
259 case 'r': l = 0x0d; i += 2; break;
260 case 't': l = 0x09; i += 2; break;
261 case 'v': l = 0x0b; i += 2; break;
262 case '\\': l = '\\'; i += 2; break;
263 case '\'': l = '\''; i += 2; break;
264 case '"': l = '"'; i += 2; break;
265 case '0':
266 case '1':
267 case '2':
268 case '3':
47db4fc7
LM
269 l = octal (s + 1, 3);
270 if (l != -1) {
4c4a10dd
LM
271 i += 4;
272 }
273 break;
274 case 'x':
47db4fc7
LM
275 l = hexa (s + 2, 2);
276 if (l != -1) {
4c4a10dd
LM
277 i += 4;
278 }
279 break;
280 default:
281 }
282 VERBOSE (DEBUG, printf("l: 0x%02x '%c'\n", l, l));
47db4fc7 283 s[j++] = (l != -1) ? l : s[i++];
4c4a10dd
LM
284 }
285 s[j] = '\0';
286
287 return s;
288}
289
a1ab98f9
LM
290/* main function */
291
4c4a10dd 292int main (int argc, char *argv[])
a1ab98f9 293{
5272fae8 294 int rc = 0;
a1ab98f9
LM
295 char *input = NULL;
296 char *output = NULL;
5272fae8
LM
297 char *commands = NULL;
298 int printlen = -1;
4c4a10dd
LM
299 char *seq = NULL;
300 char *addr = NULL;
301
a1ab98f9
LM
302 /* get basename */
303 char *pt = progname = argv[0];
304 while (*pt) {
305 if ((*pt == '/') || (*pt == '\\')) {
306 progname = pt + 1;
307 }
308 pt++;
309 }
310
4c4a10dd
LM
311 while (argc-- > 1) {
312 char *arg = *(++argv);
313 if (arg[0] != '-') {
314 VERBOSE (ERROR, fprintf (stderr, "%s: invalid option -- %s\n", progname, arg));
315 return usage (1);
316 }
317 char c = arg[1];
a1ab98f9 318 switch (c) {
5272fae8 319 case 'e':
4c4a10dd
LM
320 arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
321 if (arg) {
322 arg = specialchar (arg);
323 if (commands == NULL) {
324 commands = arg;
325 } else {
326 strcat (commands, " ");
327 strcat (commands, arg);
328 }
5272fae8
LM
329 }
330 break;
4c4a10dd
LM
331 case 'i':
332 input = (arg[2]) ? arg + 2 : (--argc > 0 ) ? *(++argv) : NULL;
333 break;
a1ab98f9 334 case 'n':
4c4a10dd
LM
335 arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
336 if (arg == NULL) {
337 VERBOSE (ERROR, fprintf (stderr, "%s: missing number of columns\n", progname));
338 return usage (1);
339 }
340 nbcols = atoi (arg);
a1ab98f9
LM
341 break;
342 case 'o':
4c4a10dd 343 output = (arg[2]) ? arg + 2 : (--argc > 0 ) ? *(++argv) : NULL;
a1ab98f9
LM
344 break;
345 case 'v':
4c4a10dd
LM
346 arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
347 if (arg == NULL) {
348 VERBOSE (ERROR, fprintf (stderr, "%s: missing verbose level\n", progname));
349 return usage (1);
350 }
351 verbose = atoi (arg);
a1ab98f9
LM
352 break;
353 case 'h':
354 default:
4c4a10dd 355 return usage (c != 'h');
a1ab98f9
LM
356 }
357 }
a1ab98f9
LM
358
359 /* check input */
a1ab98f9
LM
360 if (input) {
361 fin = fopen (input, "rb");
362 if (!fin) {
363 VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", input));
5272fae8 364 return 1;
a1ab98f9
LM
365 }
366 } else {
367 fin = stdin;
368 }
369
370 /* check output */
a1ab98f9 371 if (output) {
ce305529 372 fout = fopen (output, "wb");
a1ab98f9
LM
373 if (!fout) {
374 VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", output));
375 fclose (fin);
5272fae8 376 return 1;
a1ab98f9
LM
377 }
378 } else {
ce305529 379 //fout = stdout;
a1ab98f9
LM
380 }
381
4c4a10dd
LM
382 /* get file size */
383 if (fin != stdin) {
384 fseek (fin, 0 , SEEK_END);
385 long int filesize = ftell (fin);
386 fseek (fin, 0 , SEEK_SET);
387 nbdigits = getnbdigits (filesize);
388 }
389
5272fae8 390 if (commands == NULL) {
4c4a10dd 391 hexdump (-1);
5272fae8
LM
392 } else {
393 VERBOSE (DEBUG, printf ("commands: %s\n", commands));
394 while ((*commands != '\0') && (rc == 0)) {
395 switch (*commands++) {
396 case ' ':
397 case '\t':
398 break;
399
400 case '/': /* read patern */
4c4a10dd
LM
401 seq = commands;
402 while (*commands) {
403 if (*commands == '/') {
404 *commands++ = 0;
405 break;
406 }
407 commands++;
408 }
409 if (*seq != 0) {
410 rc = searchseq (seq);
411 } else {
412 VERBOSE (ERROR, fprintf (stderr, "no sequence definied\n"));
413 rc = 1;
414 }
5272fae8
LM
415 break;
416
417 case '0': /* read address */
418 break;
419
420 case 'a': /* append mode */
421 break;
422
423 case 'd': /* delete mode */
424 break;
425
426 case 'i': /* insert mode */
427 break;
428
429 case 'p': /* print mode */
430 printlen = -1;
431 while (*commands != '\0') {
432 if ((*commands == ' ') || (*commands == '\t')) {
433 commands++;
434 } else if ((*commands >= '0') && (*commands <= '9')) {
435 printlen = strtol (commands, &commands, 10);
436 break;
437 } else if (*commands == '-') {
438 printlen = -1;
439 commands++;
440 break;
441 } else {
442 VERBOSE (ERROR, fprintf (stderr, "unkown print lenght (%s)\n", commands));
443 rc = 1;
444 break;
445 }
446 }
4c4a10dd
LM
447 if (rc == 0) {
448 hexdump (printlen);
449 }
5272fae8
LM
450 break;
451
452 case 's': /* substitute mode */
453 break;
454
455 default:
456 VERBOSE (ERROR, fprintf (stderr, "unknown command (%c)\n", commands[-1]));
457 rc = 1;
458 }
459 }
460 }
a1ab98f9 461
ce305529
LM
462 /* end of file */
463 if ((rc == 0) && (fout != NULL)) {
464 while (!feof (fin)) {
465 int nbread = fread (buffer, 1, BUFFERSIZE, fin);
466 if (nbread) {
467 fwrite (buffer, 1, nbread, fout);
468 }
469 }
470 }
471
a1ab98f9 472 /* close all */
5272fae8
LM
473 if (fin) fclose (fin);
474 if (fout) fclose (fout);
a1ab98f9 475
5272fae8 476 return rc;
a1ab98f9
LM
477}
478
a1ab98f9
LM
479// test: hexdump.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
480// test: hexdump.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }'
481// test: hexdump.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
482// test: hexdump.exe -i hexdump.c | grep -q '0x[0-9a-f]*: '
ce305529
LM
483// test: hexdump.exe -i hexdump.c -n 3 | head -2 | tail -1 | grep -q '0x0003: 64 65 70 dep'
484// test: hexdump.exe -i hexdump.c -o test.c -e 'p 200' | tail -1 | grep -q '0x00c0:'
485// test: cmp hexdump.c test.c
486// test: rm test.c
4c4a10dd
LM
487// 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'
488// 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'
489// test: cmp hexdump.c test.c
490// test: rm test.c
a1ab98f9
LM
491
492/* vim: set ts=4 sw=4 et: */