]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: record output positions in printfrr
authorDavid Lamparter <equinox@diac24.net>
Tue, 2 Mar 2021 19:16:18 +0000 (20:16 +0100)
committerDavid Lamparter <equinox@diac24.net>
Sat, 27 Mar 2021 16:01:29 +0000 (17:01 +0100)
This replaces `%n` with a safe, out-of-band option that simply records
the start and end offset of the output produced for each `%...`
specifier.

The old `%n` code is removed.

Signed-off-by: David Lamparter <equinox@diac24.net>
lib/printf/vfprintf.c
lib/printfrr.h
tests/lib/test_printfrr.c

index 3b5bda965a1baf8bafda92c9268feafb034f65a2..96675e3620dfaecfd52486b33e53e618b52ee820 100644 (file)
@@ -147,7 +147,7 @@ __wcsconv(wchar_t *wcsarg, int prec)
  * Non-MT-safe version
  */
 ssize_t
-vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap)
+vbprintfrr(struct fbuf *cb_in, const char *fmt0, va_list ap)
 {
        const char *fmt;        /* format string */
        int ch;                 /* character from fmt */
@@ -178,6 +178,8 @@ vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap)
        va_list orgap;          /* original argument pointer */
        char *convbuf;          /* wide to multibyte conversion result */
        char *extstart = NULL;  /* where printfrr_ext* started printing */
+       struct fbuf cb_copy, *cb;
+       struct fmt_outpos *opos;
 
        static const char xdigs_lower[16] = "0123456789abcdef";
        static const char xdigs_upper[16] = "0123456789ABCDEF";
@@ -269,6 +271,16 @@ vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap)
        argtable = NULL;
        nextarg = 1;
        va_copy(orgap, ap);
+
+       if (cb_in) {
+               /* prevent printfrr exts from polluting cb->outpos */
+               cb_copy = *cb_in;
+               cb_copy.outpos = NULL;
+               cb_copy.outpos_n = cb_copy.outpos_i = 0;
+               cb = &cb_copy;
+       } else
+               cb = NULL;
+
        io_init(&io, cb);
        ret = 0;
 
@@ -298,6 +310,11 @@ vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap)
                sign = '\0';
                ox[1] = '\0';
 
+               if (cb_in && cb_in->outpos_i < cb_in->outpos_n)
+                       opos = &cb_in->outpos[cb_in->outpos_i];
+               else
+                       opos = NULL;
+
 rflag:         ch = *fmt++;
 reswitch:      switch (ch) {
                case ' ':
@@ -502,35 +519,6 @@ reswitch:  switch (ch) {
                        size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
                        sign = '\0';
                        break;
-#ifdef DANGEROUS_PERCENT_N
-               /* FRR does not use %n in printf formats.  This is just left
-                * here in case someone tries to use %n and starts debugging
-                * why the f* it doesn't work
-                */
-               case 'n':
-                       /*
-                        * Assignment-like behavior is specified if the
-                        * value overflows or is otherwise unrepresentable.
-                        * C99 says to use `signed char' for %hhn conversions.
-                        */
-                       if (flags & LLONGINT)
-                               *GETARG(long long *) = ret;
-                       else if (flags & SIZET)
-                               *GETARG(ssize_t *) = (ssize_t)ret;
-                       else if (flags & PTRDIFFT)
-                               *GETARG(ptrdiff_t *) = ret;
-                       else if (flags & INTMAXT)
-                               *GETARG(intmax_t *) = ret;
-                       else if (flags & LONGINT)
-                               *GETARG(long *) = ret;
-                       else if (flags & SHORTINT)
-                               *GETARG(short *) = ret;
-                       else if (flags & CHARINT)
-                               *GETARG(signed char *) = ret;
-                       else
-                               *GETARG(int *) = ret;
-                       continue;       /* no output */
-#endif
                case 'O':
                        flags |= LONGINT;
                        /*FALLTHROUGH*/
@@ -660,6 +648,7 @@ number:                     if ((dprec = prec) >= 0)
                        cp = buf;
                        size = 1;
                        sign = '\0';
+                       opos = NULL;
                        break;
                }
 
@@ -694,6 +683,9 @@ number:                     if ((dprec = prec) >= 0)
                if ((flags & (LADJUST|ZEROPAD)) == 0)
                        PAD(width - realsz, blanks);
 
+               if (opos)
+                       opos->off_start = cb->pos - cb->buf;
+
                /* prefix */
                if (sign)
                        PRINT(&sign, 1);
@@ -711,6 +703,12 @@ number:                    if ((dprec = prec) >= 0)
                /* leading zeroes from decimal precision */
                PAD(dprec - size, zeroes);
                PRINT(cp, size);
+
+               if (opos) {
+                       opos->off_end = cb->pos - cb->buf;
+                       cb_in->outpos_i++;
+               }
+
                /* left-adjusting padding (always blank) */
                if (flags & LADJUST)
                        PAD(width - realsz, blanks);
@@ -759,10 +757,17 @@ ext_printed:
                        cb->pos = extstart;
                        PAD(npad, blanks);
                        cb->pos += nmove;
+                       extstart += npad;
                }
 
                io.avail = cb ? cb->len - (cb->pos - cb->buf) : 0;
 
