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