libbb: shrink sump.c
function old new delta dot_flags_width_chars - 16 +16 int_convs - 7 +7 lcc 7 - -7 index_str 16 - -16 rewrite 1013 937 -76 ------------------------------------------------------------------------------ (add/remove: 2/2 grow/shrink: 0/1 up/down: 23/-99) Total: -76 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
b13b618335
commit
cb8e84e65a
159
libbb/dump.c
159
libbb/dump.c
@ -14,12 +14,12 @@
|
|||||||
#include "libbb.h"
|
#include "libbb.h"
|
||||||
#include "dump.h"
|
#include "dump.h"
|
||||||
|
|
||||||
static const char index_str[] ALIGN1 = ".#-+ 0123456789";
|
static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789";
|
||||||
|
|
||||||
static const char size_conv_str[] ALIGN1 =
|
static const char size_conv_str[] ALIGN1 =
|
||||||
"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
|
"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
|
||||||
|
|
||||||
static const char lcc[] ALIGN1 = "diouxX";
|
static const char int_convs[] ALIGN1 = "diouxX";
|
||||||
|
|
||||||
|
|
||||||
typedef struct priv_dumper_t {
|
typedef struct priv_dumper_t {
|
||||||
@ -71,7 +71,7 @@ static NOINLINE int bb_dump_size(FS *fs)
|
|||||||
* skip any special chars -- save precision in
|
* skip any special chars -- save precision in
|
||||||
* case it's a %s format.
|
* case it's a %s format.
|
||||||
*/
|
*/
|
||||||
while (strchr(index_str + 1, *++fmt))
|
while (strchr(dot_flags_width_chars + 1, *++fmt))
|
||||||
continue;
|
continue;
|
||||||
if (*fmt == '.' && isdigit(*++fmt)) {
|
if (*fmt == '.' && isdigit(*++fmt)) {
|
||||||
prec = atoi(fmt);
|
prec = atoi(fmt);
|
||||||
@ -82,14 +82,15 @@ static NOINLINE int bb_dump_size(FS *fs)
|
|||||||
if (!p) {
|
if (!p) {
|
||||||
if (*fmt == 's') {
|
if (*fmt == 's') {
|
||||||
bcnt += prec;
|
bcnt += prec;
|
||||||
} else if (*fmt == '_') {
|
}
|
||||||
|
if (*fmt == '_') {
|
||||||
++fmt;
|
++fmt;
|
||||||
if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
|
if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
|
||||||
bcnt += 1;
|
bcnt += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bcnt += size_conv_str[p - (size_conv_str + 12)];
|
bcnt += p[-12];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cur_size += bcnt * fu->reps;
|
cur_size += bcnt * fu->reps;
|
||||||
@ -99,32 +100,30 @@ static NOINLINE int bb_dump_size(FS *fs)
|
|||||||
|
|
||||||
static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
|
static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
|
||||||
{
|
{
|
||||||
enum { NOTOKAY, USEBCNT, USEPREC } sokay;
|
|
||||||
FU *fu;
|
FU *fu;
|
||||||
PR *pr;
|
|
||||||
char *p1, *p2, *p3;
|
|
||||||
char savech, *fmtp;
|
|
||||||
const char *byte_count_str;
|
|
||||||
int nconv, prec = 0;
|
|
||||||
|
|
||||||
for (fu = fs->nextfu; fu; fu = fu->nextfu) {
|
for (fu = fs->nextfu; fu; fu = fu->nextfu) {
|
||||||
|
PR *pr;
|
||||||
|
char *p1, *p2, *p3;
|
||||||
|
char *fmtp;
|
||||||
|
int nconv = 0;
|
||||||
/*
|
/*
|
||||||
* break each format unit into print units; each
|
* break each format unit into print units; each
|
||||||
* conversion character gets its own.
|
* conversion character gets its own.
|
||||||
*/
|
*/
|
||||||
for (nconv = 0, fmtp = fu->fmt; *fmtp; ) {
|
for (fmtp = fu->fmt; *fmtp; ) {
|
||||||
/* NOSTRICT */
|
unsigned len;
|
||||||
/* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL*/
|
const char *prec;
|
||||||
pr = xzalloc(sizeof(PR));
|
const char *byte_count_str;
|
||||||
|
|
||||||
|
/* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL */
|
||||||
|
pr = xzalloc(sizeof(*pr));
|
||||||
if (!fu->nextpr)
|
if (!fu->nextpr)
|
||||||
fu->nextpr = pr;
|
fu->nextpr = pr;
|
||||||
|
|
||||||
/* skip preceding text and up to the next % sign */
|
/* skip preceding text and up to the next % sign */
|
||||||
for (p1 = fmtp; *p1 && *p1 != '%'; ++p1)
|
p1 = strchr(fmtp, '%');
|
||||||
continue;
|
if (!p1) { /* only text in the string */
|
||||||
|
|
||||||
/* only text in the string */
|
|
||||||
if (!*p1) {
|
|
||||||
pr->fmt = fmtp;
|
pr->fmt = fmtp;
|
||||||
pr->flags = F_TEXT;
|
pr->flags = F_TEXT;
|
||||||
break;
|
break;
|
||||||
@ -134,22 +133,20 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
|
|||||||
* get precision for %s -- if have a byte count, don't
|
* get precision for %s -- if have a byte count, don't
|
||||||
* need it.
|
* need it.
|
||||||
*/
|
*/
|
||||||
|
prec = NULL;
|
||||||
if (fu->bcnt) {
|
if (fu->bcnt) {
|
||||||
sokay = USEBCNT;
|
|
||||||
/* skip to conversion character */
|
/* skip to conversion character */
|
||||||
for (++p1; strchr(index_str, *p1); ++p1)
|
while (strchr(dot_flags_width_chars, *++p1))
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
/* skip any special chars, field width */
|
/* skip any special chars, field width */
|
||||||
while (strchr(index_str + 1, *++p1))
|
while (strchr(dot_flags_width_chars + 1, *++p1))
|
||||||
continue;
|
continue;
|
||||||
if (*p1 == '.' && isdigit(*++p1)) {
|
if (*p1 == '.' && isdigit(*++p1)) {
|
||||||
sokay = USEPREC;
|
prec = p1;
|
||||||
prec = atoi(p1);
|
|
||||||
while (isdigit(*++p1))
|
while (isdigit(*++p1))
|
||||||
continue;
|
continue;
|
||||||
} else
|
}
|
||||||
sokay = NOTOKAY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p2 = p1 + 1; /* set end pointer */
|
p2 = p1 + 1; /* set end pointer */
|
||||||
@ -174,63 +171,63 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
|
|||||||
}
|
}
|
||||||
/* Unlike the original, output the remainder of the format string. */
|
/* Unlike the original, output the remainder of the format string. */
|
||||||
pr->bcnt = *byte_count_str;
|
pr->bcnt = *byte_count_str;
|
||||||
} else if (*p1 == 'l') {
|
} else
|
||||||
|
if (*p1 == 'l') { /* %ld etc */
|
||||||
|
const char *e;
|
||||||
|
|
||||||
++p2;
|
++p2;
|
||||||
++p1;
|
++p1;
|
||||||
DO_INT_CONV:
|
DO_INT_CONV:
|
||||||
{
|
e = strchr(int_convs, *p1); /* "diouxX"? */
|
||||||
const char *e;
|
if (!e)
|
||||||
e = strchr(lcc, *p1);
|
goto DO_BAD_CONV_CHAR;
|
||||||
if (!e) {
|
pr->flags = F_INT;
|
||||||
goto DO_BAD_CONV_CHAR;
|
if (e > int_convs + 1) /* not d or i? */
|
||||||
}
|
pr->flags = F_UINT;
|
||||||
pr->flags = F_INT;
|
byte_count_str = "\004\002\001";
|
||||||
if (e > lcc + 1) {
|
goto DO_BYTE_COUNT;
|
||||||
pr->flags = F_UINT;
|
} else
|
||||||
}
|
if (strchr(int_convs, *p1)) { /* %d etc */
|
||||||
byte_count_str = "\004\002\001";
|
|
||||||
goto DO_BYTE_COUNT;
|
|
||||||
}
|
|
||||||
/* NOTREACHED */
|
|
||||||
} else if (strchr(lcc, *p1)) {
|
|
||||||
goto DO_INT_CONV;
|
goto DO_INT_CONV;
|
||||||
} else if (strchr("eEfgG", *p1)) {
|
} else
|
||||||
|
if (strchr("eEfgG", *p1)) { /* floating point */
|
||||||
pr->flags = F_DBL;
|
pr->flags = F_DBL;
|
||||||
byte_count_str = "\010\004";
|
byte_count_str = "\010\004";
|
||||||
goto DO_BYTE_COUNT;
|
goto DO_BYTE_COUNT;
|
||||||
} else if (*p1 == 's') {
|
} else
|
||||||
|
if (*p1 == 's') {
|
||||||
pr->flags = F_STR;
|
pr->flags = F_STR;
|
||||||
if (sokay == USEBCNT) {
|
pr->bcnt = fu->bcnt;
|
||||||
pr->bcnt = fu->bcnt;
|
if (fu->bcnt == 0) {
|
||||||
} else if (sokay == USEPREC) {
|
if (!prec)
|
||||||
pr->bcnt = prec;
|
bb_error_msg_and_die("%%s needs precision or byte count");
|
||||||
} else { /* NOTOKAY */
|
pr->bcnt = atoi(prec);
|
||||||
bb_error_msg_and_die("%%s requires a precision or a byte count");
|
|
||||||
}
|
}
|
||||||
} else if (*p1 == '_') {
|
} else
|
||||||
++p2;
|
if (*p1 == '_') {
|
||||||
|
p2++; /* move past a in "%_a" */
|
||||||
switch (p1[1]) {
|
switch (p1[1]) {
|
||||||
case 'A':
|
case 'A': /* %_A[dox]: print address and the end */
|
||||||
dumper->endfu = fu;
|
dumper->endfu = fu;
|
||||||
fu->flags |= F_IGNORE;
|
fu->flags |= F_IGNORE;
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case 'a':
|
case 'a': /* %_a[dox]: current address */
|
||||||
pr->flags = F_ADDRESS;
|
pr->flags = F_ADDRESS;
|
||||||
++p2;
|
p2++; /* move past x in "%_ax" */
|
||||||
if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
|
if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
|
||||||
goto DO_BAD_CONV_CHAR;
|
goto DO_BAD_CONV_CHAR;
|
||||||
}
|
}
|
||||||
*p1 = p1[2];
|
*p1 = p1[2];
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c': /* %_c: chars, \ooo, \n \r \t etc */
|
||||||
pr->flags = F_C;
|
pr->flags = F_C;
|
||||||
/* *p1 = 'c'; set in conv_c */
|
/* *p1 = 'c'; set in conv_c */
|
||||||
goto DO_BYTE_COUNT_1;
|
goto DO_BYTE_COUNT_1;
|
||||||
case 'p':
|
case 'p': /* %_p: chars, dots for nonprintable */
|
||||||
pr->flags = F_P;
|
pr->flags = F_P;
|
||||||
*p1 = 'c';
|
*p1 = 'c';
|
||||||
goto DO_BYTE_COUNT_1;
|
goto DO_BYTE_COUNT_1;
|
||||||
case 'u':
|
case 'u': /* %_p: chars, 'nul', 'esc' etc for nonprintable */
|
||||||
pr->flags = F_U;
|
pr->flags = F_U;
|
||||||
/* *p1 = 'c'; set in conv_u */
|
/* *p1 = 'c'; set in conv_u */
|
||||||
goto DO_BYTE_COUNT_1;
|
goto DO_BYTE_COUNT_1;
|
||||||
@ -246,13 +243,8 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
|
|||||||
* copy to PR format string, set conversion character
|
* copy to PR format string, set conversion character
|
||||||
* pointer, update original.
|
* pointer, update original.
|
||||||
*/
|
*/
|
||||||
savech = *p2;
|
len = (p1 - fmtp) + 1;
|
||||||
p1[1] = '\0';
|
pr->fmt = xstrndup(fmtp, len);
|
||||||
pr->fmt = xstrdup(fmtp);
|
|
||||||
*p2 = savech;
|
|
||||||
//Too early! xrealloc can move pr->fmt!
|
|
||||||
//pr->cchar = pr->fmt + (p1 - fmtp);
|
|
||||||
|
|
||||||
/* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
|
/* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
|
||||||
* Skip subsequent text and up to the next % sign and tack the
|
* Skip subsequent text and up to the next % sign and tack the
|
||||||
* additional text onto fmt: eg. if fmt is "%x is a HEX number",
|
* additional text onto fmt: eg. if fmt is "%x is a HEX number",
|
||||||
@ -260,16 +252,17 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
|
|||||||
*/
|
*/
|
||||||
for (p3 = p2; *p3 && *p3 != '%'; p3++)
|
for (p3 = p2; *p3 && *p3 != '%'; p3++)
|
||||||
continue;
|
continue;
|
||||||
if (p3 > p2) {
|
if ((p3 - p2) != 0) {
|
||||||
savech = *p3;
|
char *d;
|
||||||
*p3 = '\0';
|
pr->fmt = d = xrealloc(pr->fmt, len + (p3 - p2) + 1);
|
||||||
pr->fmt = xrealloc(pr->fmt, strlen(pr->fmt) + (p3-p2) + 1);
|
d += len;
|
||||||
strcat(pr->fmt, p2);
|
do {
|
||||||
*p3 = savech;
|
*d++ = *p2++;
|
||||||
p2 = p3;
|
} while (p2 != p3);
|
||||||
|
*d = '\0';
|
||||||
|
/* now p2 = p3 */
|
||||||
}
|
}
|
||||||
|
pr->cchar = pr->fmt + len - 1; /* must be after realloc! */
|
||||||
pr->cchar = pr->fmt + (p1 - fmtp);
|
|
||||||
fmtp = p2;
|
fmtp = p2;
|
||||||
|
|
||||||
/* only one conversion character if byte count */
|
/* only one conversion character if byte count */
|
||||||
@ -281,7 +274,7 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
|
|||||||
* if format unit byte count not specified, figure it out
|
* if format unit byte count not specified, figure it out
|
||||||
* so can adjust rep count later.
|
* so can adjust rep count later.
|
||||||
*/
|
*/
|
||||||
if (!fu->bcnt)
|
if (fu->bcnt == 0)
|
||||||
for (pr = fu->nextpr; pr; pr = pr->nextpr)
|
for (pr = fu->nextpr; pr; pr = pr->nextpr)
|
||||||
fu->bcnt += pr->bcnt;
|
fu->bcnt += pr->bcnt;
|
||||||
}
|
}
|
||||||
@ -303,16 +296,18 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
|
|||||||
fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt;
|
fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt;
|
||||||
}
|
}
|
||||||
if (fu->reps > 1 && fu->nextpr) {
|
if (fu->reps > 1 && fu->nextpr) {
|
||||||
|
PR *pr;
|
||||||
|
char *p1, *p2;
|
||||||
|
|
||||||
for (pr = fu->nextpr;; pr = pr->nextpr)
|
for (pr = fu->nextpr;; pr = pr->nextpr)
|
||||||
if (!pr->nextpr)
|
if (!pr->nextpr)
|
||||||
break;
|
break;
|
||||||
for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
|
p2 = NULL;
|
||||||
|
for (p1 = pr->fmt; *p1; ++p1)
|
||||||
p2 = isspace(*p1) ? p1 : NULL;
|
p2 = isspace(*p1) ? p1 : NULL;
|
||||||
if (p2)
|
if (p2)
|
||||||
pr->nospace = p2;
|
pr->nospace = p2;
|
||||||
}
|
}
|
||||||
if (!fu->nextfu)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,6 +351,7 @@ static NOINLINE int next(priv_dumper_t *dumper)
|
|||||||
if (dumper->next__done)
|
if (dumper->next__done)
|
||||||
return 0; /* no next file */
|
return 0; /* no next file */
|
||||||
dumper->next__done = 1;
|
dumper->next__done = 1;
|
||||||
|
//why stat of stdin is specially prohibited?
|
||||||
statok = 0;
|
statok = 0;
|
||||||
}
|
}
|
||||||
if (dumper->pub.dump_skip)
|
if (dumper->pub.dump_skip)
|
||||||
@ -760,6 +756,11 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
|
|||||||
if (!isspace(*p)) {
|
if (!isspace(*p)) {
|
||||||
bb_error_msg_and_die("bad format {%s}", fmt);
|
bb_error_msg_and_die("bad format {%s}", fmt);
|
||||||
}
|
}
|
||||||
|
// Above check prohibits formats such as '/1"%02x"' - it requires space after 1.
|
||||||
|
// Other than this, formats can be pretty much jammed together:
|
||||||
|
// "%07_ax:"8/2 "%04x|""\n"
|
||||||
|
// but this space is required. The check *can* be removed, but
|
||||||
|
// keeping it to stay compat with util-linux hexdump.
|
||||||
tfu->bcnt = atoi(savep);
|
tfu->bcnt = atoi(savep);
|
||||||
/* skip trailing white space */
|
/* skip trailing white space */
|
||||||
p = skip_whitespace(p + 1);
|
p = skip_whitespace(p + 1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user