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>
This commit is contained in:
parent
085f19cdff
commit
dac5b83142
@ -2,50 +2,15 @@
|
||||
|
||||
PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
|
||||
|
||||
#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 */
|
||||
|
||||
enum dump_vflag_t { ALL, DUP, FIRST, WAIT }; /* -v values */
|
||||
|
||||
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 FS FS;
|
||||
|
||||
typedef struct dumper_t {
|
||||
off_t dump_skip; /* bytes to skip */
|
||||
int dump_length; /* max bytes to read */
|
||||
smallint dump_vflag; /*enum dump_vflag_t*/
|
||||
const char *eofstring;
|
||||
FS *fshead;
|
||||
} dumper_t;
|
||||
|
||||
|
87
libbb/dump.c
87
libbb/dump.c
@ -13,13 +13,43 @@
|
||||
#include "libbb.h"
|
||||
#include "dump.h"
|
||||
|
||||
static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789";
|
||||
#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 */
|
||||
|
||||
static const char size_conv_str[] ALIGN1 =
|
||||
"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
|
||||
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;
|
||||
|
||||
static const char int_convs[] ALIGN1 = "diouxX";
|
||||
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:[dave@cray.com] 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;
|
||||
|
34
testsuite/xxd.tests
Executable file
34
testsuite/xxd.tests
Executable file
@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright 2020 by Denys Vlasenko <vda.linux@googlemail.com>
|
||||
# Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
|
||||
. ./testing.sh
|
||||
|
||||
# testing "description" "command" "result" "infile" "stdin"
|
||||
testing 'xxd -p with one NUL' \
|
||||
'xxd -p' \
|
||||
"\
|
||||
00
|
||||
" \
|
||||
'' \
|
||||
'\0'
|
||||
|
||||
testing 'xxd -p with 30 NULs' \
|
||||
'xxd -p' \
|
||||
"\
|
||||
000000000000000000000000000000000000000000000000000000000000
|
||||
" \
|
||||
'' \
|
||||
'\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'
|
||||
|
||||
testing 'xxd -p with 31 NULs' \
|
||||
'xxd -p' \
|
||||
"\
|
||||
000000000000000000000000000000000000000000000000000000000000
|
||||
00
|
||||
" \
|
||||
'' \
|
||||
'\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'
|
||||
|
||||
exit $FAILCOUNT
|
@ -141,6 +141,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv)
|
||||
bb_dump_add(dumper, buf);
|
||||
} else {
|
||||
bb_dump_add(dumper, "\"\n\"");
|
||||
dumper->eofstring = "\n";
|
||||
}
|
||||
|
||||
return bb_dump_dump(dumper, argv);
|
||||
|
Loading…
Reference in New Issue
Block a user