]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/printfrr.h
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / lib / printfrr.h
index 418e839d97ce5bbe9c6119d5abc13f32c722c02a..b8bef562d25c6fc1c775f45e1800634470023b66 100644 (file)
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
 /*
  * Copyright (c) 2019  David Lamparter, for NetDEF, Inc.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #ifndef _FRR_PRINTFRR_H
 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)
@@ -105,6 +101,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];
@@ -112,23 +110,80 @@ struct printfrr_ext {
        /* both can be given, if not the code continues searching
         * (you can do %pX and %dX in 2 different entries)
         *
-        * return value: number of bytes consumed from the format string, so
-        * you can consume extra flags (e.g. register for "%pX", consume
-        * "%pXfoo" or "%pXbar" for flags.)  Convention is to make those flags
-        * lowercase letters or numbers.
+        * return value: number of bytes that would be printed if the buffer
+        * was large enough.  be careful about not under-reporting this;
+        * otherwise asnprintf() & co. will get broken.  Returning -1 means
+        * something went wrong & default %p/%d handling should be executed.
         *
-        * bsz is a compile-time constant in printf;  it's gonna be relatively
-        * small.  This isn't designed to print Shakespeare from a pointer.
+        * 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)(char *buf, size_t bsz, const char *fmt, int prec,
-                       const void *);
-       ssize_t (*print_int)(char *buf, size_t bsz, const char *fmt, int prec,
-                       uintmax_t);
+       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...
@@ -136,31 +191,38 @@ struct printfrr_ext {
 void printfrr_ext_reg(const struct printfrr_ext *);
 
 #define printfrr_ext_autoreg_p(matchs, print_fn)                               \
-       static ssize_t print_fn(char *, size_t, 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,                                               \
                .print_ptr = print_fn,                                         \
        };                                                                     \
        static void _printreg_##print_fn(void) __attribute__((constructor));   \
-       static void _printreg_##print_fn(void) {                               \
+       static void _printreg_##print_fn(void)                                 \
+       {                                                                      \
                printfrr_ext_reg(&_printext_##print_fn);                       \
        }                                                                      \
-       /* end */
+       MACRO_REQUIRE_SEMICOLON()
 
 #define printfrr_ext_autoreg_i(matchs, print_fn)                               \
-       static ssize_t print_fn(char *, size_t, 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,                                         \
        };                                                                     \
        static void _printreg_##print_fn(void) __attribute__((constructor));   \
-       static void _printreg_##print_fn(void) {                               \
+       static void _printreg_##print_fn(void)                                 \
+       {                                                                      \
                printfrr_ext_reg(&_printext_##print_fn);                       \
        }                                                                      \
-       /* end */
+       MACRO_REQUIRE_SEMICOLON()
 
-/* fbuf helper functions */
+/* fbuf helper functions - note all 3 of these return the length that would
+ * be written regardless of how much space was available in the buffer, as
+ * needed for implementing printfrr extensions.  (They also accept NULL buf
+ * for that.)
+ */
 
 static inline ssize_t bputs(struct fbuf *buf, const char *str)
 {
@@ -184,6 +246,68 @@ static inline ssize_t bputch(struct fbuf *buf, char ch)
        return 1;
 }
 
+static inline ssize_t bputhex(struct fbuf *buf, uint8_t val)
+{
+       static const char hexch[] = "0123456789abcdef";
+
+       if (buf && buf->pos < buf->buf + buf->len)
+               *buf->pos++ = hexch[(val >> 4) & 0xf];
+       if (buf && buf->pos < buf->buf + buf->len)
+               *buf->pos++ = hexch[val & 0xf];
+       return 2;
+}
+
+/* %pVA extension, equivalent to Linux kernel %pV */
+
+struct va_format {
+       const char *fmt;
+       va_list *va;
+};
+
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pFB" (struct fbuf *)
+#pragma FRR printfrr_ext "%pVA" (struct va_format *)
+
+#pragma FRR printfrr_ext "%pHX" (signed char *)
+#pragma FRR printfrr_ext "%pHX" (unsigned char *)
+#pragma FRR printfrr_ext "%pHX" (void *)
+#pragma FRR printfrr_ext "%pHS" (signed char *)
+#pragma FRR printfrr_ext "%pHS" (unsigned char *)
+#pragma FRR printfrr_ext "%pHS" (void *)
+
+#pragma FRR printfrr_ext "%pSE" (char *)
+#pragma FRR printfrr_ext "%pSQ" (char *)
+
+#pragma FRR printfrr_ext "%pTS" (struct timespec *)
+#pragma FRR printfrr_ext "%pTV" (struct timeval *)
+#pragma FRR printfrr_ext "%pTT" (time_t *)
+#endif
+
+/* when using non-ISO-C compatible extension specifiers... */
+
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#define FMT_NSTD_BEGIN
+#define FMT_NSTD_END
+#else /* !_FRR_ATTRIBUTE_PRINTFRR */
+#define FMT_NSTD_BEGIN \
+       _Pragma("GCC diagnostic push")                                         \
+       _Pragma("GCC diagnostic ignored \"-Wformat\"")                         \
+       /* end */
+#define FMT_NSTD_END \
+       _Pragma("GCC diagnostic pop")                                          \
+       /* end */
+#endif
+
+#define FMT_NSTD(expr)                                                         \
+       ({                                                                     \
+               FMT_NSTD_BEGIN                                                 \
+               typeof(expr) _v;                                               \
+               _v = expr;                                                     \
+               FMT_NSTD_END                                                   \
+               _v;                                                            \
+       })                                                                     \
+       /* end */
+
 #ifdef __cplusplus
 }
 #endif