]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib/printf: integrate
authorDavid Lamparter <equinox@diac24.net>
Sun, 12 May 2019 19:10:04 +0000 (21:10 +0200)
committerDavid Lamparter <equinox@diac24.net>
Mon, 3 Jun 2019 14:44:51 +0000 (16:44 +0200)
Signed-off-by: David Lamparter <equinox@diac24.net>
lib/printf/glue.c [new file with mode: 0644]
lib/printf/printf-pos.c
lib/printf/printfcommon.h
lib/printf/printflocal.h
lib/printf/vfprintf.c
lib/printfrr.h [new file with mode: 0644]
lib/subdir.am

diff --git a/lib/printf/glue.c b/lib/printf/glue.c
new file mode 100644 (file)
index 0000000..6b6e17d
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+
+#include "printfrr.h"
+
+ssize_t bprintfrr(struct fbuf *out, const char *fmt, ...)
+{
+       ssize_t ret;
+       va_list ap;
+
+       va_start(ap, fmt);
+       ret = vbprintfrr(out, fmt, ap);
+       va_end(ap);
+       return ret;
+}
+
+ssize_t vsnprintfrr(char *out, size_t outsz, const char *fmt, va_list ap)
+{
+       struct fbuf fbb = { .buf = out, .pos = out, .len = outsz - 1, };
+       struct fbuf *fb = (out && outsz) ? &fbb : NULL;
+       ssize_t ret;
+
+       ret = vbprintfrr(fb, fmt, ap);
+       if (fb)
+               fb->pos[0] = '\0';
+       return ret;
+}
+
+ssize_t snprintfrr(char *out, size_t outsz, const char *fmt, ...)
+{
+       struct fbuf fbb = { .buf = out, .pos = out, .len = outsz - 1, };
+       struct fbuf *fb = (out && outsz) ? &fbb : NULL;
+       ssize_t ret;
+       va_list ap;
+
+       va_start(ap, fmt);
+       ret = vbprintfrr(fb, fmt, ap);
+       va_end(ap);
+       if (fb)
+               fb->pos[0] = '\0';
+       return ret;
+}
+
+ssize_t vcsnprintfrr(char *out, size_t outsz, const char *fmt, va_list ap)
+{
+       if (!out || !outsz)
+               return vbprintfrr(NULL, fmt, ap);
+
+       struct fbuf fbb = { .buf = out, .pos = out, .len = outsz - 1, };
+       ssize_t ret;
+       size_t pos;
+
+       pos = strnlen(out, outsz);
+       fbb.pos += pos;
+
+       ret = vbprintfrr(&fbb, fmt, ap);
+       fbb.pos[0] = '\0';
+       return ret >= 0 ? ret + (ssize_t)pos : ret;
+}
+
+ssize_t csnprintfrr(char *out, size_t outsz, const char *fmt, ...)
+{
+       ssize_t ret;
+       va_list ap;
+
+       va_start(ap, fmt);
+       ret = vcsnprintfrr(out, outsz, fmt, ap);
+       va_end(ap);
+       return ret;
+}
+
+char *vasnprintfrr(struct memtype *mt, char *out, size_t outsz, const char *fmt,
+                  va_list ap)
+{
+       struct fbuf fb = { .buf = out, .pos = out, .len = outsz - 1, };
+       ssize_t len;
+       va_list ap2;
+       char *ret = out;
+
+       va_copy(ap2, ap);
+       len = vbprintfrr(&fb, fmt, ap);
+       if (len < 0)
+               /* error = malformed format string => try something useful */
+               return qstrdup(mt, fmt);
+
+       if ((size_t)len >= outsz - 1) {
+               ret = qmalloc(mt, len + 1);
+               fb.buf = fb.pos = ret;
+               fb.len = len;
+
+               vbprintfrr(&fb, fmt, ap2);
+       }
+       ret[len] = '\0';
+       return ret;
+}
+
+char *asnprintfrr(struct memtype *mt, char *out, size_t outsz, const char *fmt,
+                 ...)
+{
+       va_list ap;
+       char *ret;
+
+       va_start(ap, fmt);
+       ret = vasnprintfrr(mt, out, outsz, fmt, ap);
+       va_end(ap);
+       return ret;
+}
+
+char *vasprintfrr(struct memtype *mt, const char *fmt, va_list ap)
+{
+       char buf[256];
+       char *ret;
+
+       ret = vasnprintfrr(mt, buf, sizeof(buf), fmt, ap);
+
+       if (ret == buf)
+               ret = qstrdup(mt, ret);
+       return ret;
+}
+
+char *asprintfrr(struct memtype *mt, const char *fmt, ...)
+{
+       char buf[256];
+       va_list ap;
+       char *ret;
+
+       va_start(ap, fmt);
+       ret = vasnprintfrr(mt, buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+
+       if (ret == buf)
+               ret = qstrdup(mt, ret);
+       return ret;
+}
index a461a2be9a30b1398aa420df11778173877c43b9..7e5231c27e9ecb1388910b6f95d07124889b30bb 100644 (file)
  * SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_CDEFS_H
 #include <sys/cdefs.h>
+#endif
 
 /*
  * This is the code responsible for handling positional arguments
index 716177c57ddc9cc161e71d4a27756b591c4924d0..5c45520b4c3adbb61f776454882855d97631bb5f 100644 (file)
@@ -50,19 +50,15 @@ static CHAR *__ultoa(u_long, CHAR *, int, int, const char *);
 
 #define NIOV 8
 struct io_state {
-       FILE *fp;
-       struct __suio uio;      /* output information: summary */
-       struct iovec iov[NIOV];/* ... and individual io vectors */
+       struct fbuf *cb;
+       size_t avail;
 };
 
 static inline void
