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:
Denys Vlasenko 2017-01-25 16:21:00 +01:00
parent b13b618335
commit cb8e84e65a

View File

@ -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);