back to topotato report
topotato coverage report
Current view: top level - lib/printf - glue.c (source / functions) Hit Total Coverage
Test: test_pim6_prune_propagate.py::PIM6PrunePropagate Lines: 62 153 40.5 %
Date: 2023-02-24 18:39:23 Functions: 7 16 43.8 %

          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             : #ifdef HAVE_CONFIG_H
      18             : #include "config.h"
      19             : #endif
      20             : 
      21             : #include <sys/types.h>
      22             : #include <string.h>
      23             : #include <wchar.h>
      24             : 
      25             : #include "printfrr.h"
      26             : #include "printflocal.h"
      27             : 
      28        1220 : ssize_t bprintfrr(struct fbuf *out, const char *fmt, ...)
      29             : {
      30        1220 :         ssize_t ret;
      31        1220 :         va_list ap;
      32             : 
      33        1220 :         va_start(ap, fmt);
      34        1220 :         ret = vbprintfrr(out, fmt, ap);
      35        1220 :         va_end(ap);
      36        1220 :         return ret;
      37             : }
      38             : 
      39           0 : ssize_t vsnprintfrr(char *out, size_t outsz, const char *fmt, va_list ap)
      40             : {
      41           0 :         struct fbuf fbb = { .buf = out, .pos = out, .len = outsz - 1, };
      42           0 :         struct fbuf *fb = (out && outsz) ? &fbb : NULL;
      43           0 :         ssize_t ret;
      44             : 
      45           0 :         ret = vbprintfrr(fb, fmt, ap);
      46           0 :         if (fb)
      47           0 :                 fb->pos[0] = '\0';
      48           0 :         return ret;
      49             : }
      50             : 
      51        8831 : ssize_t snprintfrr(char *out, size_t outsz, const char *fmt, ...)
      52             : {
      53        8831 :         struct fbuf fbb = { .buf = out, .pos = out, .len = outsz - 1, };
      54        8831 :         struct fbuf *fb = (out && outsz) ? &fbb : NULL;
      55        8831 :         ssize_t ret;
      56        8831 :         va_list ap;
      57             : 
      58        8831 :         va_start(ap, fmt);
      59        8831 :         ret = vbprintfrr(fb, fmt, ap);
      60        8829 :         va_end(ap);
      61        8829 :         if (fb)
      62        8829 :                 fb->pos[0] = '\0';
      63        8829 :         return ret;
      64             : }
      65             : 
      66           0 : ssize_t vcsnprintfrr(char *out, size_t outsz, const char *fmt, va_list ap)
      67             : {
      68           0 :         if (!out || !outsz)
      69           0 :                 return vbprintfrr(NULL, fmt, ap);
      70             : 
      71           0 :         struct fbuf fbb = { .buf = out, .pos = out, .len = outsz - 1, };
      72           0 :         ssize_t ret;
      73           0 :         size_t pos;
      74             : 
      75           0 :         pos = strnlen(out, outsz);
      76           0 :         fbb.pos += pos;
      77             : 
      78           0 :         ret = vbprintfrr(&fbb, fmt, ap);
      79           0 :         fbb.pos[0] = '\0';
      80           0 :         return ret >= 0 ? ret + (ssize_t)pos : ret;
      81             : }
      82             : 
      83           0 : ssize_t csnprintfrr(char *out, size_t outsz, const char *fmt, ...)
      84             : {
      85           0 :         ssize_t ret;
      86           0 :         va_list ap;
      87             : 
      88           0 :         va_start(ap, fmt);
      89           0 :         ret = vcsnprintfrr(out, outsz, fmt, ap);
      90           0 :         va_end(ap);
      91           0 :         return ret;
      92             : }
      93             : 
      94         253 : char *vasnprintfrr(struct memtype *mt, char *out, size_t outsz, const char *fmt,
      95             :                    va_list ap)
      96             : {
      97         253 :         struct fbuf fb = { .buf = out, .pos = out, .len = outsz - 1, };
      98         253 :         ssize_t len;
      99         253 :         va_list ap2;
     100         253 :         char *ret = out;
     101             : 
     102         253 :         va_copy(ap2, ap);
     103         253 :         len = vbprintfrr(&fb, fmt, ap);
     104         253 :         if (len < 0) {
     105           0 :                 va_end(ap2);
     106             :                 /* error = malformed format string => try something useful */
     107           0 :                 return qstrdup(mt, fmt);
     108             :         }
     109             : 
     110         253 :         if ((size_t)len >= outsz - 1) {
     111           0 :                 ret = qmalloc(mt, len + 1);
     112           0 :                 fb.buf = fb.pos = ret;
     113           0 :                 fb.len = len;
     114             : 
     115           0 :                 vbprintfrr(&fb, fmt, ap2);
     116             :         }
     117             : 
     118         253 :         va_end(ap2);
     119         253 :         ret[len] = '\0';
     120         253 :         return ret;
     121             : }
     122             : 
     123           0 : char *asnprintfrr(struct memtype *mt, char *out, size_t outsz, const char *fmt,
     124             :                   ...)
     125             : {
     126           0 :         va_list ap;
     127           0 :         char *ret;
     128             : 
     129           0 :         va_start(ap, fmt);
     130           0 :         ret = vasnprintfrr(mt, out, outsz, fmt, ap);
     131           0 :         va_end(ap);
     132           0 :         return ret;
     133             : }
     134             : 
     135           0 : char *vasprintfrr(struct memtype *mt, const char *fmt, va_list ap)
     136             : {
     137           0 :         char buf[256];
     138           0 :         char *ret;
     139             : 
     140           0 :         ret = vasnprintfrr(mt, buf, sizeof(buf), fmt, ap);
     141             : 
     142           0 :         if (ret == buf)
     143           0 :                 ret = qstrdup(mt, ret);
     144           0 :         return ret;
     145             : }
     146             : 
     147           0 : char *asprintfrr(struct memtype *mt, const char *fmt, ...)
     148             : {
     149           0 :         char buf[256];
     150           0 :         va_list ap;
     151           0 :         char *ret;
     152             : 
     153           0 :         va_start(ap, fmt);
     154           0 :         ret = vasnprintfrr(mt, buf, sizeof(buf), fmt, ap);
     155           0 :         va_end(ap);
     156             : 
     157           0 :         if (ret == buf)
     158           0 :                 ret = qstrdup(mt, ret);
     159           0 :         return ret;
     160             : }
     161             : 
     162             : /* Q: WTF?
     163             :  * A: since printf should be reasonably fast (think debugging logs), the idea
     164             :  *    here is to keep things close by each other in a cacheline.  That's why
     165             :  *    ext_quick just has the first 2 characters of an extension, and we do a
     166             :  *    nice linear continuous sweep.  Only if we find something, we go do more
     167             :  *    expensive things.
     168             :  *
     169             :  * Q: doesn't this need a mutex/lock?
     170             :  * A: theoretically, yes, but that's quite expensive and I rather elide that
     171             :  *    necessity by putting down some usage rules.  Just call this at startup
     172             :  *    while singlethreaded and all is fine.  Ideally, just use constructors
     173             :  *    (and make sure dlopen() doesn't mess things up...)
     174             :  */
     175             : #define MAXEXT 64
     176             : 
     177             : struct ext_quick {
     178             :         char fmt[2];
     179             : };
     180             : 
     181             : static uint8_t ext_offsets[26] __attribute__((aligned(32)));
     182             : static struct ext_quick entries[MAXEXT] __attribute__((aligned(64)));
     183             : static const struct printfrr_ext *exts[MAXEXT] __attribute__((aligned(64)));
     184             : 
     185         352 : void printfrr_ext_reg(const struct printfrr_ext *ext)
     186             : {
     187         352 :         uint8_t o;
     188         352 :         ptrdiff_t i;
     189             : 
     190         352 :         if (!printfrr_ext_char(ext->match[0]))
     191             :                 return;
     192             : 
     193         352 :         o = ext->match[0] - 'A';
     194         352 :         for (i = ext_offsets[o];
     195         436 :                         i < MAXEXT && entries[i].fmt[0] &&
     196         336 :                         memcmp(entries[i].fmt, ext->match, 2) < 0;
     197          84 :                         i++)
     198             :                 ;
     199         352 :         if (i == MAXEXT)
     200             :                 return;
     201        4372 :         for (o++; o <= 'Z' - 'A'; o++)
     202        4020 :                 ext_offsets[o]++;
     203             : 
     204         352 :         memmove(entries + i + 1, entries + i,
     205         352 :                         (MAXEXT - i - 1) * sizeof(entries[0]));
     206         352 :         memmove(exts + i + 1, exts + i,
     207             :                         (MAXEXT - i - 1) * sizeof(exts[0]));
     208             : 
     209         352 :         memcpy(entries[i].fmt, ext->match, 2);
     210         352 :         exts[i] = ext;
     211             : }
     212             : 
     213        4031 : ssize_t printfrr_extp(struct fbuf *buf, struct printfrr_eargs *ea,
     214             :                       const void *ptr)
     215             : {
     216        4031 :         const char *fmt = ea->fmt;
     217        4031 :         const struct printfrr_ext *ext;
     218        4031 :         size_t i;
     219             : 
     220        5159 :         for (i = ext_offsets[fmt[0] - 'A']; i < MAXEXT; i++) {
     221        5159 :                 if (!entries[i].fmt[0] || entries[i].fmt[0] > fmt[0])
     222             :                         return -1;
     223        5159 :                 if (entries[i].fmt[1] && entries[i].fmt[1] != fmt[1])
     224        1128 :                         continue;
     225        4031 :                 ext = exts[i];
     226        4031 :                 if (!ext->print_ptr)
     227           0 :                         continue;
     228        4031 :                 if (strncmp(ext->match, fmt, strlen(ext->match)))
     229           0 :                         continue;
     230        4031 :                 ea->fmt += strlen(ext->match);
     231        4031 :                 return ext->print_ptr(buf, ea, ptr);
     232             :         }
     233             :         return -1;
     234             : }
     235             : 
     236           0 : ssize_t printfrr_exti(struct fbuf *buf, struct printfrr_eargs *ea,
     237             :                       uintmax_t num)
     238             : {
     239           0 :         const char *fmt = ea->fmt;
     240           0 :         const struct printfrr_ext *ext;
     241           0 :         size_t i;
     242             : 
     243           0 :         for (i = ext_offsets[fmt[0] - 'A']; i < MAXEXT; i++) {
     244           0 :                 if (!entries[i].fmt[0] || entries[i].fmt[0] > fmt[0])
     245             :                         return -1;
     246           0 :                 if (entries[i].fmt[1] && entries[i].fmt[1] != fmt[1])
     247           0 :                         continue;
     248           0 :                 ext = exts[i];
     249           0 :                 if (!ext->print_int)
     250           0 :                         continue;
     251           0 :                 if (strncmp(ext->match, fmt, strlen(ext->match)))
     252           0 :                         continue;
     253           0 :                 ea->fmt += strlen(ext->match);
     254           0 :                 return ext->print_int(buf, ea, num);
     255             :         }
     256             :         return -1;
     257             : }
     258             : 
     259          16 : printfrr_ext_autoreg_p("FB", printfrr_fb);
     260           0 : static ssize_t printfrr_fb(struct fbuf *out, struct printfrr_eargs *ea,
     261             :                            const void *ptr)
     262             : {
     263           0 :         const struct fbuf *in = ptr;
     264           0 :         ptrdiff_t copy_len;
     265             : 
     266           0 :         if (!in)
     267           0 :                 return bputs(out, "NULL");
     268             : 
     269           0 :         if (out) {
     270           0 :                 copy_len = MIN(in->pos - in->buf,
     271             :                                out->buf + out->len - out->pos);
     272           0 :                 if (copy_len > 0) {
     273           0 :                         memcpy(out->pos, in->buf, copy_len);
     274           0 :                         out->pos += copy_len;
     275             :                 }
     276             :         }
     277             : 
     278           0 :         return in->pos - in->buf;
     279             : }
     280             : 
     281          16 : printfrr_ext_autoreg_p("VA", printfrr_va);
     282           0 : static ssize_t printfrr_va(struct fbuf *buf, struct printfrr_eargs *ea,
     283             :                            const void *ptr)
     284             : {
     285           0 :         const struct va_format *vaf = ptr;
     286           0 :         va_list ap;
     287             : 
     288           0 :         if (!vaf || !vaf->fmt || !vaf->va)
     289           0 :                 return bputs(buf, "NULL");
     290             : 
     291             :         /* make sure we don't alter the data passed in - especially since
     292             :          * bprintfrr (and thus this) might be called on the same format twice,
     293             :          * when allocating a larger buffer in asnprintfrr()
     294             :          */
     295           0 :         va_copy(ap, *vaf->va);
     296             : #pragma GCC diagnostic push
     297             : #pragma GCC diagnostic ignored "-Wformat-nonliteral"
     298             :         /* can't format check this */
     299           0 :         return vbprintfrr(buf, vaf->fmt, ap);
     300             : #pragma GCC diagnostic pop
     301             : }

Generated by: LCOV version v1.16-topotato