... for easier extensibility. Add width, # and - flags while at it.
Signed-off-by: David Lamparter <equinox@diac24.net>
}
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);
* 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)
return ret;
case 's':
- (*fmt)++;
+ ea->fmt++;
if (!nexthop)
return bputs(buf, "(null)");
}
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];
}
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];
}
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];
}
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];
}
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];
}
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;
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;
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;
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;
}
#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;
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) {
*/
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;
*/
#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];
* 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.)
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, \
/* 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, \
}
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;
return bputs(buf, "(null)");
while (!endflags) {
- switch (**fmt) {
+ switch (*ea->fmt) {
case 'p':
- (*fmt)++;
+ ea->fmt++;
include_port = true;
break;
default:
}
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;