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
|
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 */
|
enum dump_vflag_t { ALL, DUP, FIRST, WAIT }; /* -v values */
|
||||||
|
|
||||||
typedef struct PR {
|
typedef struct FS FS;
|
||||||
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 dumper_t {
|
typedef struct dumper_t {
|
||||||
off_t dump_skip; /* bytes to skip */
|
off_t dump_skip; /* bytes to skip */
|
||||||
int dump_length; /* max bytes to read */
|
int dump_length; /* max bytes to read */
|
||||||
smallint dump_vflag; /*enum dump_vflag_t*/
|
smallint dump_vflag; /*enum dump_vflag_t*/
|
||||||
|
const char *eofstring;
|
||||||
FS *fshead;
|
FS *fshead;
|
||||||
} dumper_t;
|
} dumper_t;
|
||||||
|
|
||||||
|
87
libbb/dump.c
87
libbb/dump.c
@ -13,13 +13,43 @@
|
|||||||
#include "libbb.h"
|
#include "libbb.h"
|
||||||
#include "dump.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 =
|
typedef struct PR {
|
||||||
"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
|
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 {
|
typedef struct priv_dumper_t {
|
||||||
dumper_t pub;
|
dumper_t pub;
|
||||||
@ -39,6 +69,13 @@ typedef struct priv_dumper_t {
|
|||||||
unsigned char *get__savp;
|
unsigned char *get__savp;
|
||||||
} priv_dumper_t;
|
} 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)
|
dumper_t* FAST_FUNC alloc_dumper(void)
|
||||||
{
|
{
|
||||||
priv_dumper_t *dumper = xzalloc(sizeof(*dumper));
|
priv_dumper_t *dumper = xzalloc(sizeof(*dumper));
|
||||||
@ -48,7 +85,6 @@ dumper_t* FAST_FUNC alloc_dumper(void)
|
|||||||
return &dumper->pub;
|
return &dumper->pub;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static NOINLINE int bb_dump_size(FS *fs)
|
static NOINLINE int bb_dump_size(FS *fs)
|
||||||
{
|
{
|
||||||
FU *fu;
|
FU *fu;
|
||||||
@ -284,7 +320,9 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
|
|||||||
* repeat it as necessary.
|
* repeat it as necessary.
|
||||||
*
|
*
|
||||||
* if rep count is greater than 1, no trailing whitespace
|
* 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) {
|
for (fu = fs->nextfu; fu; fu = fu->nextfu) {
|
||||||
if (!fu->nextfu
|
if (!fu->nextfu
|
||||||
@ -453,7 +491,7 @@ static void bpad(PR *pr)
|
|||||||
for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1)
|
for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1)
|
||||||
if (pr->nospace)
|
if (pr->nospace)
|
||||||
pr->nospace--;
|
pr->nospace--;
|
||||||
while ((*p2++ = *p1++) != 0)
|
while ((*p2++ = *p1++) != '\0')
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,36 +558,43 @@ static void conv_u(PR *pr, unsigned char *p)
|
|||||||
|
|
||||||
static void display(priv_dumper_t* dumper)
|
static void display(priv_dumper_t* dumper)
|
||||||
{
|
{
|
||||||
FS *fs;
|
unsigned char *bp;
|
||||||
FU *fu;
|
|
||||||
PR *pr;
|
|
||||||
int cnt;
|
|
||||||
unsigned char *bp, *savebp;
|
|
||||||
off_t saveaddress;
|
|
||||||
unsigned char savech = '\0';
|
unsigned char savech = '\0';
|
||||||
|
|
||||||
while ((bp = get(dumper)) != NULL) {
|
while ((bp = get(dumper)) != NULL) {
|
||||||
|
FS *fs;
|
||||||
|
unsigned char *savebp;
|
||||||
|
off_t saveaddress;
|
||||||
|
|
||||||
fs = dumper->pub.fshead;
|
fs = dumper->pub.fshead;
|
||||||
savebp = bp;
|
savebp = bp;
|
||||||
saveaddress = dumper->address;
|
saveaddress = dumper->address;
|
||||||
for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) {
|
for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) {
|
||||||
|
FU *fu;
|
||||||
for (fu = fs->nextfu; fu; fu = fu->nextfu) {
|
for (fu = fs->nextfu; fu; fu = fu->nextfu) {
|
||||||
|
int cnt;
|
||||||
if (fu->flags & F_IGNORE) {
|
if (fu->flags & F_IGNORE) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (cnt = fu->reps; cnt; --cnt) {
|
for (cnt = fu->reps; cnt; --cnt) {
|
||||||
|
PR *pr;
|
||||||
for (pr = fu->nextpr; pr; dumper->address += pr->bcnt,
|
for (pr = fu->nextpr; pr; dumper->address += pr->bcnt,
|
||||||
bp += pr->bcnt, pr = pr->nextpr) {
|
bp += pr->bcnt, pr = pr->nextpr) {
|
||||||
if (dumper->eaddress && dumper->address >= dumper->eaddress
|
if (dumper->eaddress
|
||||||
&& !(pr->flags & (F_TEXT | F_BPAD))
|
&& 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) {
|
if (cnt == 1 && pr->nospace) {
|
||||||
savech = *pr->nospace;
|
savech = *pr->nospace;
|
||||||
*pr->nospace = '\0';
|
*pr->nospace = '\0';
|
||||||
}
|
}
|
||||||
/* PRINT; */
|
|
||||||
switch (pr->flags) {
|
switch (pr->flags) {
|
||||||
case F_ADDRESS:
|
case F_ADDRESS:
|
||||||
printf(pr->fmt, (unsigned) dumper->address);
|
printf(pr->fmt, (unsigned) dumper->address);
|
||||||
@ -638,7 +683,9 @@ static void display(priv_dumper_t* dumper)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dumper->endfu) {
|
if (dumper->endfu) {
|
||||||
|
PR *pr;
|
||||||
/*
|
/*
|
||||||
* if eaddress not set, error or file size was multiple
|
* if eaddress not set, error or file size was multiple
|
||||||
* of blocksize, and no partial block ever found.
|
* 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;
|
const char *p;
|
||||||
FS *tfs;
|
FS *tfs;
|
||||||
FU *tfu, **nextfupp;
|
FU **nextfupp;
|
||||||
const char *savep;
|
|
||||||
|
|
||||||
/* start new linked list of format units */
|
/* start new linked list of format units */
|
||||||
tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
|
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 */
|
/* take the format string and break it up into format units */
|
||||||
p = fmt;
|
p = fmt;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
FU *tfu;
|
||||||
|
const char *savep;
|
||||||
|
|
||||||
p = skip_whitespace(p);
|
p = skip_whitespace(p);
|
||||||
if (*p == '\0') {
|
if (*p == '\0') {
|
||||||
break;
|
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);
|
bb_dump_add(dumper, buf);
|
||||||
} else {
|
} else {
|
||||||
bb_dump_add(dumper, "\"\n\"");
|
bb_dump_add(dumper, "\"\n\"");
|
||||||
|
dumper->eofstring = "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
return bb_dump_dump(dumper, argv);
|
return bb_dump_dump(dumper, argv);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user