diff options
| author | Mark Stapp <mjs@voltanet.io> | 2021-03-31 09:10:30 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-03-31 09:10:30 -0400 |
| commit | e2efe13327adefb655811bdb03bb76b95db2407c (patch) | |
| tree | b9fa898013c23be16c8a50ee477af017ab52220a /lib/printf/vfprintf.c | |
| parent | fb639375cb2ca062f350c56c51367f2d8d5b2514 (diff) | |
| parent | 19b1a1c6a975f772b22dda9c5c42c6288e2ce459 (diff) | |
Merge pull request #8350 from opensourcerouting/printfrr-revamp
lib: `printfrr()` care package
Diffstat (limited to 'lib/printf/vfprintf.c')
| -rw-r--r-- | lib/printf/vfprintf.c | 179 |
1 files changed, 132 insertions, 47 deletions
diff --git a/lib/printf/vfprintf.c b/lib/printf/vfprintf.c index 8c7a8a58c4..49fa2b718f 100644 --- a/lib/printf/vfprintf.c +++ b/lib/printf/vfprintf.c @@ -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 */ @@ -177,6 +177,9 @@ vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap) int nextarg; /* 1-based argument index */ 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"; @@ -268,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; @@ -292,11 +305,16 @@ vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap) flags = 0; dprec = 0; - width = 0; + width = -1; prec = -1; 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 ' ': @@ -438,15 +456,24 @@ reswitch: switch (ch) { ulval = SARG(); if (printfrr_ext_char(fmt[0])) { - n2 = printfrr_exti(buf, sizeof(buf), fmt, prec, + struct printfrr_eargs ea = { + .fmt = fmt, + .precision = prec, + .width = width, + .alt_repr = !!(flags & ALT), + .leftadj = !!(flags & LADJUST), + }; + + if (cb) + extstart = cb->pos; + + size = printfrr_exti(cb, &ea, (flags & INTMAX_SIZE) ? ujval : (uintmax_t)ulval); - if (n2 > 0) { - fmt += n2; - cp = buf; - size = strlen(cp); - sign = '\0'; - break; + if (size >= 0) { + fmt = ea.fmt; + width = ea.width; + goto ext_printed; } } if (flags & INTMAX_SIZE) { @@ -503,35 +530,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*/ @@ -551,14 +549,24 @@ reswitch: switch (ch) { * -- ANSI X3J11 */ ptrval = GETARG(void *); - if (printfrr_ext_char(fmt[0]) && - (n2 = printfrr_extp(buf, sizeof(buf), - fmt, prec, ptrval)) > 0) { - fmt += n2; - cp = buf; - size = strlen(cp); - sign = '\0'; - break; + if (printfrr_ext_char(fmt[0])) { + struct printfrr_eargs ea = { + .fmt = fmt, + .precision = prec, + .width = width, + .alt_repr = !!(flags & ALT), + .leftadj = !!(flags & LADJUST), + }; + + if (cb) + extstart = cb->pos; + + size = printfrr_extp(cb, &ea, ptrval); + if (size >= 0) { + fmt = ea.fmt; + width = ea.width; + goto ext_printed; + } } ujval = (uintmax_t)(uintptr_t)ptrval; base = 16; @@ -662,6 +670,7 @@ number: if ((dprec = prec) >= 0) cp = buf; size = 1; sign = '\0'; + opos = NULL; break; } @@ -679,6 +688,9 @@ number: if ((dprec = prec) >= 0) * Compute actual size, so we know how much to pad. * size excludes decimal prec; realsz includes it. */ + if (width < 0) + width = 0; + realsz = dprec > size ? dprec : size; if (sign) realsz++; @@ -686,7 +698,7 @@ number: if ((dprec = prec) >= 0) realsz += 2; prsize = width > realsz ? width : realsz; - if ((unsigned)ret + prsize > INT_MAX) { + if ((unsigned int)ret + prsize > INT_MAX) { ret = EOF; errno = EOVERFLOW; goto error; @@ -696,6 +708,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); @@ -713,6 +728,74 @@ 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); + + /* finally, adjust ret */ + ret += prsize; + + FLUSH(); /* copy out the I/O vectors */ + continue; + +ext_printed: + /* when we arrive here, a printfrr extension has written to cb + * (if non-NULL), but we still need to handle padding. The + * original cb->pos is in extstart; the return value from the + * ext is in size. + * + * Keep analogous to code above please. + */ + + if (width < 0) + width = 0; + + realsz = size; + prsize = width > realsz ? width : realsz; + if ((unsigned int)ret + prsize > INT_MAX) { + ret = EOF; + errno = EOVERFLOW; + goto error; + } + + /* right-adjusting blank padding - need to move the chars + * that the extension has already written. Should be very + * rare. + */ + if (cb && width > size && (flags & (LADJUST|ZEROPAD)) == 0) { + size_t nwritten = cb->pos - extstart; + size_t navail = cb->buf + cb->len - extstart; + size_t npad = width - realsz; + size_t nmove; + + if (navail < npad) + navail = 0; + else + navail -= npad; + nmove = MIN(nwritten, navail); + + memmove(extstart + npad, extstart, nmove); + + 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); @@ -730,6 +813,8 @@ error: free(convbuf); if ((argtable != NULL) && (argtable != statargtable)) free (argtable); + if (cb_in) + cb_in->pos = cb->pos; return (ret); /* NOTREACHED */ } |