-io_init(struct io_state *iop, FILE *fp)
+io_init(struct io_state *iop, struct fbuf *cb)
 {
-
-       iop->uio.uio_iov = iop->iov;
-       iop->uio.uio_resid = 0;
-       iop->uio.uio_iovcnt = 0;
-       iop->fp = fp;
+       iop->cb = cb;
+       iop->avail = cb ? cb->len - (cb->pos - cb->buf) : 0;
 }
 
 /*
@@ -70,13 +66,19 @@ io_init(struct io_state *iop, FILE *fp)
  * remain valid until io_flush() is called.
  */
 static inline int
-io_print(struct io_state *iop, const CHAR * __restrict ptr, int len)
+io_print(struct io_state *iop, const CHAR * __restrict ptr, size_t len)
 {
+       size_t copylen = len;
 
-       iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr;
-       iop->iov[iop->uio.uio_iovcnt].iov_len = len;
-       iop->uio.uio_resid += len;
-       return (0);
+       if (!iop->cb)
+               return 0;
+       if (iop->avail < copylen)
+               copylen = iop->avail;
+
+       memcpy(iop->cb->pos, ptr, copylen);
+       iop->avail -= copylen;
+       iop->cb->pos += copylen;
+       return 0;
 }
 
 /*
index a2de161130bec45a65b361c02c8aeed5c25ef6f2..653baf2a4e4238ac5fc0607005dc0695138d59e1 100644 (file)
@@ -35,6 +35,7 @@
  */
 
 #include "compiler.h"
+#include "printfrr.h"
 
 /*
  * Flags used during conversion.
index 66cedcb6986d79e13b8a5b8ddbb6756c8da61a16..05e88afd73d3015094e5dbdd3dc0954f5a9b56d2 100644 (file)
  * SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_CDEFS_H
 #include <sys/cdefs.h>
+#endif
 
 /*
  * Actual printf innards.
 
 #include <stdarg.h>
 
-#define NO_FLOATING_POINT
-
-int __vfprintf(FILE *fp, const char *fmt0, va_list ap);
-
-struct __suio {
-       size_t uio_resid;
-
-       struct iovec *uio_iov;
-       size_t uio_iovcnt;
-};
-
 #include "printflocal.h"
 
 #define        CHAR    char
@@ -151,8 +146,8 @@ __wcsconv(wchar_t *wcsarg, int prec)
 /*
  * Non-MT-safe version
  */
-int
-__vfprintf(FILE *fp, const char *fmt0, va_list ap)
+ssize_t
+vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap)
 {
        char *fmt;              /* format string */
        int ch;                 /* character from fmt */
@@ -181,7 +176,6 @@ __vfprintf(FILE *fp, 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 */
-       int savserr;
 
        static const char xdigs_lower[16] = "0123456789abcdef";
        static const char xdigs_upper[16] = "0123456789ABCDEF";
@@ -266,16 +260,13 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap)
                val = GETARG (int); \
        }
 
-       savserr = fp->_flags & __SERR;
-       fp->_flags &= ~__SERR;
-
        saved_errno = errno;
        convbuf = NULL;
        fmt = (char *)fmt0;
        argtable = NULL;
        nextarg = 1;
        va_copy(orgap, ap);
