aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2020-10-20 18:54:36 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2020-10-20 18:57:02 +0200
commitdac5b8314236338963877903cba3d7edfbfc9c58 (patch)
tree5e7ce92407b9079b4e49e728f28f8a7c6311999c
parent085f19cdffd653013b1483c08851ecc35cdd818e (diff)
downloadbusybox-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.h39
-rw-r--r--libbb/dump.c93
-rwxr-xr-xtestsuite/xxd.tests34
-rw-r--r--util-linux/hexdump_xxd.c1
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
3PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 3PUSH_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
19enum dump_vflag_t { ALL, DUP, FIRST, WAIT }; /* -v values */ 5enum dump_vflag_t { ALL, DUP, FIRST, WAIT }; /* -v values */
20 6
21typedef struct PR { 7typedef 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
30typedef 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
39typedef 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
45typedef struct dumper_t { 9typedef 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
16static 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 */
18static 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 */
21static 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
30typedef 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
39typedef 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
48typedef 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
24typedef struct priv_dumper_t { 54typedef 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
72static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789";
73
74static const char size_conv_str[] ALIGN1 =
75"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
76
77static const char int_convs[] ALIGN1 = "diouxX";
78
42dumper_t* FAST_FUNC alloc_dumper(void) 79dumper_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
52static NOINLINE int bb_dump_size(FS *fs) 88static 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
521static void display(priv_dumper_t* dumper) 559static 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"
9testing 'xxd -p with one NUL' \
10 'xxd -p' \
11 "\
1200
13" \
14 '' \
15 '\0'
16
17testing 'xxd -p with 30 NULs' \
18 'xxd -p' \
19 "\
20000000000000000000000000000000000000000000000000000000000000
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
25testing 'xxd -p with 31 NULs' \
26 'xxd -p' \
27 "\
28000000000000000000000000000000000000000000000000000000000000
2900
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
34exit $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);