- don't free user-supplied string (via -e)
[oweals/busybox.git] / libbb / dump.c
index 29c2c85eea7d0eafaaa09ebbc7b54d683c36f742..74c5e1691753f965a7d543d4f029020aa812a44d 100644 (file)
 #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,121 @@ 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:[dave@cray.com]initialize curp */
-
        int n;
        int need, nread;
-       unsigned char *tmpp;
+       int blocksize = dumper->blocksize;
 
-       if (!curp) {
-               address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
-               curp = xmalloc(bb_dump_blocksize);
-               savp = xmalloc(bb_dump_blocksize);
+       if (!dumper->get__curp) {
+               dumper->address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
+               dumper->get__curp = xmalloc(blocksize);
+               dumper->get__savp = xzalloc(blocksize); /* need to be initialized */
        } else {
-               tmpp = curp;
-               curp = savp;
-               savp = tmpp;
-               address = savaddress += bb_dump_blocksize;
+               unsigned char *tmp = dumper->get__curp;
+               dumper->get__curp = dumper->get__savp;
+               dumper->get__savp = tmp;
+               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 +528,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 +562,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 +573,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 +589,7 @@ static void display(void)
                                                        }
                                                        break;
                                                }
-                                               case F_INT:{
+                                               case F_INT: {
                                                        int ival;
                                                        short sval;
 
@@ -605,7 +620,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 +648,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 +672,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:[dave@cray.com] 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 +733,8 @@ void FAST_FUNC bb_dump_add(const char *fmt)
                /* NOSTRICT */
                /* DBU:[dave@cray.com] 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 +747,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 +766,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);
                }