10d5a8d63159790ec3bccc9c08961b922b146fe1
[oweals/busybox.git] / libbb / dump.c
1 /*
2  * Support code for the hexdump and od applets,
3  * based on code from util-linux v 2.11l
4  *
5  * Copyright (c) 1989
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  * Original copyright notice is retained at the end of this file.
23  */
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>              /* for isdigit() */
28 #include "dump.h"
29 #include "libbb.h"
30
31 enum _vflag vflag = FIRST;
32 FS *fshead;                             /* head of format strings */
33 extern FS *fshead;                              /* head of format strings */
34 extern int blocksize;
35 static FU *endfu;
36 static char **_argv;
37 static off_t savaddress;                /* saved address/offset in stream */
38 static off_t eaddress;                  /* end address */
39 static off_t address;                   /* address/offset in stream */
40 off_t skip;                      /* bytes to skip */
41 off_t saveaddress;
42 int exitval;                            /* final exit value */
43 int blocksize;                          /* data block size */
44 int length = -1;                        /* max bytes to read */
45
46
47 int size(FS *fs)
48 {
49         register FU *fu;
50         register int bcnt, cursize;
51         register char *fmt;
52         int prec;
53
54         /* figure out the data block size needed for each format unit */
55         for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
56                 if (fu->bcnt) {
57                         cursize += fu->bcnt * fu->reps;
58                         continue;
59                 }
60                 for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
61                         if (*fmt != '%')
62                                 continue;
63                         /*
64                          * skip any special chars -- save precision in
65                          * case it's a %s format.
66                          */
67                         while (index(".#-+ 0123456789" + 1, *++fmt));
68                         if (*fmt == '.' && isdigit(*++fmt)) {
69                                 prec = atoi(fmt);
70                                 while (isdigit(*++fmt));
71                         }
72                         switch(*fmt) {
73                         case 'c':
74                                 bcnt += 1;
75                                 break;
76                         case 'd': case 'i': case 'o': case 'u':
77                         case 'x': case 'X':
78                                 bcnt += 4;
79                                 break;
80                         case 'e': case 'E': case 'f': case 'g': case 'G':
81                                 bcnt += 8;
82                                 break;
83                         case 's':
84                                 bcnt += prec;
85                                 break;
86                         case '_':
87                                 switch(*++fmt) {
88                                 case 'c': case 'p': case 'u':
89                                         bcnt += 1;
90                                         break;
91                                 }
92                         }
93                 }
94                 cursize += bcnt * fu->reps;
95         }
96         return(cursize);
97 }
98
99 void rewrite(FS *fs)
100 {
101         enum { NOTOKAY, USEBCNT, USEPREC } sokay;
102         register PR *pr, **nextpr = NULL;
103         register FU *fu;
104         register char *p1, *p2;
105         char savech, *fmtp;
106         int nconv, prec = 0;
107
108         for (fu = fs->nextfu; fu; fu = fu->nextfu) {
109                 /*
110                  * break each format unit into print units; each
111                  * conversion character gets its own.
112                  */
113                 for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
114                         /* NOSTRICT */
115                         pr = (PR *)xmalloc(sizeof(PR));
116                         if (!fu->nextpr)
117                                 fu->nextpr = pr;
118                         else
119                                 *nextpr = pr;
120
121                         /* skip preceding text and up to the next % sign */
122                         for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
123
124                         /* only text in the string */
125                         if (!*p1) {
126                                 pr->fmt = fmtp;
127                                 pr->flags = F_TEXT;
128                                 break;
129                         }
130
131                         /*
132                          * get precision for %s -- if have a byte count, don't
133                          * need it.
134                          */
135                         if (fu->bcnt) {
136                                 sokay = USEBCNT;
137                                 /* skip to conversion character */
138                                 for (++p1; index(".#-+ 0123456789", *p1); ++p1);
139                         } else {
140                                 /* skip any special chars, field width */
141                                 while (index(".#-+ 0123456789" + 1, *++p1));
142                                 if (*p1 == '.' && isdigit(*++p1)) {
143                                         sokay = USEPREC;
144                                         prec = atoi(p1);
145                                         while (isdigit(*++p1));
146                                 }
147                                 else
148                                         sokay = NOTOKAY;
149                         }
150
151                         p2 = p1 + 1;            /* set end pointer */
152
153                         /*
154                          * figure out the byte count for each conversion;
155                          * rewrite the format as necessary, set up blank-
156                          * padding for end of data.
157                          */
158                         switch(*p1) {
159                         case 'c':
160                                 pr->flags = F_CHAR;
161                                 switch(fu->bcnt) {
162                                 case 0: case 1:
163                                         pr->bcnt = 1;
164                                         break;
165                                 default:
166                                         p1[1] = '\0';
167                                         error_msg_and_die("bad byte count for conversion character %s.", p1);
168                                 }
169                                 break;
170                         case 'd': case 'i':
171                                 pr->flags = F_INT;
172                                 goto sw1;
173                         case 'l':
174                                 ++p2;
175                                 switch(p1[1]) {
176                                 case 'd': case 'i':
177                                         ++p1;
178                                         pr->flags = F_INT;
179                                         goto sw1;
180                                 case 'o': case 'u': case 'x': case 'X':
181                                         ++p1;
182                                         pr->flags = F_UINT;
183                                         goto sw1;
184                                 default:
185                                         p1[2] = '\0';
186                                         error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1);
187                                 }
188                                 /* NOTREACHED */
189                         case 'o': case 'u': case 'x': case 'X':
190                                 pr->flags = F_UINT;
191 sw1:                            switch(fu->bcnt) {
192                                 case 0: case 4:
193                                         pr->bcnt = 4;
194                                         break;
195                                 case 1:
196                                         pr->bcnt = 1;
197                                         break;
198                                 case 2:
199                                         pr->bcnt = 2;
200                                         break;
201                                 default:
202                                         p1[1] = '\0';
203                                         error_msg_and_die("bad byte count for conversion character %s.", p1);
204                                 }
205                                 break;
206                         case 'e': case 'E': case 'f': case 'g': case 'G':
207                                 pr->flags = F_DBL;
208                                 switch(fu->bcnt) {
209                                 case 0: case 8:
210                                         pr->bcnt = 8;
211                                         break;
212                                 case 4:
213                                         pr->bcnt = 4;
214                                         break;
215                                 default:
216                                         p1[1] = '\0';
217                                         error_msg_and_die("bad byte count for conversion character %s.", p1);
218                                 }
219                                 break;
220                         case 's':
221                                 pr->flags = F_STR;
222                                 switch(sokay) {
223                                 case NOTOKAY:
224                                         error_msg_and_die("%%s requires a precision or a byte count.");
225                                 case USEBCNT:
226                                         pr->bcnt = fu->bcnt;
227                                         break;
228                                 case USEPREC:
229                                         pr->bcnt = prec;
230                                         break;
231                                 }
232                                 break;
233                         case '_':
234                                 ++p2;
235                                 switch(p1[1]) {
236                                 case 'A':
237                                         endfu = fu;
238                                         fu->flags |= F_IGNORE;
239                                         /* FALLTHROUGH */
240                                 case 'a':
241                                         pr->flags = F_ADDRESS;
242                                         ++p2;
243                                         switch(p1[2]) {
244                                         case 'd': case 'o': case'x':
245                                                 *p1 = p1[2];
246                                                 break;
247                                         default:
248                                                 p1[3] = '\0';
249                                                 error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1);
250                                         }
251                                         break;
252                                 case 'c':
253                                         pr->flags = F_C;
254                                         /* *p1 = 'c';   set in conv_c */
255                                         goto sw2;
256                                 case 'p':
257                                         pr->flags = F_P;
258                                         *p1 = 'c';
259                                         goto sw2;
260                                 case 'u':
261                                         pr->flags = F_U;
262                                         /* *p1 = 'c';   set in conv_u */
263 sw2:                                    switch(fu->bcnt) {
264                                         case 0: case 1:
265                                                 pr->bcnt = 1;
266                                                 break;
267                                         default:
268                                                 p1[2] = '\0';
269                                                 error_msg_and_die("bad byte count for conversion character %s.", p1);
270                                         }
271                                         break;
272                                 default:
273                                         p1[2] = '\0';
274                                         error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1);
275                                 }
276                                 break;
277                         default:
278                                 p1[1] = '\0';
279                                 error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1);
280                         }
281
282                         /*
283                          * copy to PR format string, set conversion character
284                          * pointer, update original.
285                          */
286                         savech = *p2;
287                         p1[1] = '\0';
288                         if (!(pr->fmt = strdup(fmtp)))
289                                 perror_msg_and_die("hexdump");
290                         *p2 = savech;
291                         pr->cchar = pr->fmt + (p1 - fmtp);
292                         fmtp = p2;
293
294                         /* only one conversion character if byte count */
295                         if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) {
296                                 error_msg_and_die("hexdump: byte count with multiple conversion characters.\n");
297                         }
298                 }
299                 /*
300                  * if format unit byte count not specified, figure it out
301                  * so can adjust rep count later.
302                  */
303                 if (!fu->bcnt)
304                         for (pr = fu->nextpr; pr; pr = pr->nextpr)
305                                 fu->bcnt += pr->bcnt;
306         }
307         /*
308          * if the format string interprets any data at all, and it's
309          * not the same as the blocksize, and its last format unit
310          * interprets any data at all, and has no iteration count,
311          * repeat it as necessary.
312          *
313          * if, rep count is greater than 1, no trailing whitespace
314          * gets output from the last iteration of the format unit.
315          */
316         for (fu = fs->nextfu;; fu = fu->nextfu) {
317                 if (!fu->nextfu && fs->bcnt < blocksize &&
318                     !(fu->flags&F_SETREP) && fu->bcnt)
319                         fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
320                 if (fu->reps > 1) {
321                         for (pr = fu->nextpr;; pr = pr->nextpr)
322                                 if (!pr->nextpr)
323                                         break;
324                         for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
325                                 p2 = isspace(*p1) ? p1 : NULL;
326                         if (p2)
327                                 pr->nospace = p2;
328                 }
329                 if (!fu->nextfu)
330                         break;
331         }
332 }
333
334 static void doskip(char *fname, int statok)
335 {
336         struct stat sbuf;
337
338         if (statok) {
339                 if (fstat(fileno(stdin), &sbuf)) {
340                         perror_msg_and_die("hexdump: %s", fname);
341                 }
342                 if ( ( ! (S_ISCHR(sbuf.st_mode) ||
343                           S_ISBLK(sbuf.st_mode) ||
344                           S_ISFIFO(sbuf.st_mode)) ) &&
345                      skip >= sbuf.st_size) {
346                   /* If size valid and skip >= size */
347                         skip -= sbuf.st_size;
348                         address += sbuf.st_size;
349                         return;
350                 }
351         }
352         if (fseek(stdin, skip, SEEK_SET)) {
353                 perror_msg_and_die("hexdump: %s", fname);
354         }
355         savaddress = address += skip;
356         skip = 0;
357 }
358
359 int next(char **argv)
360 {
361         static int done;
362         int statok;
363
364         if (argv) {
365                 _argv = argv;
366                 return(1);
367         }
368         for (;;) {
369                 if (*_argv) {
370                         if (!(freopen(*_argv, "r", stdin))) {
371                                 perror_msg("%s", *_argv);
372                                 exitval = 1;
373                                 ++_argv;
374                                 continue;
375                         }
376                         statok = done = 1;
377                 } else {
378                         if (done++)
379                                 return(0);
380                         statok = 0;
381                 }
382                 if (skip)
383                         doskip(statok ? *_argv : "stdin", statok);
384                 if (*_argv)
385                         ++_argv;
386                 if (!skip)
387                         return(1);
388         }
389         /* NOTREACHED */
390 }
391
392 static u_char *
393 get(void)
394 {
395         static int ateof = 1;
396         static u_char *curp, *savp;
397         register int n;
398         int need, nread;
399         u_char *tmpp;
400
401         if (!curp) {
402                 curp = (u_char *)xmalloc(blocksize);
403                 savp = (u_char *)xmalloc(blocksize);
404         } else {
405                 tmpp = curp;
406                 curp = savp;
407                 savp = tmpp;
408                 address = savaddress += blocksize;
409         }
410         for (need = blocksize, nread = 0;;) {
411                 /*
412                  * if read the right number of bytes, or at EOF for one file,
413                  * and no other files are available, zero-pad the rest of the
414                  * block and set the end flag.
415                  */
416                 if (!length || (ateof && !next((char **)NULL))) {
417                         if (need == blocksize) {
418                                 return((u_char *)NULL);
419                         }
420                         if (vflag != ALL && !bcmp(curp, savp, nread)) {
421                                 if (vflag != DUP) {
422                                         printf("*\n");
423                                 }
424                                 return((u_char *)NULL);
425                         }
426                         bzero((char *)curp + nread, need);
427                         eaddress = address + nread;
428                         return(curp);
429                 }
430                 n = fread((char *)curp + nread, sizeof(u_char),
431                     length == -1 ? need : MIN(length, need), stdin);
432                 if (!n) {
433                         if (ferror(stdin)) {
434                                 perror_msg("%s", _argv[-1]);
435                         }
436                         ateof = 1;
437                         continue;
438                 }
439                 ateof = 0;
440                 if (length != -1) {
441                         length -= n;
442                 }
443                 if (!(need -= n)) {
444                         if (vflag == ALL || vflag == FIRST ||
445                             bcmp(curp, savp, blocksize)) {
446                                 if (vflag == DUP || vflag == FIRST) {
447                                         vflag = WAIT;
448                                 }
449                                 return(curp);
450                         }
451                         if (vflag == WAIT) {
452                                 printf("*\n");
453                         }
454                         vflag = DUP;
455                         address = savaddress += blocksize;
456                         need = blocksize;
457                         nread = 0;
458                 } else {
459                         nread += n;
460                 }
461         }
462 }
463
464 static void bpad(PR *pr)
465 {
466         register char *p1, *p2;
467
468         /*
469          * remove all conversion flags; '-' is the only one valid
470          * with %s, and it's not useful here.
471          */
472         pr->flags = F_BPAD;
473         *pr->cchar = 's';
474         for (p1 = pr->fmt; *p1 != '%'; ++p1);
475         for (p2 = ++p1; *p1 && index(" -0+#", *p1); ++p1);
476         while ((*p2++ = *p1++) != 0) ;
477 }
478
479 void conv_c(PR *pr, u_char *p)
480 {
481         char buf[10], *str;
482
483         switch(*p) {
484         case '\0':
485                 str = "\\0";
486                 goto strpr;
487         /* case '\a': */
488         case '\007':
489                 str = "\\a";
490                 goto strpr;
491         case '\b':
492                 str = "\\b";
493                 goto strpr;
494         case '\f':
495                 str = "\\f";
496                 goto strpr;
497         case '\n':
498                 str = "\\n";
499                 goto strpr;
500         case '\r':
501                 str = "\\r";
502                 goto strpr;
503         case '\t':
504                 str = "\\t";
505                 goto strpr;
506         case '\v':
507                 str = "\\v";
508                 goto strpr;
509         default:
510                 break;
511         }
512         if (isprint(*p)) {
513                 *pr->cchar = 'c';
514                 (void)printf(pr->fmt, *p);
515         } else {
516                 sprintf(str = buf, "%03o", (int)*p);
517 strpr:
518                 *pr->cchar = 's';
519                 printf(pr->fmt, str);
520         }
521 }
522
523 void conv_u(PR *pr, u_char *p)
524 {
525         static char *list[] = {
526                 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
527                  "bs",  "ht",  "lf",  "vt",  "ff",  "cr",  "so",  "si",
528                 "dle", "dcl", "dc2", "dc3", "dc4", "nak", "syn", "etb",
529                 "can",  "em", "sub", "esc",  "fs",  "gs",  "rs",  "us",
530         };
531
532         /* od used nl, not lf */
533         if (*p <= 0x1f) {
534                 *pr->cchar = 's';
535                 printf(pr->fmt, list[*p]);
536         } else if (*p == 0x7f) {
537                 *pr->cchar = 's';
538                 printf(pr->fmt, "del");
539         } else if (isprint(*p)) {
540                 *pr->cchar = 'c';
541                 printf(pr->fmt, *p);
542         } else {
543                 *pr->cchar = 'x';
544                 printf(pr->fmt, (int)*p);
545         }
546 }
547
548 void display(void)
549 {
550 //      extern FU *endfu;
551         register FS *fs;
552         register FU *fu;
553         register PR *pr;
554         register int cnt;
555         register u_char *bp;
556 //      off_t saveaddress;
557         u_char savech = 0, *savebp;
558
559         while ((bp = get()) != NULL) {
560             for (fs = fshead, savebp = bp, saveaddress = address; fs;
561                                 fs = fs->nextfs, bp = savebp, address = saveaddress) {
562                     for (fu = fs->nextfu; fu; fu = fu->nextfu) {
563                                 if (fu->flags & F_IGNORE) {
564                                         break;
565                                 }
566                                 for (cnt = fu->reps; cnt; --cnt) {
567                                     for (pr = fu->nextpr; pr; address += pr->bcnt,
568                                                         bp += pr->bcnt, pr = pr->nextpr) {
569                                             if (eaddress && address >= eaddress &&
570                                                                 !(pr->flags&(F_TEXT|F_BPAD))) {
571                                                         bpad(pr);
572                                                 }
573                                             if (cnt == 1 && pr->nospace) {
574                                                         savech = *pr->nospace;
575                                                         *pr->nospace = '\0';
576                                             }
577 //                                          PRINT;
578                                                 switch(pr->flags) {
579                                                         case F_ADDRESS:
580                                                                 printf(pr->fmt, address);
581                                                                 break;
582                                                         case F_BPAD:
583                                                                 printf(pr->fmt, "");
584                                                                 break;
585                                                         case F_C:
586                                                                 conv_c(pr, bp);
587                                                                 break;
588                                                         case F_CHAR:
589                                                                 printf(pr->fmt, *bp);
590                                                                 break;
591                                                         case F_DBL: {
592                                                                 double dval;
593                                                                 float fval;
594                                                                 switch(pr->bcnt) {
595                                                                         case 4:
596                                                                                 bcopy((char *)bp, (char *)&fval, sizeof(fval));
597                                                                                 printf(pr->fmt, fval);
598                                                                                 break;
599                                                                         case 8:
600                                                                                 bcopy((char *)bp, (char *)&dval, sizeof(dval));
601                                                                                 printf(pr->fmt, dval);
602                                                                                 break;
603                                                                 }
604                                                                 break;
605                                                         }
606                                                         case F_INT: {
607                                                                 int ival;
608                                                                 short sval;
609                                                                 switch(pr->bcnt) {
610                                                                         case 1:
611                                                                                 printf(pr->fmt, (int)*bp);
612                                                                                 break;
613                                                                         case 2:
614                                                                                 bcopy((char *)bp, (char *)&sval, sizeof(sval));
615                                                                                 printf(pr->fmt, (int)sval);
616                                                                                 break;
617                                                                         case 4:
618                                                                                 bcopy((char *)bp, (char *)&ival, sizeof(ival));
619                                                                                 printf(pr->fmt, ival);
620                                                                                 break;
621                                                                 }
622                                                                 break;
623                                                         }
624                                                         case F_P:
625                                                                 printf(pr->fmt, isprint(*bp) ? *bp : '.');
626                                                                 break;
627                                                         case F_STR:
628                                                                 printf(pr->fmt, (char *)bp);
629                                                                 break;
630                                                         case F_TEXT:
631                                                                 printf(pr->fmt);
632                                                                 break;
633                                                         case F_U:
634                                                                 conv_u(pr, bp);
635                                                                 break;
636                                                         case F_UINT: {
637                                                                 u_int ival;
638                                                                 u_short sval;
639                                                                 switch(pr->bcnt) {
640                                                                         case 1:
641                                                                                 printf(pr->fmt, (u_int)*bp);
642                                                                                 break;
643                                                                         case 2:
644                                                                                 bcopy((char *)bp, (char *)&sval, sizeof(sval));
645                                                                                 printf(pr->fmt, (u_int)sval);
646                                                                                 break;
647                                                                         case 4:
648                                                                                 bcopy((char *)bp, (char *)&ival, sizeof(ival));
649                                                                                 printf(pr->fmt, ival);
650                                                                                 break;
651                                                                 }
652                                                                 break;
653                                                         }
654                                                 }
655                                            if (cnt == 1 && pr->nospace) {
656                                                         *pr->nospace = savech;
657                                                 }
658                                         }
659                                 }
660                         }
661                 }
662         }
663         if (endfu) {
664                 /*
665                  * if eaddress not set, error or file size was multiple of
666                  * blocksize, and no partial block ever found.
667                  */
668                 if (!eaddress) {
669                         if (!address) {
670                                 return;
671                         }
672                         eaddress = address;
673                 }
674                 for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
675                         switch(pr->flags) {
676                         case F_ADDRESS:
677                                 (void)printf(pr->fmt, eaddress);
678                                 break;
679                         case F_TEXT:
680                                 (void)printf(pr->fmt);
681                                 break;
682                         }
683                 }
684         }
685 }
686
687 int dump(char **argv)
688 {
689         register FS *tfs;
690
691         /* figure out the data block size */
692         for (blocksize = 0, tfs = fshead; tfs; tfs = tfs->nextfs) {
693                 tfs->bcnt = size(tfs);
694                 if (blocksize < tfs->bcnt) {
695                         blocksize = tfs->bcnt;
696                 }
697         }
698         /* rewrite the rules, do syntax checking */
699         for (tfs = fshead; tfs; tfs = tfs->nextfs) {
700                 rewrite(tfs);
701         }
702
703         next(argv);
704         display();
705
706         return(exitval);
707 }
708
709 void add(char *fmt)
710 {
711         register char *p;
712         register char *p1;
713         register char *p2;
714         static FS **nextfs;
715         FS *tfs;
716         FU *tfu, **nextfu;
717         char *savep;
718
719         /* start new linked list of format units */
720         /* NOSTRICT */
721         tfs = (FS *)xmalloc(sizeof(FS));
722         if (!fshead) {
723                 fshead = tfs;
724         } else {
725                 *nextfs = tfs;
726         }
727         nextfs = &tfs->nextfs;
728         nextfu = &tfs->nextfu;
729
730         /* take the format string and break it up into format units */
731         for (p = fmt;;) {
732                 /* skip leading white space */
733                 for (; isspace(*p); ++p);
734                 if (!*p) {
735                         break;
736                 }
737
738                 /* allocate a new format unit and link it in */
739                 /* NOSTRICT */
740                 tfu = (FU *)xmalloc(sizeof(FU));
741                 *nextfu = tfu;
742                 nextfu = &tfu->nextfu;
743                 tfu->reps = 1;
744
745                 /* if leading digit, repetition count */
746                 if (isdigit(*p)) {
747                         for (savep = p; isdigit(*p); ++p);
748                         if (!isspace(*p) && *p != '/') {
749                                 error_msg_and_die("hexdump: bad format {%s}", fmt);
750                         }
751                         /* may overwrite either white space or slash */
752                         tfu->reps = atoi(savep);
753                         tfu->flags = F_SETREP;
754                         /* skip trailing white space */
755                         for (++p; isspace(*p); ++p);
756                 }
757
758                 /* skip slash and trailing white space */
759                 if (*p == '/') {
760                         while (isspace(*++p));
761                 }
762
763                 /* byte count */
764                 if (isdigit(*p)) {
765                         for (savep = p; isdigit(*p); ++p);
766                         if (!isspace(*p)) {
767                                 error_msg_and_die("hexdump: bad format {%s}", fmt);
768                         }
769                         tfu->bcnt = atoi(savep);
770                         /* skip trailing white space */
771                         for (++p; isspace(*p); ++p);
772                 }
773
774                 /* format */
775                 if (*p != '"') {
776                         error_msg_and_die("hexdump: bad format {%s}", fmt);
777                 }
778                 for (savep = ++p; *p != '"';) {
779                         if (*p++ == 0) {
780                                 error_msg_and_die("hexdump: bad format {%s}", fmt);
781                         }
782                 }
783                 if (!(tfu->fmt = malloc(p - savep + 1))) {
784                         perror_msg_and_die("hexdump");
785                 }
786                 strncpy(tfu->fmt, savep, p - savep);
787                 tfu->fmt[p - savep] = '\0';
788 //              escape(tfu->fmt);
789
790                 p1 = tfu->fmt;
791
792                 /* alphabetic escape sequences have to be done in place */
793                 for (p2 = p1;; ++p1, ++p2) {
794                         if (!*p1) {
795                                 *p2 = *p1;
796                                 break;
797                         }
798                         if (*p1 == '\\') {
799                                 switch(*++p1) {
800                                 case 'a':
801                                      /* *p2 = '\a'; */
802                                         *p2 = '\007';
803                                         break;
804                                 case 'b':
805                                         *p2 = '\b';
806                                         break;
807                                 case 'f':
808                                         *p2 = '\f';
809                                         break;
810                                 case 'n':
811                                         *p2 = '\n';
812                                         break;
813                                 case 'r':
814                                         *p2 = '\r';
815                                         break;
816                                 case 't':
817                                         *p2 = '\t';
818                                         break;
819                                 case 'v':
820                                         *p2 = '\v';
821                                         break;
822                                 default:
823                                         *p2 = *p1;
824                                         break;
825                                 }
826                         }
827                 }
828
829                 p++;
830         }
831 }
832 /*
833  * Copyright (c) 1989 The Regents of the University of California.
834  * All rights reserved.
835  *
836  * Redistribution and use in source and binary forms, with or without
837  * modification, are permitted provided that the following conditions
838  * are met:
839  * 1. Redistributions of source code must retain the above copyright
840  *    notice, this list of conditions and the following disclaimer.
841  * 2. Redistributions in binary form must reproduce the above copyright
842  *    notice, this list of conditions and the following disclaimer in the
843  *    documentation and/or other materials provided with the distribution.
844  * 3. All advertising materials mentioning features or use of this software
845  *    must display the following acknowledgement:
846  *      This product includes software developed by the University of
847  *      California, Berkeley and its contributors.
848  * 4. Neither the name of the University nor the names of its contributors
849  *    may be used to endorse or promote products derived from this software
850  *    without specific prior written permission.
851  *
852  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
853  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
854  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
855  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
856  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
857  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
858  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
859  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
860  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
861  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
862  * SUCH DAMAGE.
863  */