+               if (opos && extstart <= cb->pos) {
+                       opos->off_start = extstart - cb->buf;
+                       opos->off_end = cb->pos - cb->buf;
+                       cb_in->outpos_i++;
+               }
+
                /* left-adjusting padding (always blank) */
                if (flags & LADJUST)
                        PAD(width - realsz, blanks);
@@ -780,6 +785,8 @@ error:
                free(convbuf);
        if ((argtable != NULL) && (argtable != statargtable))
                free (argtable);
+       if (cb_in)
+               cb_in->pos = cb->pos;
        return (ret);
        /* NOTREACHED */
 }
index 549334ba5ba444e23ed51f453885e7a4be1d1527..49243248d6926519699842f494f3ebe483ac7113 100644 (file)
 extern "C" {
 #endif
 
+struct fmt_outpos {
+       unsigned int off_start, off_end;
+};
+
 struct fbuf {
        char *buf;
        char *pos;
        size_t len;
+
+       struct fmt_outpos *outpos;
+       size_t outpos_n, outpos_i;
 };
 
 #define at(a, b) PRINTFRR(a, b)
index 9ffea8b9782d8acf8a1797b7b9d26ee58f8e97ba..6d64615fafb54a45efc34fc8e511dd18c0ef75cd 100644 (file)
@@ -95,11 +95,21 @@ static void printchk(const char *ref, const char *fmt, ...)
                errors++;
        }
 
+       struct fmt_outpos outpos[16];
+       struct fbuf fb = {
+               .buf = bufrr,
+               .pos = bufrr,
+               .len = sizeof(bufrr) - 1,
+               .outpos = outpos,
+               .outpos_n = array_size(outpos),
+       };
+
        va_start(ap, fmt);
-       vsnprintfrr(bufrr, sizeof(bufrr), fmt, ap);
+       vbprintfrr(&fb, fmt, ap);
+       fb.pos[0] = '\0';
        va_end(ap);
 
-       printf("fmt: \"%s\"\nref: \"%s\"\nfrr: \"%s\"\n%s\n\n",
+       printf("fmt: \"%s\"\nref: \"%s\"\nfrr: \"%s\"\n%s\n",
               fmt, ref, bufrr, strcmp(ref, bufrr) ? "ERROR" : "ok");
        if (strcmp(ref, bufrr))
                errors++;
@@ -107,6 +117,14 @@ static void printchk(const char *ref, const char *fmt, ...)
                printf("return value <> length mismatch\n");
                errors++;
        }
+
+       for (size_t i = 0; i < fb.outpos_i; i++)
+               printf("\t[%zu: %u..%u] = \"%.*s\"\n", i,
+                       outpos[i].off_start,
+                       outpos[i].off_end,
+                       (int)(outpos[i].off_end - outpos[i].off_start),
+                       bufrr + outpos[i].off_start);
+       printf("\n");
 }
 
 int main(int argc, char **argv)