diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2020-10-20 18:54:36 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2020-10-20 18:57:02 +0200 |
commit | dac5b8314236338963877903cba3d7edfbfc9c58 (patch) | |
tree | 5e7ce92407b9079b4e49e728f28f8a7c6311999c | |
parent | 085f19cdffd653013b1483c08851ecc35cdd818e (diff) | |
download | busybox-w32-dac5b8314236338963877903cba3d7edfbfc9c58.tar.gz busybox-w32-dac5b8314236338963877903cba3d7edfbfc9c58.tar.bz2 busybox-w32-dac5b8314236338963877903cba3d7edfbfc9c58.zip |
xxd: fix printing of trailing spaces
function old new delta
bb_dump_dump 1497 1523 +26
xxd_main 459 466 +7
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 33/0) Total: 33 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | include/dump.h | 39 | ||||
-rw-r--r-- | libbb/dump.c | 93 | ||||
-rwxr-xr-x | testsuite/xxd.tests | 34 | ||||
-rw-r--r-- | util-linux/hexdump_xxd.c | 1 |
4 files changed, 108 insertions, 59 deletions
diff --git a/include/dump.h b/include/dump.h index 4c237ef05..f4759c193 100644 --- a/include/dump.h +++ b/include/dump.h | |||
@@ -2,50 +2,15 @@ | |||
2 | 2 | ||
3 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | 3 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN |
4 | 4 | ||
5 | #define F_IGNORE 0x01 /* %_A */ | ||
6 | #define F_SETREP 0x02 /* rep count set, not default */ | ||
7 | #define F_ADDRESS 0x001 /* print offset */ | ||
8 | #define F_BPAD 0x002 /* blank pad */ | ||
9 | #define F_C 0x004 /* %_c */ | ||
10 | #define F_CHAR 0x008 /* %c */ | ||
11 | #define F_DBL 0x010 /* %[EefGf] */ | ||
12 | #define F_INT 0x020 /* %[di] */ | ||
13 | #define F_P 0x040 /* %_p */ | ||
14 | #define F_STR 0x080 /* %s */ | ||
15 | #define F_U 0x100 /* %_u */ | ||
16 | #define F_UINT 0x200 /* %[ouXx] */ | ||
17 | #define F_TEXT 0x400 /* no conversions */ | ||
18 | |||
19 | enum dump_vflag_t { ALL, DUP, FIRST, WAIT }; /* -v values */ | 5 | enum dump_vflag_t { ALL, DUP, FIRST, WAIT }; /* -v values */ |
20 | 6 | ||
21 | typedef struct PR { | 7 | typedef struct FS FS; |
22 | struct PR *nextpr; /* next print unit */ | ||
23 | unsigned flags; /* flag values */ | ||
24 | int bcnt; /* byte count */ | ||
25 | char *cchar; /* conversion character */ | ||
26 | char *fmt; /* printf format */ | ||
27 | char *nospace; /* no whitespace version */ | ||
28 | } PR; | ||
29 | |||
30 | typedef struct FU { | ||
31 | struct FU *nextfu; /* next format unit */ | ||
32 | struct PR *nextpr; /* next print unit */ | ||
33 | unsigned flags; /* flag values */ | ||
34 | int reps; /* repetition count */ | ||
35 | int bcnt; /* byte count */ | ||
36 | char *fmt; /* format string */ | ||
37 | } FU; | ||
38 | |||
39 | typedef struct FS { /* format strings */ | ||
40 | struct FS *nextfs; /* linked list of format strings */ | ||
41 | struct FU *nextfu; /* linked list of format units */ | ||
42 | int bcnt; | ||
43 | } FS; | ||
44 | 8 | ||
45 | typedef struct dumper_t { | 9 | typedef struct dumper_t { |
46 | off_t dump_skip; /* bytes to skip */ | 10 | off_t dump_skip; /* bytes to skip */ |
47 | int dump_length; /* max bytes to read */ | 11 | int dump_length; /* max bytes to read */ |
48 | smallint dump_vflag; /*enum dump_vflag_t*/ | 12 | smallint dump_vflag; /*enum dump_vflag_t*/ |
13 | const char *eofstring; | ||
49 | FS *fshead; | 14 | FS *fshead; |
50 | } dumper_t; | 15 | } dumper_t; |
51 | 16 | ||
diff --git a/libbb/dump.c b/libbb/dump.c index 8029cca0e..920f003ef 100644 --- a/libbb/dump.c +++ b/libbb/dump.c | |||
@@ -13,13 +13,43 @@ | |||
13 | #include "libbb.h" | 13 | #include "libbb.h" |
14 | #include "dump.h" | 14 | #include "dump.h" |
15 | 15 | ||
16 | static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; | 16 | #define F_IGNORE 0x01 /* %_A */ |
17 | 17 | #define F_SETREP 0x02 /* rep count set, not default */ | |
18 | static const char size_conv_str[] ALIGN1 = | 18 | #define F_ADDRESS 0x001 /* print offset */ |
19 | "\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG"; | 19 | #define F_BPAD 0x002 /* blank pad */ |
20 | 20 | #define F_C 0x004 /* %_c */ | |
21 | static const char int_convs[] ALIGN1 = "diouxX"; | 21 | #define F_CHAR 0x008 /* %c */ |
22 | 22 | #define F_DBL 0x010 /* %[EefGf] */ | |
23 | #define F_INT 0x020 /* %[di] */ | ||
24 | #define F_P 0x040 /* %_p */ | ||
25 | #define F_STR 0x080 /* %s */ | ||
26 | #define F_U 0x100 /* %_u */ | ||
27 | #define F_UINT 0x200 /* %[ouXx] */ | ||
28 | #define F_TEXT 0x400 /* no conversions */ | ||
29 | |||
30 | typedef struct PR { | ||
31 | struct PR *nextpr; /* next print unit */ | ||
32 | unsigned flags; /* flag values */ | ||
33 | int bcnt; /* byte count */ | ||
34 | char *cchar; /* conversion character */ | ||
35 | char *fmt; /* printf format */ | ||
36 | char *nospace; /* no whitespace version */ | ||
37 | } PR; | ||
38 | |||
39 | typedef struct FU { | ||
40 | struct FU *nextfu; /* next format unit */ | ||
41 | struct PR *nextpr; /* next print unit */ | ||
42 | unsigned flags; /* flag values */ | ||
43 | int reps; /* repetition count */ | ||
44 | int bcnt; /* byte count */ | ||
45 | char *fmt; /* format string */ | ||
46 | } FU; | ||
47 | |||
48 | typedef struct FS { /* format strings */ | ||
49 | struct FS *nextfs; /* linked list of format strings */ | ||
50 | struct FU *nextfu; /* linked list of format units */ | ||
51 | int bcnt; | ||
52 | } FS; | ||
23 | 53 | ||
24 | typedef struct priv_dumper_t { | 54 | typedef struct priv_dumper_t { |
25 | dumper_t pub; | 55 | dumper_t pub; |
@@ -39,6 +69,13 @@ typedef struct priv_dumper_t { | |||
39 | unsigned char *get__savp; | 69 | unsigned char *get__savp; |
40 | } priv_dumper_t; | 70 | } priv_dumper_t; |
41 | 71 | ||
72 | static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; | ||
73 | |||
74 | static const char size_conv_str[] ALIGN1 = | ||
75 | "\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG"; | ||
76 | |||
77 | static const char int_convs[] ALIGN1 = "diouxX"; | ||
78 | |||
42 | dumper_t* FAST_FUNC alloc_dumper(void) | 79 | dumper_t* FAST_FUNC alloc_dumper(void) |
43 | { | 80 | { |
44 | priv_dumper_t *dumper = xzalloc(sizeof(*dumper)); | 81 | priv_dumper_t *dumper = xzalloc(sizeof(*dumper)); |
@@ -48,7 +85,6 @@ dumper_t* FAST_FUNC alloc_dumper(void) | |||
48 | return &dumper->pub; | 85 | return &dumper->pub; |
49 | } | 86 | } |
50 | 87 | ||
51 | |||
52 | static NOINLINE int bb_dump_size(FS *fs) | 88 | static NOINLINE int bb_dump_size(FS *fs) |
53 | { | 89 | { |
54 | FU *fu; | 90 | FU *fu; |
@@ -284,7 +320,9 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
284 | * repeat it as necessary. | 320 | * repeat it as necessary. |
285 | * | 321 | * |
286 | * if rep count is greater than 1, no trailing whitespace | 322 | * if rep count is greater than 1, no trailing whitespace |
287 | * gets output from the last iteration of the format unit. | 323 | * gets output from the last iteration of the format unit: |
324 | * 2/1 "%02x " prints "XX XX", not "XX XX " | ||
325 | * 2/1 "%02x\n" prints "XX\nXX", not "XX\nXX\n" | ||
288 | */ | 326 | */ |
289 | for (fu = fs->nextfu; fu; fu = fu->nextfu) { | 327 | for (fu = fs->nextfu; fu; fu = fu->nextfu) { |
290 | if (!fu->nextfu | 328 | if (!fu->nextfu |
@@ -453,7 +491,7 @@ static void bpad(PR *pr) | |||
453 | for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1) | 491 | for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1) |
454 | if (pr->nospace) | 492 | if (pr->nospace) |
455 | pr->nospace--; | 493 | pr->nospace--; |
456 | while ((*p2++ = *p1++) != 0) | 494 | while ((*p2++ = *p1++) != '\0') |
457 | continue; | 495 | continue; |
458 | } | 496 | } |
459 | 497 | ||
@@ -520,36 +558,43 @@ static void conv_u(PR *pr, unsigned char *p) | |||
520 | 558 | ||
521 | static void display(priv_dumper_t* dumper) | 559 | static void display(priv_dumper_t* dumper) |
522 | { | 560 | { |
523 | FS *fs; | 561 | unsigned char *bp; |
524 | FU *fu; | ||
525 | PR *pr; | ||
526 | int cnt; | ||
527 | unsigned char *bp, *savebp; | ||
528 | off_t saveaddress; | ||
529 | unsigned char savech = '\0'; | 562 | unsigned char savech = '\0'; |
530 | 563 | ||
531 | while ((bp = get(dumper)) != NULL) { | 564 | while ((bp = get(dumper)) != NULL) { |
565 | FS *fs; | ||
566 | unsigned char *savebp; | ||
567 | off_t saveaddress; | ||
568 | |||
532 | fs = dumper->pub.fshead; | 569 | fs = dumper->pub.fshead; |
533 | savebp = bp; | 570 | savebp = bp; |
534 | saveaddress = dumper->address; | 571 | saveaddress = dumper->address; |
535 | for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) { | 572 | for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) { |
573 | FU *fu; | ||
536 | for (fu = fs->nextfu; fu; fu = fu->nextfu) { | 574 | for (fu = fs->nextfu; fu; fu = fu->nextfu) { |
575 | int cnt; | ||
537 | if (fu->flags & F_IGNORE) { | 576 | if (fu->flags & F_IGNORE) { |
538 | break; | 577 | break; |
539 | } | 578 | } |
540 | for (cnt = fu->reps; cnt; --cnt) { | 579 | for (cnt = fu->reps; cnt; --cnt) { |
580 | PR *pr; | ||
541 | for (pr = fu->nextpr; pr; dumper->address += pr->bcnt, | 581 | for (pr = fu->nextpr; pr; dumper->address += pr->bcnt, |
542 | bp += pr->bcnt, pr = pr->nextpr) { | 582 | bp += pr->bcnt, pr = pr->nextpr) { |
543 | if (dumper->eaddress && dumper->address >= dumper->eaddress | 583 | if (dumper->eaddress |
544 | && !(pr->flags & (F_TEXT | F_BPAD)) | 584 | && dumper->address >= dumper->eaddress |
545 | ) { | 585 | ) { |
546 | bpad(pr); | 586 | if (dumper->pub.eofstring) { |
587 | /* xxd support: requested to not pad incomplete blocks */ | ||
588 | fputs(dumper->pub.eofstring, stdout); | ||
589 | return; | ||
590 | } | ||
591 | if (!(pr->flags & (F_TEXT | F_BPAD))) | ||
592 | bpad(pr); | ||
547 | } | 593 | } |
548 | if (cnt == 1 && pr->nospace) { | 594 | if (cnt == 1 && pr->nospace) { |
549 | savech = *pr->nospace; | 595 | savech = *pr->nospace; |
550 | *pr->nospace = '\0'; | 596 | *pr->nospace = '\0'; |
551 | } | 597 | } |
552 | /* PRINT; */ | ||
553 | switch (pr->flags) { | 598 | switch (pr->flags) { |
554 | case F_ADDRESS: | 599 | case F_ADDRESS: |
555 | printf(pr->fmt, (unsigned) dumper->address); | 600 | printf(pr->fmt, (unsigned) dumper->address); |
@@ -638,7 +683,9 @@ static void display(priv_dumper_t* dumper) | |||
638 | } | 683 | } |
639 | } | 684 | } |
640 | } | 685 | } |
686 | |||
641 | if (dumper->endfu) { | 687 | if (dumper->endfu) { |
688 | PR *pr; | ||
642 | /* | 689 | /* |
643 | * if eaddress not set, error or file size was multiple | 690 | * if eaddress not set, error or file size was multiple |
644 | * of blocksize, and no partial block ever found. | 691 | * of blocksize, and no partial block ever found. |
@@ -695,8 +742,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) | |||
695 | { | 742 | { |
696 | const char *p; | 743 | const char *p; |
697 | FS *tfs; | 744 | FS *tfs; |
698 | FU *tfu, **nextfupp; | 745 | FU **nextfupp; |
699 | const char *savep; | ||
700 | 746 | ||
701 | /* start new linked list of format units */ | 747 | /* start new linked list of format units */ |
702 | tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */ | 748 | tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */ |
@@ -713,6 +759,9 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) | |||
713 | /* take the format string and break it up into format units */ | 759 | /* take the format string and break it up into format units */ |
714 | p = fmt; | 760 | p = fmt; |
715 | for (;;) { | 761 | for (;;) { |
762 | FU *tfu; | ||
763 | const char *savep; | ||
764 | |||
716 | p = skip_whitespace(p); | 765 | p = skip_whitespace(p); |
717 | if (*p == '\0') { | 766 | if (*p == '\0') { |
718 | break; | 767 | break; |
diff --git a/testsuite/xxd.tests b/testsuite/xxd.tests new file mode 100755 index 000000000..2e80be5fe --- /dev/null +++ b/testsuite/xxd.tests | |||
@@ -0,0 +1,34 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # Copyright 2020 by Denys Vlasenko <vda.linux@googlemail.com> | ||
4 | # Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | |||
6 | . ./testing.sh | ||
7 | |||
8 | # testing "description" "command" "result" "infile" "stdin" | ||
9 | testing 'xxd -p with one NUL' \ | ||
10 | 'xxd -p' \ | ||
11 | "\ | ||
12 | 00 | ||
13 | " \ | ||
14 | '' \ | ||
15 | '\0' | ||
16 | |||
17 | testing 'xxd -p with 30 NULs' \ | ||
18 | 'xxd -p' \ | ||
19 | "\ | ||
20 | 000000000000000000000000000000000000000000000000000000000000 | ||
21 | " \ | ||
22 | '' \ | ||
23 | '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0' | ||
24 | |||
25 | testing 'xxd -p with 31 NULs' \ | ||
26 | 'xxd -p' \ | ||
27 | "\ | ||
28 | 000000000000000000000000000000000000000000000000000000000000 | ||
29 | 00 | ||
30 | " \ | ||
31 | '' \ | ||
32 | '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0' | ||
33 | |||
34 | exit $FAILCOUNT | ||
diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c index 6cf6d0297..f2d1ecb2c 100644 --- a/util-linux/hexdump_xxd.c +++ b/util-linux/hexdump_xxd.c | |||
@@ -141,6 +141,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
141 | bb_dump_add(dumper, buf); | 141 | bb_dump_add(dumper, buf); |
142 | } else { | 142 | } else { |
143 | bb_dump_add(dumper, "\"\n\""); | 143 | bb_dump_add(dumper, "\"\n\""); |
144 | dumper->eofstring = "\n"; | ||
144 | } | 145 | } |
145 | 146 | ||
146 | return bb_dump_dump(dumper, argv); | 147 | return bb_dump_dump(dumper, argv); |