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