| @@ -13,13 +13,43 @@ |
| #include "libbb.h" |
| #include "dump.h" |
| |
| - | static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; |
| - | |
| - | static const char size_conv_str[] ALIGN1 = |
| - | "\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG"; |
| - | |
| - | static const char int_convs[] ALIGN1 = "diouxX"; |
| - | |
| + | #define F_IGNORE 0x01 /* %_A */ |
| + | #define F_SETREP 0x02 /* rep count set, not default */ |
| + | #define F_ADDRESS 0x001 /* print offset */ |
| + | #define F_BPAD 0x002 /* blank pad */ |
| + | #define F_C 0x004 /* %_c */ |
| + | #define F_CHAR 0x008 /* %c */ |
| + | #define F_DBL 0x010 /* %[EefGf] */ |
| + | #define F_INT 0x020 /* %[di] */ |
| + | #define F_P 0x040 /* %_p */ |
| + | #define F_STR 0x080 /* %s */ |
| + | #define F_U 0x100 /* %_u */ |
| + | #define F_UINT 0x200 /* %[ouXx] */ |
| + | #define F_TEXT 0x400 /* no conversions */ |
| + | |
| + | typedef struct PR { |
| + | struct PR *nextpr; /* next print unit */ |
| + | unsigned flags; /* flag values */ |
| + | int bcnt; /* byte count */ |
| + | char *cchar; /* conversion character */ |
| + | char *fmt; /* printf format */ |
| + | char *nospace; /* no whitespace version */ |
| + | } PR; |
| + | |
| + | typedef struct FU { |
| + | struct FU *nextfu; /* next format unit */ |
| + | struct PR *nextpr; /* next print unit */ |
| + | unsigned flags; /* flag values */ |
| + | int reps; /* repetition count */ |
| + | int bcnt; /* byte count */ |
| + | char *fmt; /* format string */ |
| + | } FU; |
| + | |
| + | typedef struct FS { /* format strings */ |
| + | struct FS *nextfs; /* linked list of format strings */ |
| + | struct FU *nextfu; /* linked list of format units */ |
| + | int bcnt; |
| + | } FS; |
| |
| typedef struct priv_dumper_t { |
| dumper_t pub; |
| @@ -39,6 +69,13 @@ typedef struct priv_dumper_t { |
| unsigned char *get__savp; |
| } priv_dumper_t; |
| |
| + | static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; |
| + | |
| + | static const char size_conv_str[] ALIGN1 = |
| + | "\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG"; |
| + | |
| + | static const char int_convs[] ALIGN1 = "diouxX"; |
| + | |
| dumper_t* FAST_FUNC alloc_dumper(void) |
| { |
| priv_dumper_t *dumper = xzalloc(sizeof(*dumper)); |
| @@ -48,7 +85,6 @@ dumper_t* FAST_FUNC alloc_dumper(void) |
| return &dumper->pub; |
| } |
| |
| - | |
| static NOINLINE int bb_dump_size(FS *fs) |
| { |
| FU *fu; |
| @@ -284,7 +320,9 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) |
| * repeat it as necessary. |
| * |
| * if rep count is greater than 1, no trailing whitespace |
| - | * gets output from the last iteration of the format unit. |
| + | * gets output from the last iteration of the format unit: |
| + | * 2/1 "%02x " prints "XX XX", not "XX XX " |
| + | * 2/1 "%02x\n" prints "XX\nXX", not "XX\nXX\n" |
| */ |
| for (fu = fs->nextfu; fu; fu = fu->nextfu) { |
| if (!fu->nextfu |
| @@ -453,7 +491,7 @@ static void bpad(PR *pr) |
| for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1) |
| if (pr->nospace) |
| pr->nospace--; |
| - | while ((*p2++ = *p1++) != 0) |
| + | while ((*p2++ = *p1++) != '\0') |
| continue; |
| } |
| |
| @@ -520,36 +558,43 @@ static void conv_u(PR *pr, unsigned char *p) |
| |
| static void display(priv_dumper_t* dumper) |
| { |
| - | FS *fs; |
| - | FU *fu; |
| - | PR *pr; |
| - | int cnt; |
| - | unsigned char *bp, *savebp; |
| - | off_t saveaddress; |
| + | unsigned char *bp; |
| unsigned char savech = '\0'; |
| |
| while ((bp = get(dumper)) != NULL) { |
| + | FS *fs; |
| + | unsigned char *savebp; |
| + | off_t saveaddress; |
| + | |
| fs = dumper->pub.fshead; |
| savebp = bp; |
| saveaddress = dumper->address; |
| for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) { |
| + | FU *fu; |
| for (fu = fs->nextfu; fu; fu = fu->nextfu) { |
| + | int cnt; |
| if (fu->flags & F_IGNORE) { |
| break; |
| } |
| for (cnt = fu->reps; cnt; --cnt) { |
| + | PR *pr; |
| for (pr = fu->nextpr; pr; dumper->address += pr->bcnt, |
| bp += pr->bcnt, pr = pr->nextpr) { |
| - | if (dumper->eaddress && dumper->address >= dumper->eaddress |
| - | && !(pr->flags & (F_TEXT | F_BPAD)) |
| + | if (dumper->eaddress |
| + | && dumper->address >= dumper->eaddress |
| ) { |
| - | bpad(pr); |
| + | if (dumper->pub.eofstring) { |
| + | /* xxd support: requested to not pad incomplete blocks */ |
| + | fputs(dumper->pub.eofstring, stdout); |
| + | return; |
| + | } |
| + | if (!(pr->flags & (F_TEXT | F_BPAD))) |
| + | bpad(pr); |
| } |
| if (cnt == 1 && pr->nospace) { |
| savech = *pr->nospace; |
| *pr->nospace = '\0'; |
| } |
| - | /* PRINT; */ |
| switch (pr->flags) { |
| case F_ADDRESS: |
| printf(pr->fmt, (unsigned) dumper->address); |
| @@ -638,7 +683,9 @@ static void display(priv_dumper_t* dumper) |
| } |
| } |
| } |
| + | |
| if (dumper->endfu) { |
| + | PR *pr; |
| /* |
| * if eaddress not set, error or file size was multiple |
| * 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) |
| { |
| const char *p; |
| FS *tfs; |
| - | FU *tfu, **nextfupp; |
| - | const char *savep; |
| + | FU **nextfupp; |
| |
| /* start new linked list of format units */ |
| tfs = xzalloc(sizeof(FS)); /*DBU:[[email protected]] start out NULL */ |
| @@ -713,6 +759,9 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) |
| /* take the format string and break it up into format units */ |
| p = fmt; |
| for (;;) { |
| + | FU *tfu; |
| + | const char *savep; |
| + | |
| p = skip_whitespace(p); |
| if (*p == '\0') { |
| break; |