| @@ -14,19 +14,6 @@ |
| #include "libbb.h" |
| #include "dump.h" |
| |
| - | FS *bb_dump_fshead; /* head of format strings */ |
| - | off_t bb_dump_skip; /* bytes to skip */ |
| - | int bb_dump_blocksize; /* data block size */ |
| - | int bb_dump_length = -1; /* max bytes to read */ |
| - | smallint /*enum _vflag*/ bb_dump_vflag = FIRST; |
| - | |
| - | static FU *endfu; |
| - | static char **_argv; |
| - | static off_t savaddress; /* saved address/offset in stream */ |
| - | static off_t eaddress; /* end address */ |
| - | static off_t address; /* address/offset in stream */ |
| - | static int exitval; /* final exit value */ |
| - | |
| static const char index_str[] ALIGN1 = ".#-+ 0123456789"; |
| |
| static const char size_conv_str[] ALIGN1 = |
| @@ -34,7 +21,36 @@ static const char size_conv_str[] ALIGN1 = |
| |
| static const char lcc[] ALIGN1 = "diouxX"; |
| |
| - | int FAST_FUNC bb_dump_size(FS *fs) |
| + | |
| + | typedef struct priv_dumper_t { |
| + | dumper_t pub; |
| + | |
| + | char **argv; |
| + | FU *endfu; |
| + | off_t savaddress; /* saved address/offset in stream */ |
| + | off_t eaddress; /* end address */ |
| + | off_t address; /* address/offset in stream */ |
| + | int blocksize; |
| + | smallint exitval; /* final exit value */ |
| + | |
| + | /* former statics */ |
| + | smallint next__done; |
| + | smallint get__ateof; // = 1; |
| + | unsigned char *get__curp; |
| + | unsigned char *get__savp; |
| + | } priv_dumper_t; |
| + | |
| + | dumper_t* FAST_FUNC alloc_dumper(void) |
| + | { |
| + | priv_dumper_t *dumper = xzalloc(sizeof(*dumper)); |
| + | dumper->pub.dump_length = -1; |
| + | dumper->pub.dump_vflag = FIRST; |
| + | dumper->get__ateof = 1; |
| + | return &dumper->pub; |
| + | } |
| + | |
| + | |
| + | static NOINLINE int bb_dump_size(FS *fs) |
| { |
| FU *fu; |
| int bcnt, cur_size; |
| @@ -52,13 +68,14 @@ int FAST_FUNC bb_dump_size(FS *fs) |
| if (*fmt != '%') |
| continue; |
| /* |
| - | * bb_dump_skip any special chars -- save precision in |
| + | * skip any special chars -- save precision in |
| * case it's a %s format. |
| */ |
| while (strchr(index_str + 1, *++fmt)); |
| if (*fmt == '.' && isdigit(*++fmt)) { |
| prec = atoi(fmt); |
| - | while (isdigit(*++fmt)); |
| + | while (isdigit(*++fmt)) |
| + | continue; |
| } |
| p = strchr(size_conv_str + 12, *fmt); |
| if (!p) { |
| @@ -79,7 +96,7 @@ int FAST_FUNC bb_dump_size(FS *fs) |
| return cur_size; |
| } |
| |
| - | static void rewrite(FS *fs) |
| + | static void rewrite(priv_dumper_t *dumper, FS *fs) |
| { |
| enum { NOTOKAY, USEBCNT, USEPREC } sokay; |
| PR *pr, **nextpr = NULL; |
| @@ -104,7 +121,7 @@ static void rewrite(FS *fs) |
| * uninitialized 1st time through. |
| */ |
| |
| - | /* bb_dump_skip preceding text and up to the next % sign */ |
| + | /* skip preceding text and up to the next % sign */ |
| for (p1 = fmtp; *p1 && *p1 != '%'; ++p1) |
| continue; |
| |
| @@ -121,11 +138,11 @@ static void rewrite(FS *fs) |
| */ |
| if (fu->bcnt) { |
| sokay = USEBCNT; |
| - | /* bb_dump_skip to conversion character */ |
| + | /* skip to conversion character */ |
| for (++p1; strchr(index_str, *p1); ++p1) |
| continue; |
| } else { |
| - | /* bb_dump_skip any special chars, field width */ |
| + | /* skip any special chars, field width */ |
| while (strchr(index_str + 1, *++p1)) |
| continue; |
| if (*p1 == '.' && isdigit(*++p1)) { |
| @@ -137,7 +154,7 @@ static void rewrite(FS *fs) |
| sokay = NOTOKAY; |
| } |
| |
| - | p2 = p1 + 1; /* set end pointer */ |
| + | p2 = p1 + 1; /* set end pointer */ |
| |
| /* |
| * figure out the byte count for each conversion; |
| @@ -198,7 +215,7 @@ static void rewrite(FS *fs) |
| ++p2; |
| switch (p1[1]) { |
| case 'A': |
| - | endfu = fu; |
| + | dumper->endfu = fu; |
| fu->flags |= F_IGNORE; |
| /* FALLTHROUGH */ |
| case 'a': |
| @@ -274,7 +291,7 @@ static void rewrite(FS *fs) |
| } |
| /* |
| * if the format string interprets any data at all, and it's |
| - | * not the same as the bb_dump_blocksize, and its last format unit |
| + | * not the same as the blocksize, and its last format unit |
| * interprets any data at all, and has no iteration count, |
| * repeat it as necessary. |
| * |
| @@ -282,10 +299,10 @@ static void rewrite(FS *fs) |
| * gets output from the last iteration of the format unit. |
| */ |
| for (fu = fs->nextfu;; fu = fu->nextfu) { |
| - | if (!fu->nextfu && fs->bcnt < bb_dump_blocksize |
| + | if (!fu->nextfu && fs->bcnt < dumper->blocksize |
| && !(fu->flags & F_SETREP) && fu->bcnt |
| ) { |
| - | fu->reps += (bb_dump_blocksize - fs->bcnt) / fu->bcnt; |
| + | fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt; |
| } |
| if (fu->reps > 1) { |
| for (pr = fu->nextpr;; pr = pr->nextpr) |
| @@ -301,7 +318,7 @@ static void rewrite(FS *fs) |
| } |
| } |
| |
| - | static void do_skip(const char *fname, int statok) |
| + | static void do_skip(priv_dumper_t *dumper, const char *fname, int statok) |
| { |
| struct stat sbuf; |
| |
| @@ -309,125 +326,122 @@ static void do_skip(const char *fname, int statok) |
| if (fstat(STDIN_FILENO, &sbuf)) { |
| bb_simple_perror_msg_and_die(fname); |
| } |
| - | if ((!(S_ISCHR(sbuf.st_mode) || |
| - | S_ISBLK(sbuf.st_mode) || |
| - | S_ISFIFO(sbuf.st_mode))) && bb_dump_skip >= sbuf.st_size) { |
| - | /* If bb_dump_size valid and bb_dump_skip >= size */ |
| - | bb_dump_skip -= sbuf.st_size; |
| - | address += sbuf.st_size; |
| + | if (!(S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode) || S_ISFIFO(sbuf.st_mode)) |
| + | && dumper->pub.dump_skip >= sbuf.st_size |
| + | ) { |
| + | /* If bb_dump_size valid and pub.dump_skip >= size */ |
| + | dumper->pub.dump_skip -= sbuf.st_size; |
| + | dumper->address += sbuf.st_size; |
| return; |
| } |
| } |
| - | if (fseek(stdin, bb_dump_skip, SEEK_SET)) { |
| + | if (fseek(stdin, dumper->pub.dump_skip, SEEK_SET)) { |
| bb_simple_perror_msg_and_die(fname); |
| } |
| - | savaddress = address += bb_dump_skip; |
| - | bb_dump_skip = 0; |
| + | dumper->address += dumper->pub.dump_skip; |
| + | dumper->savaddress = dumper->address; |
| + | dumper->pub.dump_skip = 0; |
| } |
| |
| - | static int next(char **argv) |
| + | static NOINLINE int next(priv_dumper_t *dumper) |
| { |
| - | static smallint done; |
| - | |
| int statok; |
| |
| - | if (argv) { |
| - | _argv = argv; |
| - | return 1; |
| - | } |
| for (;;) { |
| - | if (*_argv) { |
| - | if (!(freopen(*_argv, "r", stdin))) { |
| - | bb_simple_perror_msg(*_argv); |
| - | exitval = 1; |
| - | ++_argv; |
| + | if (*dumper->argv) { |
| + | if (!(freopen(*dumper->argv, "r", stdin))) { |
| + | bb_simple_perror_msg(*dumper->argv); |
| + | dumper->exitval = 1; |
| + | ++dumper->argv; |
| continue; |
| } |
| - | done = statok = 1; |
| + | dumper->next__done = statok = 1; |
| } else { |
| - | if (done) |
| + | if (dumper->next__done) |
| return 0; |
| - | done = 1; |
| + | dumper->next__done = 1; |
| statok = 0; |
| } |
| - | if (bb_dump_skip) |
| - | do_skip(statok ? *_argv : "stdin", statok); |
| - | if (*_argv) |
| - | ++_argv; |
| - | if (!bb_dump_skip) |
| + | if (dumper->pub.dump_skip) |
| + | do_skip(dumper, statok ? *dumper->argv : "stdin", statok); |
| + | if (*dumper->argv) |
| + | ++dumper->argv; |
| + | if (!dumper->pub.dump_skip) |
| return 1; |
| } |
| /* NOTREACHED */ |
| } |
| |
| - | static unsigned char *get(void) |
| + | static unsigned char *get(priv_dumper_t *dumper) |
| { |
| - | static smallint ateof = 1; |
| - | static unsigned char *curp = NULL, *savp; /*DBU:[[email protected]]initialize curp */ |
| - | |
| int n; |
| int need, nread; |
| unsigned char *tmpp; |
| + | int blocksize = dumper->blocksize; |
| |
| - | if (!curp) { |
| - | address = (off_t)0; /*DBU:[[email protected]] initialize,initialize..*/ |
| - | curp = xmalloc(bb_dump_blocksize); |
| - | savp = xmalloc(bb_dump_blocksize); |
| + | if (!dumper->get__curp) { |
| + | dumper->address = (off_t)0; /*DBU:[[email protected]] initialize,initialize..*/ |
| + | dumper->get__curp = xmalloc(blocksize); |
| + | dumper->get__savp = xmalloc(blocksize); |
| } else { |
| - | tmpp = curp; |
| - | curp = savp; |
| - | savp = tmpp; |
| - | address = savaddress += bb_dump_blocksize; |
| + | tmpp = dumper->get__curp; |
| + | dumper->get__curp = dumper->get__savp; |
| + | dumper->get__savp = tmpp; |
| + | dumper->savaddress += blocksize; |
| + | dumper->address = dumper->savaddress; |
| } |
| - | for (need = bb_dump_blocksize, nread = 0;;) { |
| + | need = blocksize; |
| + | nread = 0; |
| + | while (1) { |
| /* |
| * if read the right number of bytes, or at EOF for one file, |
| * and no other files are available, zero-pad the rest of the |
| * block and set the end flag. |
| */ |
| - | if (!bb_dump_length || (ateof && !next(NULL))) { |
| - | if (need == bb_dump_blocksize) { |
| + | if (!dumper->pub.dump_length || (dumper->get__ateof && !next(dumper))) { |
| + | if (need == blocksize) { |
| return NULL; |
| } |
| - | if (bb_dump_vflag != ALL && !memcmp(curp, savp, nread)) { |
| - | if (bb_dump_vflag != DUP) { |
| + | if (dumper->pub.dump_vflag != ALL && !memcmp(dumper->get__curp, dumper->get__savp, nread)) { |
| + | if (dumper->pub.dump_vflag != DUP) { |
| puts("*"); |
| } |
| return NULL; |
| } |
| - | memset(curp + nread, 0, need); |
| - | eaddress = address + nread; |
| - | return curp; |
| + | memset(dumper->get__curp + nread, 0, need); |
| + | dumper->eaddress = dumper->address + nread; |
| + | return dumper->get__curp; |
| } |
| - | n = fread(curp + nread, sizeof(unsigned char), |
| - | bb_dump_length == -1 ? need : MIN(bb_dump_length, need), stdin); |
| + | n = fread(dumper->get__curp + nread, sizeof(unsigned char), |
| + | dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), stdin); |
| if (!n) { |
| if (ferror(stdin)) { |
| - | bb_simple_perror_msg(_argv[-1]); |
| + | bb_simple_perror_msg(dumper->argv[-1]); |
| } |
| - | ateof = 1; |
| + | dumper->get__ateof = 1; |
| continue; |
| } |
| - | ateof = 0; |
| - | if (bb_dump_length != -1) { |
| - | bb_dump_length -= n; |
| + | dumper->get__ateof = 0; |
| + | if (dumper->pub.dump_length != -1) { |
| + | dumper->pub.dump_length -= n; |
| } |
| need -= n; |
| if (!need) { |
| - | if (bb_dump_vflag == ALL || bb_dump_vflag == FIRST |
| - | || memcmp(curp, savp, bb_dump_blocksize) |
| + | if (dumper->pub.dump_vflag == ALL || dumper->pub.dump_vflag == FIRST |
| + | || memcmp(dumper->get__curp, dumper->get__savp, blocksize) |
| ) { |
| - | if (bb_dump_vflag == DUP || bb_dump_vflag == FIRST) { |
| - | bb_dump_vflag = WAIT; |
| + | if (dumper->pub.dump_vflag == DUP || dumper->pub.dump_vflag == FIRST) { |
| + | dumper->pub.dump_vflag = WAIT; |
| } |
| - | return curp; |
| + | return dumper->get__curp; |
| } |
| - | if (bb_dump_vflag == WAIT) { |
| + | if (dumper->pub.dump_vflag == WAIT) { |
| puts("*"); |
| } |
| - | bb_dump_vflag = DUP; |
| - | address = savaddress += bb_dump_blocksize; |
| - | need = bb_dump_blocksize; |
| + | dumper->pub.dump_vflag = DUP; |
| + | dumper->savaddress += blocksize; |
| + | dumper->address = dumper->savaddress; |
| + | need = blocksize; |
| nread = 0; |
| } else { |
| nread += n; |
| @@ -515,29 +529,31 @@ static void conv_u(PR *pr, unsigned char *p) |
| } |
| } |
| |
| - | static void display(void) |
| + | static void display(priv_dumper_t* dumper) |
| { |
| - | /* extern FU *endfu; */ |
| FS *fs; |
| FU *fu; |
| PR *pr; |
| int cnt; |
| - | unsigned char *bp; |
| + | unsigned char *bp, *savebp; |
| off_t saveaddress; |
| - | unsigned char savech = 0, *savebp; |
| + | unsigned char savech = '\0'; |
| |
| - | while ((bp = get()) != NULL) { |
| - | for (fs = bb_dump_fshead, savebp = bp, saveaddress = address; fs; |
| - | fs = fs->nextfs, bp = savebp, address = saveaddress) { |
| + | while ((bp = get(dumper)) != NULL) { |
| + | fs = dumper->pub.fshead; |
| + | savebp = bp; |
| + | saveaddress = dumper->address; |
| + | for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) { |
| for (fu = fs->nextfu; fu; fu = fu->nextfu) { |
| if (fu->flags & F_IGNORE) { |
| break; |
| } |
| for (cnt = fu->reps; cnt; --cnt) { |
| - | for (pr = fu->nextpr; pr; address += pr->bcnt, |
| - | bp += pr->bcnt, pr = pr->nextpr) { |
| - | if (eaddress && address >= eaddress && |
| - | !(pr->flags & (F_TEXT | F_BPAD))) { |
| + | 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)) |
| + | ) { |
| bpad(pr); |
| } |
| if (cnt == 1 && pr->nospace) { |
| @@ -547,7 +563,7 @@ static void display(void) |
| /* PRINT; */ |
| switch (pr->flags) { |
| case F_ADDRESS: |
| - | printf(pr->fmt, (unsigned) address); |
| + | printf(pr->fmt, (unsigned) dumper->address); |
| break; |
| case F_BPAD: |
| printf(pr->fmt, ""); |
| @@ -558,7 +574,7 @@ static void display(void) |
| case F_CHAR: |
| printf(pr->fmt, *bp); |
| break; |
| - | case F_DBL:{ |
| + | case F_DBL: { |
| double dval; |
| float fval; |
| |
| @@ -574,7 +590,7 @@ static void display(void) |
| } |
| break; |
| } |
| - | case F_INT:{ |
| + | case F_INT: { |
| int ival; |
| short sval; |
| |
| @@ -605,7 +621,7 @@ static void display(void) |
| case F_U: |
| conv_u(pr, bp); |
| break; |
| - | case F_UINT:{ |
| + | case F_UINT: { |
| unsigned ival; |
| unsigned short sval; |
| |
| @@ -633,21 +649,21 @@ static void display(void) |
| } |
| } |
| } |
| - | if (endfu) { |
| + | if (dumper->endfu) { |
| /* |
| - | * if eaddress not set, error or file bb_dump_size was multiple of |
| - | * bb_dump_blocksize, and no partial block ever found. |
| + | * if eaddress not set, error or file size was multiple |
| + | * of blocksize, and no partial block ever found. |
| */ |
| - | if (!eaddress) { |
| - | if (!address) { |
| + | if (!dumper->eaddress) { |
| + | if (!dumper->address) { |
| return; |
| } |
| - | eaddress = address; |
| + | dumper->eaddress = dumper->address; |
| } |
| - | for (pr = endfu->nextpr; pr; pr = pr->nextpr) { |
| + | for (pr = dumper->endfu->nextpr; pr; pr = pr->nextpr) { |
| switch (pr->flags) { |
| case F_ADDRESS: |
| - | printf(pr->fmt, (unsigned) eaddress); |
| + | printf(pr->fmt, (unsigned) dumper->eaddress); |
| break; |
| case F_TEXT: |
| printf(pr->fmt); |
| @@ -657,52 +673,58 @@ static void display(void) |
| } |
| } |
| |
| - | int FAST_FUNC bb_dump_dump(char **argv) |
| + | #define dumper ((priv_dumper_t*)pub_dumper) |
| + | int FAST_FUNC bb_dump_dump(dumper_t *pub_dumper, char **argv) |
| { |
| FS *tfs; |
| + | int blocksize; |
| |
| /* figure out the data block bb_dump_size */ |
| - | for (bb_dump_blocksize = 0, tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) { |
| + | blocksize = 0; |
| + | tfs = dumper->pub.fshead; |
| + | while (tfs) { |
| tfs->bcnt = bb_dump_size(tfs); |
| - | if (bb_dump_blocksize < tfs->bcnt) { |
| - | bb_dump_blocksize = tfs->bcnt; |
| + | if (blocksize < tfs->bcnt) { |
| + | blocksize = tfs->bcnt; |
| } |
| + | tfs = tfs->nextfs; |
| } |
| + | dumper->blocksize = blocksize; |
| + | |
| /* rewrite the rules, do syntax checking */ |
| - | for (tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) { |
| - | rewrite(tfs); |
| + | for (tfs = dumper->pub.fshead; tfs; tfs = tfs->nextfs) { |
| + | rewrite(dumper, tfs); |
| } |
| |
| - | next(argv); |
| - | display(); |
| + | dumper->argv = argv; |
| + | display(dumper); |
| |
| - | return exitval; |
| + | return dumper->exitval; |
| } |
| |
| - | void FAST_FUNC bb_dump_add(const char *fmt) |
| + | void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) |
| { |
| - | static FS **nextfs; |
| - | |
| const char *p; |
| char *p1; |
| char *p2; |
| FS *tfs; |
| - | FU *tfu, **nextfu; |
| + | FU *tfu, **nextfupp; |
| const char *savep; |
| |
| /* start new linked list of format units */ |
| tfs = xzalloc(sizeof(FS)); /*DBU:[[email protected]] start out NULL */ |
| - | if (!bb_dump_fshead) { |
| - | bb_dump_fshead = tfs; |
| + | if (!dumper->pub.fshead) { |
| + | dumper->pub.fshead = tfs; |
| } else { |
| - | *nextfs = tfs; |
| + | FS *fslast = dumper->pub.fshead; |
| + | while (fslast->nextfs) |
| + | fslast = fslast->nextfs; |
| + | fslast->nextfs = tfs; |
| } |
| - | nextfs = &tfs->nextfs; |
| - | nextfu = &tfs->nextfu; |
| + | nextfupp = &tfs->nextfu; |
| |
| /* take the format string and break it up into format units */ |
| for (p = fmt;;) { |
| - | /* bb_dump_skip leading white space */ |
| p = skip_whitespace(p); |
| if (!*p) { |
| break; |
| @@ -712,8 +734,8 @@ void FAST_FUNC bb_dump_add(const char *fmt) |
| /* NOSTRICT */ |
| /* DBU:[[email protected]] zalloc so that forward pointers start out NULL */ |
| tfu = xzalloc(sizeof(FU)); |
| - | *nextfu = tfu; |
| - | nextfu = &tfu->nextfu; |
| + | *nextfupp = tfu; |
| + | nextfupp = &tfu->nextfu; |
| tfu->reps = 1; |
| |
| /* if leading digit, repetition count */ |
| @@ -726,11 +748,11 @@ void FAST_FUNC bb_dump_add(const char *fmt) |
| /* may overwrite either white space or slash */ |
| tfu->reps = atoi(savep); |
| tfu->flags = F_SETREP; |
| - | /* bb_dump_skip trailing white space */ |
| + | /* skip trailing white space */ |
| p = skip_whitespace(++p); |
| } |
| |
| - | /* bb_dump_skip slash and trailing white space */ |
| + | /* skip slash and trailing white space */ |
| if (*p == '/') { |
| p = skip_whitespace(++p); |
| } |
| @@ -745,7 +767,7 @@ void FAST_FUNC bb_dump_add(const char *fmt) |
| bb_error_msg_and_die("bad format {%s}", fmt); |
| } |
| tfu->bcnt = atoi(savep); |
| - | /* bb_dump_skip trailing white space */ |
| + | /* skip trailing white space */ |
| p = skip_whitespace(++p); |
| } |
| |