source: MondoRescue/branches/3.3/mindi-busybox/libbb/dump.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

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