-       io_init(&io, fp);
+       io_init(&io, cb);
        ret = 0;
 
        /*
diff --git a/lib/printfrr.h b/lib/printfrr.h
new file mode 100644 (file)
index 0000000..f98527e
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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
+#define _FRR_PRINTFRR_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+#include "compiler.h"
+#include "memory.h"
+
+struct fbuf {
+       char *buf;
+       char *pos;
+       size_t len;
+};
+
+#define at(a, b) \
+       __attribute__((format(printf, a, b)))
+#define atn(a, b) \
+       at(a, b) __attribute__((nonnull(1) _RET_NONNULL))
+#define atm(a, b) \
+       atn(a, b) __attribute__((malloc))
+
+/* return value is length needed for the full string (excluding \0) in all
+ * cases.  The functions write as much as they can, but continue regardless,
+ * so the return value is independent of buffer length.  Both bprintfrr and
+ * snprintf also accept NULL as output buffer.
+ */
+
+/* bprintfrr does NOT null terminate! use sparingly (only provided since it's
+ * the most direct interface) - useful for incrementally building long text
+ * (call bprintfrr repeatedly with the same buffer)
+ */
+ssize_t vbprintfrr(struct fbuf *out, const char *fmt, va_list) at(2, 0);
+ssize_t  bprintfrr(struct fbuf *out, const char *fmt, ...)     at(2, 3);
+
+/* these do null terminate like their snprintf cousins */
+ssize_t vsnprintfrr(char *out, size_t sz, const char *fmt, va_list) at(3, 0);
+ssize_t  snprintfrr(char *out, size_t sz, const char *fmt, ...)     at(3, 4);
+
+/* c = continue / concatenate (append at the end of the string)
+ * return value is would-be string length (regardless of buffer length),
+ * i.e. includes already written chars */
+ssize_t vcsnprintfrr(char *out, size_t sz, const char *fmt, va_list) at(3, 0);
+ssize_t  csnprintfrr(char *out, size_t sz, const char *fmt, ...)     at(3, 4);
+
+/* memory allocations don't fail in FRR, so you always get something here.
+ * (in case of error, returns a strdup of the format string) */
+char *vasprintfrr(struct memtype *mt, const char *fmt, va_list) atm(2, 0);
+char  *asprintfrr(struct memtype *mt, const char *fmt, ...)     atm(2, 3);
+
+/* try to use provided buffer (presumably from stack), allocate if it's too
+ * short.  Must call XFREE(mt, return value) if return value != out.
+ */
+char *vasnprintfrr(struct memtype *mt, char *out, size_t sz,
+                  const char *fmt, va_list) atn(4, 0);
+char  *asnprintfrr(struct memtype *mt, char *out, size_t sz,
+                  const char *fmt, ...)     atn(4, 5);
+
+#undef at
+#undef atm
+
+struct printfrr_ext {
+       const char *match;
+       const char *opts;
+
+       union {
+               ssize_t (*print_ptr)(struct fbuf *out, const char *fmt, void *);
+               ssize_t (*print_int)(struct fbuf *out, const char *fmt, int);
+       };
+};
+
+void printfrr_ext_reg(const struct printfrr_ext *);
+void printfrr_ext_unreg(const struct printfrr_ext *);
+
+#endif
index 61dded05f86c288dd802101fc6c84b22b9619f3a..50ff1feeccf708f52640ba678e2500eb136fbdd1 100644 (file)
@@ -94,6 +94,9 @@ lib_libfrr_la_SOURCES = \
        lib/yang_wrappers.c \
        lib/zclient.c \
        lib/logicalrouter.c \
+       lib/printf/printf-pos.c \
+       lib/printf/vfprintf.c \
+       lib/printf/glue.c \
        # end
 
 nodist_lib_libfrr_la_SOURCES = \
@@ -192,6 +195,7 @@ pkginclude_HEADERS += \
        lib/plist.h \
        lib/pqueue.h \
        lib/prefix.h \
+       lib/printfrr.h \
        lib/privs.h \
        lib/ptm_lib.h \
        lib/pw.h \
@@ -244,6 +248,8 @@ noinst_HEADERS += \
        lib/clippy.h \
        lib/log_int.h \
        lib/plist_int.h \
+       lib/printf/printfcommon.h \
+       lib/printf/printflocal.h \
        #end
 
 # General note about module and module helper library (libfrrsnmp, libfrrzmq)