back to topotato report
topotato coverage report
Current view: top level - lib - printfrr.h (source / functions) Hit Total Coverage
Test: test_mld_basic.py::MLDBasic Lines: 12 28 42.9 %
Date: 2023-02-24 18:38:01 Functions: 1 2 50.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2019  David Lamparter, for NetDEF, Inc.
       3             :  *
       4             :  * Permission to use, copy, modify, and distribute this software for any
       5             :  * purpose with or without fee is hereby granted, provided that the above
       6             :  * copyright notice and this permission notice appear in all copies.
       7             :  *
       8             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
       9             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      10             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      11             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      12             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      13             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      14             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      15             :  */
      16             : 
      17             : #ifndef _FRR_PRINTFRR_H
      18             : #define _FRR_PRINTFRR_H
      19             : 
      20             : #include <stddef.h>
      21             : #include <stdarg.h>
      22             : #include <stdint.h>
      23             : 
      24             : #include "compiler.h"
      25             : #include "memory.h"
      26             : 
      27             : #ifdef __cplusplus
      28             : extern "C" {
      29             : #endif
      30             : 
      31             : struct fmt_outpos {
      32             :         unsigned int off_start, off_end;
      33             : };
      34             : 
      35             : struct fbuf {
      36             :         char *buf;
      37             :         char *pos;
      38             :         size_t len;
      39             : 
      40             :         struct fmt_outpos *outpos;
      41             :         size_t outpos_n, outpos_i;
      42             : };
      43             : 
      44             : #define at(a, b) PRINTFRR(a, b)
      45             : #define atn(a, b) \
      46             :         at(a, b) __attribute__((nonnull(1) _RET_NONNULL))
      47             : #define atm(a, b) \
      48             :         atn(a, b) __attribute__((malloc))
      49             : 
      50             : /* return value is length needed for the full string (excluding \0) in all
      51             :  * cases.  The functions write as much as they can, but continue regardless,
      52             :  * so the return value is independent of buffer length.  Both bprintfrr and
      53             :  * snprintf also accept NULL as output buffer.
      54             :  */
      55             : 
      56             : /* bprintfrr does NOT null terminate! use sparingly (only provided since it's
      57             :  * the most direct interface) - useful for incrementally building long text
      58             :  * (call bprintfrr repeatedly with the same buffer)
      59             :  */
      60             : ssize_t vbprintfrr(struct fbuf *out, const char *fmt, va_list) at(2, 0);
      61             : ssize_t  bprintfrr(struct fbuf *out, const char *fmt, ...)     at(2, 3);
      62             : 
      63             : /* these do null terminate like their snprintf cousins */
      64             : ssize_t vsnprintfrr(char *out, size_t sz, const char *fmt, va_list) at(3, 0);
      65             : ssize_t  snprintfrr(char *out, size_t sz, const char *fmt, ...)     at(3, 4);
      66             : 
      67             : /* c = continue / concatenate (append at the end of the string)
      68             :  * return value is would-be string length (regardless of buffer length),
      69             :  * i.e. includes already written chars */
      70             : ssize_t vcsnprintfrr(char *out, size_t sz, const char *fmt, va_list) at(3, 0);
      71             : ssize_t  csnprintfrr(char *out, size_t sz, const char *fmt, ...)     at(3, 4);
      72             : 
      73             : /* memory allocations don't fail in FRR, so you always get something here.
      74             :  * (in case of error, returns a strdup of the format string) */
      75             : char *vasprintfrr(struct memtype *mt, const char *fmt, va_list) atm(2, 0);
      76             : char  *asprintfrr(struct memtype *mt, const char *fmt, ...)     atm(2, 3);
      77             : 
      78             : /* try to use provided buffer (presumably from stack), allocate if it's too
      79             :  * short.  Must call XFREE(mt, return value) if return value != out.
      80             :  */
      81             : char *vasnprintfrr(struct memtype *mt, char *out, size_t sz,
      82             :                    const char *fmt, va_list) atn(4, 0);
      83             : char  *asnprintfrr(struct memtype *mt, char *out, size_t sz,
      84             :                    const char *fmt, ...)     atn(4, 5);
      85             : 
      86             : #define printfrr(fmt, ...)                                                     \
      87             :         do {                                                                   \
      88             :                 char buf[256], *out;                                           \
      89             :                 out = asnprintfrr(MTYPE_TMP, buf, sizeof(buf), fmt,            \
      90             :                                   ##__VA_ARGS__);                              \
      91             :                 fputs(out, stdout);                                            \
      92             :                 if (out != buf)                                                \
      93             :                         XFREE(MTYPE_TMP, out);                                 \
      94             :         } while (0)
      95             : 
      96             : #undef at
      97             : #undef atm
      98             : #undef atn
      99             : 
     100             : /* extension specs must start with a capital letter (this is a restriction
     101             :  * for both performance's and human understanding's sake.)
     102             :  *
     103             :  * Note that the entire thing mostly works because a letter directly following
     104             :  * a %p print specifier is extremely unlikely to occur (why would you want to
     105             :  * print "0x12345678HELLO"?)  Normally, you'd expect spacing or punctuation
     106             :  * after a placeholder.  That also means that neither of those works well for
     107             :  * extension purposes, e.g. "%p{foo}" is reasonable to see actually used.
     108             :  *
     109             :  * TODO: would be nice to support a "%pF%dF" specifier that consumes 2
     110             :  * arguments, e.g. to pass an integer + a list of known values...  can be
     111             :  * done, but a bit tricky.
     112             :  */
     113             : #define printfrr_ext_char(ch) ((ch) >= 'A' && (ch) <= 'Z')
     114             : 
     115             : struct printfrr_eargs;
     116             : 
     117             : struct printfrr_ext {
     118             :         /* embedded string to minimize cache line pollution */
     119             :         char match[8];
     120             : 
     121             :         /* both can be given, if not the code continues searching
     122             :          * (you can do %pX and %dX in 2 different entries)
     123             :          *
     124             :          * return value: number of bytes that would be printed if the buffer
     125             :          * was large enough.  be careful about not under-reporting this;
     126             :          * otherwise asnprintf() & co. will get broken.  Returning -1 means
     127             :          * something went wrong & default %p/%d handling should be executed.
     128             :          *
     129             :          * to consume extra input flags after %pXY, increment *fmt.  It points
     130             :          * at the first character after %pXY at entry.  Convention is to make
     131             :          * those flags lowercase letters or numbers.
     132             :          */
     133             :         ssize_t (*print_ptr)(struct fbuf *buf, struct printfrr_eargs *info,
     134             :                              const void *);
     135             :         ssize_t (*print_int)(struct fbuf *buf, struct printfrr_eargs *info,
     136             :                              uintmax_t);
     137             : };
     138             : 
     139             : /* additional information passed to extended formatters */
     140             : 
     141             : struct printfrr_eargs {
     142             :         /* position in the format string.  Points to directly after the
     143             :          * extension specifier.  Increment when consuming extra "flag
     144             :          * characters".
     145             :          */
     146             :         const char *fmt;
     147             : 
     148             :         /* %.1234x / %.*x
     149             :          * not POSIX compatible when used with %p, will cause warnings from
     150             :          * GCC & clang.  Usable with %d.  Not used by the printfrr() itself
     151             :          * for extension specifiers, so essentially available as a "free"
     152             :          * parameter.  -1 if not specified.  Value in the format string
     153             :          * cannot be negative, but negative values can be passed with %.*x
     154             :          */
     155             :         int precision;
     156             : 
     157             :         /* %1234x / %*x
     158             :          * regular width specification.  Internally handled by printfrr(), set
     159             :          * to 0 if consumed by the extension in order to suppress standard
     160             :          * width/padding behavior.  0 if not specified.
     161             :          *
     162             :          * NB: always positive, even if a negative value is passed in with
     163             :          * %*x.  (The sign is used for the - flag.)
     164             :          */
     165             :         int width;
     166             : 
     167             :         /* %#x
     168             :          * "alternate representation" flag, not POSIX compatible when used
     169             :          * with %p or %d, will cause warnings from GCC & clang.  Not used by
     170             :          * printfrr() itself for extension specifiers.
     171             :          */
     172             :         bool alt_repr;
     173             : 
     174             :         /* %-x
     175             :          * left-pad flag.  Internally handled by printfrr() if width is
     176             :          * nonzero.  Only use if the extension sets width to 0.
     177             :          */
     178             :         bool leftadj;
     179             : };
     180             : 
     181             : /* for any extension that needs a buffer length */
     182             : 
     183           0 : static inline ssize_t printfrr_ext_len(struct printfrr_eargs *ea)
     184             : {
     185           0 :         ssize_t rv;
     186             : 
     187           0 :         if (ea->precision >= 0)
     188           0 :                 rv = ea->precision;
     189           0 :         else if (ea->width >= 0) {
     190           0 :                 rv = ea->width;
     191           0 :                 ea->width = -1;
     192             :         } else
     193             :                 rv = -1;
     194             : 
     195           0 :         return rv;
     196             : }
     197             : 
     198             : /* no locking - must be called when single threaded (e.g. at startup.)
     199             :  * this restriction hopefully won't be a huge bother considering normal usage
     200             :  * scenarios...
     201             :  */
     202             : void printfrr_ext_reg(const struct printfrr_ext *);
     203             : 
     204             : #define printfrr_ext_autoreg_p(matchs, print_fn)                               \
     205             :         static ssize_t print_fn(struct fbuf *, struct printfrr_eargs *,        \
     206             :                                 const void *);                                 \
     207             :         static const struct printfrr_ext _printext_##print_fn = {              \
     208             :                 .match = matchs,                                               \
     209             :                 .print_ptr = print_fn,                                         \
     210             :         };                                                                     \
     211             :         static void _printreg_##print_fn(void) __attribute__((constructor));   \
     212             :         static void _printreg_##print_fn(void)                                 \
     213             :         {                                                                      \
     214             :                 printfrr_ext_reg(&_printext_##print_fn);                       \
     215             :         }                                                                      \
     216             :         MACRO_REQUIRE_SEMICOLON()
     217             : 
     218             : #define printfrr_ext_autoreg_i(matchs, print_fn)                               \
     219             :         static ssize_t print_fn(struct fbuf *, struct printfrr_eargs *,        \
     220             :                                 uintmax_t);                                    \
     221             :         static const struct printfrr_ext _printext_##print_fn = {              \
     222             :                 .match = matchs,                                               \
     223             :                 .print_int = print_fn,                                         \
     224             :         };                                                                     \
     225             :         static void _printreg_##print_fn(void) __attribute__((constructor));   \
     226             :         static void _printreg_##print_fn(void)                                 \
     227             :         {                                                                      \
     228             :                 printfrr_ext_reg(&_printext_##print_fn);                       \
     229             :         }                                                                      \
     230             :         MACRO_REQUIRE_SEMICOLON()
     231             : 
     232             : /* fbuf helper functions - note all 3 of these return the length that would
     233             :  * be written regardless of how much space was available in the buffer, as
     234             :  * needed for implementing printfrr extensions.  (They also accept NULL buf
     235             :  * for that.)
     236             :  */
     237             : 
     238        1616 : static inline ssize_t bputs(struct fbuf *buf, const char *str)
     239             : {
     240        1616 :         size_t len = strlen(str);
     241        1616 :         size_t ncopy;
     242             : 
     243        1616 :         if (!buf)
     244           0 :                 return len;
     245             : 
     246        1616 :         ncopy = MIN(len, (size_t)(buf->buf + buf->len - buf->pos));
     247        1616 :         memcpy(buf->pos, str, ncopy);
     248        1616 :         buf->pos += ncopy;
     249             : 
     250        1616 :         return len;
     251             : }
     252             : 
     253        3674 : static inline ssize_t bputch(struct fbuf *buf, char ch)
     254             : {
     255        3674 :         if (buf && buf->pos < buf->buf + buf->len)
     256        3674 :                 *buf->pos++ = ch;
     257        3622 :         return 1;
     258             : }
     259             : 
     260           0 : static inline ssize_t bputhex(struct fbuf *buf, uint8_t val)
     261             : {
     262           0 :         static const char hexch[] = "0123456789abcdef";
     263             : 
     264           0 :         if (buf && buf->pos < buf->buf + buf->len)
     265           0 :                 *buf->pos++ = hexch[(val >> 4) & 0xf];
     266           0 :         if (buf && buf->pos < buf->buf + buf->len)
     267           0 :                 *buf->pos++ = hexch[val & 0xf];
     268           0 :         return 2;
     269             : }
     270             : 
     271             : /* %pVA extension, equivalent to Linux kernel %pV */
     272             : 
     273             : struct va_format {
     274             :         const char *fmt;
     275             :         va_list *va;
     276             : };
     277             : 
     278             : #ifdef _FRR_ATTRIBUTE_PRINTFRR
     279             : #pragma FRR printfrr_ext "%pFB" (struct fbuf *)
     280             : #pragma FRR printfrr_ext "%pVA" (struct va_format *)
     281             : 
     282             : #pragma FRR printfrr_ext "%pHX" (signed char *)
     283             : #pragma FRR printfrr_ext "%pHX" (unsigned char *)
     284             : #pragma FRR printfrr_ext "%pHX" (void *)
     285             : #pragma FRR printfrr_ext "%pHS" (signed char *)
     286             : #pragma FRR printfrr_ext "%pHS" (unsigned char *)
     287             : #pragma FRR printfrr_ext "%pHS" (void *)
     288             : 
     289             : #pragma FRR printfrr_ext "%pSE" (char *)
     290             : #pragma FRR printfrr_ext "%pSQ" (char *)
     291             : 
     292             : #pragma FRR printfrr_ext "%pTS" (struct timespec *)
     293             : #pragma FRR printfrr_ext "%pTV" (struct timeval *)
     294             : #pragma FRR printfrr_ext "%pTT" (time_t *)
     295             : #endif
     296             : 
     297             : /* when using non-ISO-C compatible extension specifiers... */
     298             : 
     299             : #ifdef _FRR_ATTRIBUTE_PRINTFRR
     300             : #define FMT_NSTD_BEGIN
     301             : #define FMT_NSTD_END
     302             : #else /* !_FRR_ATTRIBUTE_PRINTFRR */
     303             : #define FMT_NSTD_BEGIN \
     304             :         _Pragma("GCC diagnostic push")                                         \
     305             :         _Pragma("GCC diagnostic ignored \"-Wformat\"")                         \
     306             :         /* end */
     307             : #define FMT_NSTD_END \
     308             :         _Pragma("GCC diagnostic pop")                                          \
     309             :         /* end */
     310             : #endif
     311             : 
     312             : #define FMT_NSTD(expr)                                                         \
     313             :         ({                                                                     \
     314             :                 FMT_NSTD_BEGIN                                                 \
     315             :                 typeof(expr) _v;                                               \
     316             :                 _v = expr;                                                     \
     317             :                 FMT_NSTD_END                                                   \
     318             :                 _v;                                                            \
     319             :         })                                                                     \
     320             :         /* end */
     321             : 
     322             : #ifdef __cplusplus
     323             : }
     324             : #endif
     325             : 
     326             : #endif

Generated by: LCOV version v1.16-topotato