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