diff options
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/dump.c | 102 |
1 files changed, 68 insertions, 34 deletions
diff --git a/libbb/dump.c b/libbb/dump.c index d24057325..ffc46f6a7 100644 --- a/libbb/dump.c +++ b/libbb/dump.c | |||
@@ -50,8 +50,10 @@ typedef struct priv_dumper_t { | |||
50 | static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; | 50 | static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; |
51 | 51 | ||
52 | static const char size_conv_str[] ALIGN1 = | 52 | static const char size_conv_str[] ALIGN1 = |
53 | "\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG"; | 53 | "\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\x8""cdiouxXeEfgG"; |
54 | 54 | /* c d i o u x X e E f g G - bytes contain 'bcnt' for the type */ | |
55 | #define SCS_OFS 12 | ||
56 | #define float_convs (size_conv_str + SCS_OFS + sizeof("cdiouxX")-1) | ||
55 | static const char int_convs[] ALIGN1 = "diouxX"; | 57 | static const char int_convs[] ALIGN1 = "diouxX"; |
56 | 58 | ||
57 | dumper_t* FAST_FUNC alloc_dumper(void) | 59 | dumper_t* FAST_FUNC alloc_dumper(void) |
@@ -94,7 +96,7 @@ static NOINLINE int bb_dump_size(FS *fs) | |||
94 | while (isdigit(*++fmt)) | 96 | while (isdigit(*++fmt)) |
95 | continue; | 97 | continue; |
96 | } | 98 | } |
97 | p = strchr(size_conv_str + 12, *fmt); | 99 | p = strchr(size_conv_str + SCS_OFS, *fmt); |
98 | if (!p) { | 100 | if (!p) { |
99 | if (*fmt == 's') { | 101 | if (*fmt == 's') { |
100 | bcnt += prec; | 102 | bcnt += prec; |
@@ -106,7 +108,7 @@ static NOINLINE int bb_dump_size(FS *fs) | |||
106 | } | 108 | } |
107 | } | 109 | } |
108 | } else { | 110 | } else { |
109 | bcnt += p[-12]; | 111 | bcnt += p[-SCS_OFS]; |
110 | } | 112 | } |
111 | } | 113 | } |
112 | cur_size += bcnt * fu->reps; | 114 | cur_size += bcnt * fu->reps; |
@@ -193,6 +195,10 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
193 | 195 | ||
194 | ++p2; | 196 | ++p2; |
195 | ++p1; | 197 | ++p1; |
198 | if (*p1 == 'l') { /* %lld etc */ | ||
199 | ++p2; | ||
200 | ++p1; | ||
201 | } | ||
196 | DO_INT_CONV: | 202 | DO_INT_CONV: |
197 | e = strchr(int_convs, *p1); /* "diouxX"? */ | 203 | e = strchr(int_convs, *p1); /* "diouxX"? */ |
198 | if (!e) | 204 | if (!e) |
@@ -200,13 +206,13 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
200 | pr->flags = F_INT; | 206 | pr->flags = F_INT; |
201 | if (e > int_convs + 1) /* not d or i? */ | 207 | if (e > int_convs + 1) /* not d or i? */ |
202 | pr->flags = F_UINT; | 208 | pr->flags = F_UINT; |
203 | byte_count_str = "\004\002\001"; | 209 | byte_count_str = "\010\004\002\001"; |
204 | goto DO_BYTE_COUNT; | 210 | goto DO_BYTE_COUNT; |
205 | } else | 211 | } else |
206 | if (strchr(int_convs, *p1)) { /* %d etc */ | 212 | if (strchr(int_convs, *p1)) { /* %d etc */ |
207 | goto DO_INT_CONV; | 213 | goto DO_INT_CONV; |
208 | } else | 214 | } else |
209 | if (strchr("eEfgG", *p1)) { /* floating point */ | 215 | if (strchr(float_convs, *p1)) { /* floating point */ |
210 | pr->flags = F_DBL; | 216 | pr->flags = F_DBL; |
211 | byte_count_str = "\010\004"; | 217 | byte_count_str = "\010\004"; |
212 | goto DO_BYTE_COUNT; | 218 | goto DO_BYTE_COUNT; |
@@ -244,7 +250,7 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
244 | pr->flags = F_P; | 250 | pr->flags = F_P; |
245 | *p1 = 'c'; | 251 | *p1 = 'c'; |
246 | goto DO_BYTE_COUNT_1; | 252 | goto DO_BYTE_COUNT_1; |
247 | case 'u': /* %_p: chars, 'nul', 'esc' etc for nonprintable */ | 253 | case 'u': /* %_u: chars, 'nul', 'esc' etc for nonprintable */ |
248 | pr->flags = F_U; | 254 | pr->flags = F_U; |
249 | /* *p1 = 'c'; set in conv_u */ | 255 | /* *p1 = 'c'; set in conv_u */ |
250 | goto DO_BYTE_COUNT_1; | 256 | goto DO_BYTE_COUNT_1; |
@@ -324,8 +330,7 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
324 | p2 = NULL; | 330 | p2 = NULL; |
325 | for (p1 = pr->fmt; *p1; ++p1) | 331 | for (p1 = pr->fmt; *p1; ++p1) |
326 | p2 = isspace(*p1) ? p1 : NULL; | 332 | p2 = isspace(*p1) ? p1 : NULL; |
327 | if (p2) | 333 | pr->nospace = p2; |
328 | pr->nospace = p2; | ||
329 | } | 334 | } |
330 | } | 335 | } |
331 | } | 336 | } |
@@ -509,7 +514,7 @@ static void bpad(PR *pr) | |||
509 | 514 | ||
510 | static const char conv_str[] ALIGN1 = | 515 | static const char conv_str[] ALIGN1 = |
511 | "\0" "\\""0""\0" | 516 | "\0" "\\""0""\0" |
512 | "\007""\\""a""\0" /* \a */ | 517 | "\007""\\""a""\0" |
513 | "\b" "\\""b""\0" | 518 | "\b" "\\""b""\0" |
514 | "\f" "\\""f""\0" | 519 | "\f" "\\""f""\0" |
515 | "\n" "\\""n""\0" | 520 | "\n" "\\""n""\0" |
@@ -549,10 +554,12 @@ static void conv_u(PR *pr, unsigned char *p) | |||
549 | static const char list[] ALIGN1 = | 554 | static const char list[] ALIGN1 = |
550 | "nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0" | 555 | "nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0" |
551 | "bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_" | 556 | "bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_" |
552 | "dle\0dcl\0dc2\0dc3\0dc4\0nak\0syn\0etb\0" | 557 | "dle\0dc1\0dc2\0dc3\0dc4\0nak\0syn\0etb\0" |
553 | "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us"; | 558 | "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us"; |
559 | /* NB: bug: od uses %_u to implement -a, | ||
560 | * but it should use "nl", not "lf", for char #10. | ||
561 | */ | ||
554 | 562 | ||
555 | /* od used nl, not lf */ | ||
556 | if (*p <= 0x1f) { | 563 | if (*p <= 0x1f) { |
557 | *pr->cchar = 's'; | 564 | *pr->cchar = 's'; |
558 | printf(pr->fmt, list + (4 * (int)*p)); | 565 | printf(pr->fmt, list + (4 * (int)*p)); |
@@ -571,7 +578,6 @@ static void conv_u(PR *pr, unsigned char *p) | |||
571 | static NOINLINE void display(priv_dumper_t* dumper) | 578 | static NOINLINE void display(priv_dumper_t* dumper) |
572 | { | 579 | { |
573 | unsigned char *bp; | 580 | unsigned char *bp; |
574 | unsigned char savech = '\0'; | ||
575 | 581 | ||
576 | while ((bp = get(dumper)) != NULL) { | 582 | while ((bp = get(dumper)) != NULL) { |
577 | FS *fs; | 583 | FS *fs; |
@@ -592,24 +598,41 @@ static NOINLINE void display(priv_dumper_t* dumper) | |||
592 | PR *pr; | 598 | PR *pr; |
593 | for (pr = fu->nextpr; pr; dumper->pub.address += pr->bcnt, | 599 | for (pr = fu->nextpr; pr; dumper->pub.address += pr->bcnt, |
594 | bp += pr->bcnt, pr = pr->nextpr) { | 600 | bp += pr->bcnt, pr = pr->nextpr) { |
601 | unsigned char savech; | ||
602 | |||
595 | if (dumper->eaddress | 603 | if (dumper->eaddress |
596 | && dumper->pub.address >= dumper->eaddress | 604 | && dumper->pub.address >= dumper->eaddress |
597 | ) { | 605 | ) { |
606 | #if ENABLE_XXD | ||
598 | if (dumper->pub.xxd_eofstring) { | 607 | if (dumper->pub.xxd_eofstring) { |
599 | /* xxd support: requested to not pad incomplete blocks */ | 608 | /* xxd support: requested to not pad incomplete blocks */ |
600 | fputs_stdout(dumper->pub.xxd_eofstring); | 609 | fputs_stdout(dumper->pub.xxd_eofstring); |
601 | return; | 610 | return; |
602 | } | 611 | } |
612 | #endif | ||
613 | #if ENABLE_OD | ||
614 | if (dumper->pub.od_eofstring) { | ||
615 | /* od support: requested to not pad incomplete blocks */ | ||
616 | /* ... but do print final offset */ | ||
617 | fputs_stdout(dumper->pub.od_eofstring); | ||
618 | goto endfu; | ||
619 | } | ||
620 | #endif | ||
603 | if (!(pr->flags & (F_TEXT | F_BPAD))) | 621 | if (!(pr->flags & (F_TEXT | F_BPAD))) |
604 | bpad(pr); | 622 | bpad(pr); |
605 | } | 623 | } |
624 | savech = '\0'; | ||
606 | if (cnt == 1 && pr->nospace) { | 625 | if (cnt == 1 && pr->nospace) { |
607 | savech = *pr->nospace; | 626 | savech = *pr->nospace; |
608 | *pr->nospace = '\0'; | 627 | *pr->nospace = '\0'; |
609 | } | 628 | } |
610 | switch (pr->flags) { | 629 | switch (pr->flags) { |
611 | case F_ADDRESS: | 630 | case F_ADDRESS: |
612 | printf(pr->fmt, (unsigned long long) dumper->pub.address + dumper->pub.xxd_displayoff); | 631 | printf(pr->fmt, (unsigned long long) dumper->pub.address |
632 | #if ENABLE_XXD | ||
633 | + dumper->pub.xxd_displayoff | ||
634 | #endif | ||
635 | ); | ||
613 | break; | 636 | break; |
614 | case F_BPAD: | 637 | case F_BPAD: |
615 | printf(pr->fmt, ""); | 638 | printf(pr->fmt, ""); |
@@ -637,22 +660,32 @@ static NOINLINE void display(priv_dumper_t* dumper) | |||
637 | break; | 660 | break; |
638 | } | 661 | } |
639 | case F_INT: { | 662 | case F_INT: { |
640 | int ival; | 663 | union { |
641 | short sval; | 664 | int16_t ival16; |
665 | int32_t ival32; | ||
666 | int64_t ival64; | ||
667 | } u; | ||
668 | int value = (signed char)*bp; | ||
642 | 669 | ||
643 | switch (pr->bcnt) { | 670 | switch (pr->bcnt) { |
644 | case 1: | 671 | case 1: |
645 | printf(pr->fmt, (int) *bp); | ||
646 | break; | 672 | break; |
647 | case 2: | 673 | case 2: |
648 | memcpy(&sval, bp, sizeof(sval)); | 674 | move_from_unaligned16(u.ival16, bp); |
649 | printf(pr->fmt, (int) sval); | 675 | value = u.ival16; |
650 | break; | 676 | break; |
651 | case 4: | 677 | case 4: |
652 | memcpy(&ival, bp, sizeof(ival)); | 678 | move_from_unaligned32(u.ival32, bp); |
653 | printf(pr->fmt, ival); | 679 | value = u.ival32; |
654 | break; | 680 | break; |
681 | case 8: | ||
682 | move_from_unaligned64(u.ival64, bp); | ||
683 | //A hack. Users _must_ use %llX formats to not truncate high bits | ||
684 | printf(pr->fmt, (long long)u.ival64); | ||
685 | goto skip; | ||
655 | } | 686 | } |
687 | printf(pr->fmt, value); | ||
688 | skip: | ||
656 | break; | 689 | break; |
657 | } | 690 | } |
658 | case F_P: | 691 | case F_P: |
@@ -662,32 +695,29 @@ static NOINLINE void display(priv_dumper_t* dumper) | |||
662 | printf(pr->fmt, (char *) bp); | 695 | printf(pr->fmt, (char *) bp); |
663 | break; | 696 | break; |
664 | case F_TEXT: | 697 | case F_TEXT: |
665 | printf(pr->fmt); | 698 | fputs_stdout(pr->fmt); |
666 | break; | 699 | break; |
667 | case F_U: | 700 | case F_U: |
668 | conv_u(pr, bp); | 701 | conv_u(pr, bp); |
669 | break; | 702 | break; |
670 | case F_UINT: { | 703 | case F_UINT: { |
671 | unsigned ival; | 704 | unsigned value = (unsigned char)*bp; |
672 | unsigned short sval; | ||
673 | |||
674 | switch (pr->bcnt) { | 705 | switch (pr->bcnt) { |
675 | case 1: | 706 | case 1: |
676 | printf(pr->fmt, (unsigned) *bp); | ||
677 | break; | 707 | break; |
678 | case 2: | 708 | case 2: |
679 | memcpy(&sval, bp, sizeof(sval)); | 709 | move_from_unaligned16(value, bp); |
680 | printf(pr->fmt, (unsigned) sval); | ||
681 | break; | 710 | break; |
682 | case 4: | 711 | case 4: |
683 | memcpy(&ival, bp, sizeof(ival)); | 712 | move_from_unaligned32(value, bp); |
684 | printf(pr->fmt, ival); | ||
685 | break; | 713 | break; |
714 | /* case 8: no users yet */ | ||
686 | } | 715 | } |
716 | printf(pr->fmt, value); | ||
687 | break; | 717 | break; |
688 | } | 718 | } |
689 | } | 719 | } |
690 | if (cnt == 1 && pr->nospace) { | 720 | if (savech) { |
691 | *pr->nospace = savech; | 721 | *pr->nospace = savech; |
692 | } | 722 | } |
693 | } | 723 | } |
@@ -695,7 +725,7 @@ static NOINLINE void display(priv_dumper_t* dumper) | |||
695 | } | 725 | } |
696 | } | 726 | } |
697 | } | 727 | } |
698 | 728 | IF_OD(endfu:) | |
699 | if (dumper->endfu) { | 729 | if (dumper->endfu) { |
700 | PR *pr; | 730 | PR *pr; |
701 | /* | 731 | /* |
@@ -711,10 +741,14 @@ static NOINLINE void display(priv_dumper_t* dumper) | |||
711 | for (pr = dumper->endfu->nextpr; pr; pr = pr->nextpr) { | 741 | for (pr = dumper->endfu->nextpr; pr; pr = pr->nextpr) { |
712 | switch (pr->flags) { | 742 | switch (pr->flags) { |
713 | case F_ADDRESS: | 743 | case F_ADDRESS: |
714 | printf(pr->fmt, (unsigned long long) dumper->eaddress + dumper->pub.xxd_displayoff); | 744 | printf(pr->fmt, (unsigned long long) dumper->eaddress |
745 | #if ENABLE_XXD | ||
746 | + dumper->pub.xxd_displayoff | ||
747 | #endif | ||
748 | ); | ||
715 | break; | 749 | break; |
716 | case F_TEXT: | 750 | case F_TEXT: |
717 | printf(pr->fmt); | 751 | fputs_stdout(pr->fmt); |
718 | break; | 752 | break; |
719 | } | 753 | } |
720 | } | 754 | } |