From 212e04e5a7f682594dab26cd8354bc4fa040b61f Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 18 Feb 2021 22:52:23 +0100 Subject: lib: rework printfrr extensions to output directly Allowing printfrr extensions to directly write to the output buffer has a few advantages: - there is no arbitrary length limit imposed (previously 64) - the output doesn't need to be copied another time - the extension can directly use bprintfrr() to put together pieces The downside is that the theoretical length (regardless of available buffer space) must be computed correctly. Extended unit tests to test these paths a bit more thoroughly. Signed-off-by: David Lamparter --- lib/printf/vfprintf.c | 84 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 17 deletions(-) (limited to 'lib/printf/vfprintf.c') diff --git a/lib/printf/vfprintf.c b/lib/printf/vfprintf.c index a0634cde4b..3b5bda965a 100644 --- a/lib/printf/vfprintf.c +++ b/lib/printf/vfprintf.c @@ -177,6 +177,7 @@ 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 */ static const char xdigs_lower[16] = "0123456789abcdef"; static const char xdigs_upper[16] = "0123456789ABCDEF"; @@ -438,16 +439,14 @@ reswitch: switch (ch) { ulval = SARG(); if (printfrr_ext_char(fmt[0])) { - n2 = printfrr_exti(buf, sizeof(buf), fmt, prec, + if (cb) + extstart = cb->pos; + + size = printfrr_exti(cb, &fmt, prec, (flags & INTMAX_SIZE) ? ujval : (uintmax_t)ulval); - if (n2 > 0) { - fmt += n2; - cp = buf; - size = strlen(cp); - sign = '\0'; - break; - } + if (size >= 0) + goto ext_printed; } if (flags & INTMAX_SIZE) { if ((intmax_t)ujval < 0) { @@ -551,14 +550,13 @@ 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])) { + if (cb) + extstart = cb->pos; + + size = printfrr_extp(cb, &fmt, prec, ptrval); + if (size >= 0) + goto ext_printed; } ujval = (uintmax_t)(uintptr_t)ptrval; base = 16; @@ -686,7 +684,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; @@ -720,6 +718,58 @@ number: if ((dprec = prec) >= 0) /* 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. + */ + + 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; + } + + io.avail = cb ? cb->len - (cb->pos - cb->buf) : 0; + + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + PAD(width - realsz, blanks); + + /* finally, adjust ret */ + ret += prsize; + FLUSH(); /* copy out the I/O vectors */ } done: -- cgit v1.2.3 From 487eefcfbec8a24d639e6b8c805540d5c1fe38e8 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 2 Mar 2021 20:16:18 +0100 Subject: lib: record output positions in printfrr 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 --- lib/printf/vfprintf.c | 67 ++++++++++++++++++++++++++--------------------- lib/printfrr.h | 7 +++++ tests/lib/test_printfrr.c | 22 ++++++++++++++-- 3 files changed, 64 insertions(+), 32 deletions(-) (limited to 'lib/printf/vfprintf.c') diff --git a/lib/printf/vfprintf.c b/lib/printf/vfprintf.c index 3b5bda965a..96675e3620 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 */ @@ -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 */ } diff --git a/lib/printfrr.h b/lib/printfrr.h index 549334ba5b..49243248d6 100644 --- a/lib/printfrr.h +++ b/lib/printfrr.h @@ -28,10 +28,17 @@ 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) diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c index 9ffea8b978..6d64615faf 100644 --- a/tests/lib/test_printfrr.c +++ b/tests/lib/test_printfrr.c @@ -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) -- cgit v1.2.3 From 3ea794305960ed9fca230c3e0f8b1b73c2915101 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 20 Mar 2021 09:02:04 +0100 Subject: lib: put printfrr extension args into struct ... for easier extensibility. Add width, # and - flags while at it. Signed-off-by: David Lamparter --- bgpd/bgp_table.c | 4 ++-- lib/nexthop.c | 14 ++++++------ lib/prefix.c | 24 ++++++++++---------- lib/printf/glue.c | 16 ++++++------- lib/printf/printflocal.h | 5 +++-- lib/printf/vfprintf.c | 30 +++++++++++++++++++++---- lib/printfrr.h | 58 +++++++++++++++++++++++++++++++++++++++++------- lib/sockunion.c | 8 +++---- lib/srcdest_table.c | 4 ++-- 9 files changed, 114 insertions(+), 49 deletions(-) (limited to 'lib/printf/vfprintf.c') diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index d6dd03e2ac..833bdec2ed 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -201,8 +201,8 @@ struct bgp_node *bgp_table_subtree_lookup(const struct bgp_table *table, } printfrr_ext_autoreg_p("BD", printfrr_bd) -static ssize_t printfrr_bd(struct fbuf *buf, const char **fmt, - int prec, const void *ptr) +static ssize_t printfrr_bd(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const struct bgp_dest *dest = ptr; const struct prefix *p = bgp_dest_get_prefix(dest); diff --git a/lib/nexthop.c b/lib/nexthop.c index 443df99445..8439398149 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -730,22 +730,22 @@ int nexthop_str2backups(const char *str, int *num_backups, * nexthop2str() */ printfrr_ext_autoreg_p("NH", printfrr_nh) -static ssize_t printfrr_nh(struct fbuf *buf, const char **fmt, - int prec, const void *ptr) +static ssize_t printfrr_nh(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const struct nexthop *nexthop = ptr; bool do_ifi = false; const char *v_is = "", *v_via = "", *v_viaif = "via "; ssize_t ret = 0; - switch (**fmt) { + switch (*ea->fmt) { case 'v': - (*fmt)++; - if (**fmt == 'v') { + ea->fmt++; + if (*ea->fmt == 'v') { v_is = "is "; v_via = "via "; v_viaif = ""; - (*fmt)++; + ea->fmt++; } if (!nexthop) @@ -796,7 +796,7 @@ static ssize_t printfrr_nh(struct fbuf *buf, const char **fmt, return ret; case 's': - (*fmt)++; + ea->fmt++; if (!nexthop) return bputs(buf, "(null)"); diff --git a/lib/prefix.c b/lib/prefix.c index fba26a5b63..141d564606 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1361,8 +1361,8 @@ char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len) } printfrr_ext_autoreg_p("EA", printfrr_ea) -static ssize_t printfrr_ea(struct fbuf *buf, const char **fmt, - int prec, const void *ptr) +static ssize_t printfrr_ea(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const struct ethaddr *mac = ptr; char cbuf[ETHER_ADDR_STRLEN]; @@ -1376,8 +1376,8 @@ static ssize_t printfrr_ea(struct fbuf *buf, const char **fmt, } printfrr_ext_autoreg_p("IA", printfrr_ia) -static ssize_t printfrr_ia(struct fbuf *buf, const char **fmt, - int prec, const void *ptr) +static ssize_t printfrr_ia(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const struct ipaddr *ipa = ptr; char cbuf[INET6_ADDRSTRLEN]; @@ -1390,8 +1390,8 @@ static ssize_t printfrr_ia(struct fbuf *buf, const char **fmt, } printfrr_ext_autoreg_p("I4", printfrr_i4) -static ssize_t printfrr_i4(struct fbuf *buf, const char **fmt, - int prec, const void *ptr) +static ssize_t printfrr_i4(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { char cbuf[INET_ADDRSTRLEN]; @@ -1403,8 +1403,8 @@ static ssize_t printfrr_i4(struct fbuf *buf, const char **fmt, } printfrr_ext_autoreg_p("I6", printfrr_i6) -static ssize_t printfrr_i6(struct fbuf *buf, const char **fmt, - int prec, const void *ptr) +static ssize_t printfrr_i6(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { char cbuf[INET6_ADDRSTRLEN]; @@ -1416,8 +1416,8 @@ static ssize_t printfrr_i6(struct fbuf *buf, const char **fmt, } printfrr_ext_autoreg_p("FX", printfrr_pfx) -static ssize_t printfrr_pfx(struct fbuf *buf, const char **fmt, - int prec, const void *ptr) +static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { char cbuf[PREFIX_STRLEN]; @@ -1429,8 +1429,8 @@ static ssize_t printfrr_pfx(struct fbuf *buf, const char **fmt, } printfrr_ext_autoreg_p("SG4", printfrr_psg) -static ssize_t printfrr_psg(struct fbuf *buf, const char **fmt, - int prec, const void *ptr) +static ssize_t printfrr_psg(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const struct prefix_sg *sg = ptr; ssize_t ret = 0; diff --git a/lib/printf/glue.c b/lib/printf/glue.c index 477fc0d384..389f503c33 100644 --- a/lib/printf/glue.c +++ b/lib/printf/glue.c @@ -210,10 +210,10 @@ void printfrr_ext_reg(const struct printfrr_ext *ext) exts[i] = ext; } -ssize_t printfrr_extp(struct fbuf *buf, const char **fmtp, int prec, +ssize_t printfrr_extp(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { - const char *fmt = *fmtp; + const char *fmt = ea->fmt; const struct printfrr_ext *ext; size_t i; @@ -227,16 +227,16 @@ ssize_t printfrr_extp(struct fbuf *buf, const char **fmtp, int prec, continue; if (strncmp(ext->match, fmt, strlen(ext->match))) continue; - *fmtp += strlen(ext->match); - return ext->print_ptr(buf, fmtp, prec, ptr); + ea->fmt += strlen(ext->match); + return ext->print_ptr(buf, ea, ptr); } return -1; } -ssize_t printfrr_exti(struct fbuf *buf, const char **fmtp, int prec, +ssize_t printfrr_exti(struct fbuf *buf, struct printfrr_eargs *ea, uintmax_t num) { - const char *fmt = *fmtp; + const char *fmt = ea->fmt; const struct printfrr_ext *ext; size_t i; @@ -250,8 +250,8 @@ ssize_t printfrr_exti(struct fbuf *buf, const char **fmtp, int prec, continue; if (strncmp(ext->match, fmt, strlen(ext->match))) continue; - *fmtp += strlen(ext->match); - return ext->print_int(buf, fmtp, prec, num); + ea->fmt += strlen(ext->match); + return ext->print_int(buf, ea, num); } return -1; } diff --git a/lib/printf/printflocal.h b/lib/printf/printflocal.h index df962fc043..bac80e801c 100644 --- a/lib/printf/printflocal.h +++ b/lib/printf/printflocal.h @@ -101,6 +101,7 @@ int _frr_find_warguments(const wchar_t *, va_list, union arg **) DSO_LOCAL; #endif /* returns number of bytes needed for full output, or -1 */ -ssize_t printfrr_extp(struct fbuf *, const char **, int, const void *) +ssize_t printfrr_extp(struct fbuf *, struct printfrr_eargs *ea, const void *) + DSO_LOCAL; +ssize_t printfrr_exti(struct fbuf *, struct printfrr_eargs *ea, uintmax_t) DSO_LOCAL; -ssize_t printfrr_exti(struct fbuf *, const char **, int, uintmax_t) DSO_LOCAL; diff --git a/lib/printf/vfprintf.c b/lib/printf/vfprintf.c index 96675e3620..7fafa89aa7 100644 --- a/lib/printf/vfprintf.c +++ b/lib/printf/vfprintf.c @@ -456,14 +456,25 @@ reswitch: switch (ch) { ulval = SARG(); 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_exti(cb, &fmt, prec, + size = printfrr_exti(cb, &ea, (flags & INTMAX_SIZE) ? ujval : (uintmax_t)ulval); - if (size >= 0) + if (size >= 0) { + fmt = ea.fmt; + width = ea.width; goto ext_printed; + } } if (flags & INTMAX_SIZE) { if ((intmax_t)ujval < 0) { @@ -539,12 +550,23 @@ reswitch: switch (ch) { */ ptrval = GETARG(void *); 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, &fmt, prec, ptrval); - if (size >= 0) + 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; diff --git a/lib/printfrr.h b/lib/printfrr.h index 49243248d6..754cb09598 100644 --- a/lib/printfrr.h +++ b/lib/printfrr.h @@ -112,6 +112,8 @@ char *asnprintfrr(struct memtype *mt, char *out, size_t sz, */ #define printfrr_ext_char(ch) ((ch) >= 'A' && (ch) <= 'Z') +struct printfrr_eargs; + struct printfrr_ext { /* embedded string to minimize cache line pollution */ char match[8]; @@ -127,14 +129,53 @@ struct printfrr_ext { * to consume extra input flags after %pXY, increment *fmt. It points * at the first character after %pXY at entry. Convention is to make * those flags lowercase letters or numbers. + */ + ssize_t (*print_ptr)(struct fbuf *buf, struct printfrr_eargs *info, + const void *); + ssize_t (*print_int)(struct fbuf *buf, struct printfrr_eargs *info, + uintmax_t); +}; + +/* additional information passed to extended formatters */ + +struct printfrr_eargs { + /* position in the format string. Points to directly after the + * extension specifier. Increment when consuming extra "flag + * characters". + */ + const char *fmt; + + /* %.1234x / %.*x + * not POSIX compatible when used with %p, will cause warnings from + * GCC & clang. Usable with %d. Not used by the printfrr() itself + * for extension specifiers, so essentially available as a "free" + * parameter. -1 if not specified. Value in the format string + * cannot be negative, but negative values can be passed with %.*x + */ + int precision; + + /* %1234x / %*x + * regular width specification. Internally handled by printfrr(), set + * to 0 if consumed by the extension in order to suppress standard + * width/padding behavior. 0 if not specified. * - * prec is the precision specifier (the 999 in "%.999p") -1 means - * none given (value in the format string cannot be negative) + * NB: always positive, even if a negative value is passed in with + * %*x. (The sign is used for the - flag.) + */ + int width; + + /* %#x + * "alternate representation" flag, not POSIX compatible when used + * with %p or %d, will cause warnings from GCC & clang. Not used by + * printfrr() itself for extension specifiers. + */ + bool alt_repr; + + /* %-x + * left-pad flag. Internally handled by printfrr() if width is + * nonzero. Only use if the extension sets width to 0. */ - ssize_t (*print_ptr)(struct fbuf *buf, const char **fmt, int prec, - const void *); - ssize_t (*print_int)(struct fbuf *buf, const char **fmt, int prec, - uintmax_t); + bool leftadj; }; /* no locking - must be called when single threaded (e.g. at startup.) @@ -144,7 +185,7 @@ struct printfrr_ext { void printfrr_ext_reg(const struct printfrr_ext *); #define printfrr_ext_autoreg_p(matchs, print_fn) \ - static ssize_t print_fn(struct fbuf *, const char **, int, \ + static ssize_t print_fn(struct fbuf *, struct printfrr_eargs *, \ const void *); \ static const struct printfrr_ext _printext_##print_fn = { \ .match = matchs, \ @@ -157,7 +198,8 @@ void printfrr_ext_reg(const struct printfrr_ext *); /* end */ #define printfrr_ext_autoreg_i(matchs, print_fn) \ - static ssize_t print_fn(struct fbuf *, const char **, int, uintmax_t); \ + static ssize_t print_fn(struct fbuf *, struct printfrr_eargs *, \ + uintmax_t); \ static const struct printfrr_ext _printext_##print_fn = { \ .match = matchs, \ .print_int = print_fn, \ diff --git a/lib/sockunion.c b/lib/sockunion.c index ecbb0fcf91..2175ac3360 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -664,8 +664,8 @@ void sockunion_init(union sockunion *su) } printfrr_ext_autoreg_p("SU", printfrr_psu) -static ssize_t printfrr_psu(struct fbuf *buf, const char **fmt, - int prec, const void *ptr) +static ssize_t printfrr_psu(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const union sockunion *su = ptr; bool include_port = false; @@ -677,9 +677,9 @@ static ssize_t printfrr_psu(struct fbuf *buf, const char **fmt, return bputs(buf, "(null)"); while (!endflags) { - switch (**fmt) { + switch (*ea->fmt) { case 'p': - (*fmt)++; + ea->fmt++; include_port = true; break; default: diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c index b2422ba460..d2e0682e95 100644 --- a/lib/srcdest_table.c +++ b/lib/srcdest_table.c @@ -307,8 +307,8 @@ const char *srcdest_rnode2str(const struct route_node *rn, char *str, int size) } printfrr_ext_autoreg_p("RN", printfrr_rn) -static ssize_t printfrr_rn(struct fbuf *buf, const char **fmt, - int prec, const void *ptr) +static ssize_t printfrr_rn(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const struct route_node *rn = ptr; const struct prefix *dst_p, *src_p; -- cgit v1.2.3 From 2d9a4e2931e4f20c6bc49b09956a1e350664e3f2 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 26 Mar 2021 17:58:54 +0100 Subject: lib: allow discerning unspec width in printfrr ext With 0 currently the default value for the width specifier, it's not possible to discern that from a %*p where 0 was passed as the length parameter. Use -1 to allow for that. Signed-off-by: David Lamparter --- lib/printf/vfprintf.c | 8 +++++++- lib/printfrr.h | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'lib/printf/vfprintf.c') diff --git a/lib/printf/vfprintf.c b/lib/printf/vfprintf.c index 7fafa89aa7..1bd24743ee 100644 --- a/lib/printf/vfprintf.c +++ b/lib/printf/vfprintf.c @@ -305,7 +305,7 @@ vbprintfrr(struct fbuf *cb_in, const char *fmt0, va_list ap) flags = 0; dprec = 0; - width = 0; + width = -1; prec = -1; sign = '\0'; ox[1] = '\0'; @@ -688,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++; @@ -750,6 +753,9 @@ ext_printed: * 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) { diff --git a/lib/printfrr.h b/lib/printfrr.h index 754cb09598..9dd20f0a8f 100644 --- a/lib/printfrr.h +++ b/lib/printfrr.h @@ -178,6 +178,23 @@ struct printfrr_eargs { bool leftadj; }; +/* for any extension that needs a buffer length */ + +static inline ssize_t printfrr_ext_len(struct printfrr_eargs *ea) +{ + ssize_t rv; + + if (ea->precision >= 0) + rv = ea->precision; + else if (ea->width >= 0) { + rv = ea->width; + ea->width = -1; + } else + rv = -1; + + return rv; +} + /* no locking - must be called when single threaded (e.g. at startup.) * this restriction hopefully won't be a huge bother considering normal usage * scenarios... -- cgit v1.2.3