back to topotato report
topotato coverage report
Current view: top level - lib/printf - vfprintf.c (source / functions) Hit Total Coverage
Test: test_demo.py::AllStartupTest Lines: 213 350 60.9 %
Date: 2023-02-24 18:37:51 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /*-
       2             :  * SPDX-License-Identifier: BSD-3-Clause
       3             :  *
       4             :  * Copyright (c) 1990, 1993
       5             :  *      The Regents of the University of California.  All rights reserved.
       6             :  *
       7             :  * This code is derived from software contributed to Berkeley by
       8             :  * Chris Torek.
       9             :  *
      10             :  * Copyright (c) 2011 The FreeBSD Foundation
      11             :  * All rights reserved.
      12             :  * Portions of this software were developed by David Chisnall
      13             :  * under sponsorship from the FreeBSD Foundation.
      14             :  *
      15             :  * Redistribution and use in source and binary forms, with or without
      16             :  * modification, are permitted provided that the following conditions
      17             :  * are met:
      18             :  * 1. Redistributions of source code must retain the above copyright
      19             :  *    notice, this list of conditions and the following disclaimer.
      20             :  * 2. Redistributions in binary form must reproduce the above copyright
      21             :  *    notice, this list of conditions and the following disclaimer in the
      22             :  *    documentation and/or other materials provided with the distribution.
      23             :  * 3. Neither the name of the University nor the names of its contributors
      24             :  *    may be used to endorse or promote products derived from this software
      25             :  *    without specific prior written permission.
      26             :  *
      27             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      28             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      29             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      30             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      31             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      32             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      33             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      34             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      35             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      36             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      37             :  * SUCH DAMAGE.
      38             :  */
      39             : 
      40             : #ifdef HAVE_CONFIG_H
      41             : #include "config.h"
      42             : #endif
      43             : 
      44             : #ifdef HAVE_SYS_CDEFS_H
      45             : #include <sys/cdefs.h>
      46             : #endif
      47             : 
      48             : /*
      49             :  * Actual printf innards.
      50             :  *
      51             :  * This code is large and complicated...
      52             :  */
      53             : 
      54             : #include <sys/types.h>
      55             : #include <sys/uio.h>
      56             : 
      57             : #include <ctype.h>
      58             : #include <errno.h>
      59             : #include <limits.h>
      60             : #include <stddef.h>
      61             : #include <stdint.h>
      62             : #include <stdio.h>
      63             : #include <stdlib.h>
      64             : #include <string.h>
      65             : #include <wchar.h>
      66             : 
      67             : #include <stdarg.h>
      68             : 
      69             : #include "printflocal.h"
      70             : 
      71             : #define CHAR    char
      72             : #include "printfcommon.h"
      73             : 
      74             : #ifdef WCHAR_SUPPORT
      75             : /*
      76             :  * Convert a wide character string argument for the %ls format to a multibyte
      77             :  * string representation. If not -1, prec specifies the maximum number of
      78             :  * bytes to output, and also means that we can't assume that the wide char.
      79             :  * string ends is null-terminated.
      80             :  */
      81             : static char *
      82             : __wcsconv(wchar_t *wcsarg, int prec)
      83             : {
      84             :         static const mbstate_t initial;
      85             :         mbstate_t mbs;
      86             :         char buf[MB_LEN_MAX];
      87             :         wchar_t *p;
      88             :         char *convbuf;
      89             :         size_t clen, nbytes;
      90             : 
      91             :         /* Allocate space for the maximum number of bytes we could output. */
      92             :         if (prec < 0) {
      93             :                 p = wcsarg;
      94             :                 mbs = initial;
      95             :                 nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
      96             :                 if (nbytes == (size_t)-1)
      97             :                         return NULL;
      98             :         } else {
      99             :                 /*
     100             :                  * Optimisation: if the output precision is small enough,
     101             :                  * just allocate enough memory for the maximum instead of
     102             :                  * scanning the string.
     103             :                  */
     104             :                 if (prec < 128)
     105             :                         nbytes = prec;
     106             :                 else {
     107             :                         nbytes = 0;
     108             :                         p = wcsarg;
     109             :                         mbs = initial;
     110             :                         for (;;) {
     111             :                                 clen = wcrtomb(buf, *p++, &mbs);
     112             :                                 if (clen == 0 || clen == (size_t)-1 ||
     113             :                                     nbytes + clen > (size_t)prec)
     114             :                                         break;
     115             :                                 nbytes += clen;
     116             :                         }
     117             :                 }
     118             :         }
     119             :         if ((convbuf = malloc(nbytes + 1)) == NULL)
     120             :                 return NULL;
     121             : 
     122             :         /* Fill the output buffer. */
     123             :         p = wcsarg;
     124             :         mbs = initial;
     125             :         if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
     126             :             nbytes, &mbs)) == (size_t)-1) {
     127             :                 free(convbuf);
     128             :                 return NULL;
     129             :         }
     130             :         convbuf[nbytes] = '\0';
     131             :         return (convbuf);
     132             : }
     133             : #endif /* WCHAR_SUPPORT */
     134             : 
     135             : /*
     136             :  * The size of the buffer we use as scratch space for integer
     137             :  * conversions, among other things.  We need enough space to
     138             :  * write a uintmax_t in octal (plus one byte).
     139             :  */
     140             : #if UINTMAX_MAX <= UINT64_MAX
     141             : #define BUF     80
     142             : #else
     143             : #error "BUF must be large enough to format a uintmax_t"
     144             : #endif
     145             : 
     146             : /*
     147             :  * Non-MT-safe version
     148             :  */
     149             : ssize_t
     150         768 : vbprintfrr(struct fbuf *cb_in, const char *fmt0, va_list ap)
     151        1515 : {
     152         768 :         const char *fmt;        /* format string */
     153         768 :         int ch;                 /* character from fmt */
     154         768 :         int n, n2;              /* handy integer (short term usage) */
     155         768 :         const char *cp;         /* handy char pointer (short term usage) */
     156         768 :         int flags;              /* flags as above */
     157         768 :         int ret;                /* return value accumulator */
     158         768 :         int width;              /* width from format (%8d), or 0 */
     159         768 :         int prec;               /* precision from format; <0 for N/A */
     160         768 :         int saved_errno;
     161         768 :         char sign;              /* sign prefix (' ', '+', '-', or \0) */
     162             : 
     163         768 :         u_long  ulval = 0;      /* integer arguments %[diouxX] */
     164         768 :         uintmax_t ujval = 0;    /* %j, %ll, %q, %t, %z integers */
     165         768 :         void *ptrval;           /* %p */
     166         768 :         int base;               /* base for [diouxX] conversion */
     167         768 :         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
     168         768 :         int realsz;             /* field size expanded by dprec, sign, etc */
     169         768 :         int size;               /* size of converted field or string */
     170         768 :         int prsize;             /* max size of printed field */
     171         768 :         const char *xdigs;      /* digits for %[xX] conversion */
     172         768 :         struct io_state io;     /* I/O buffering state */
     173         768 :         char buf[BUF];          /* buffer with space for digits of uintmax_t */
     174         768 :         char ox[2];             /* space for 0x; ox[1] is either x, X, or \0 */
     175         768 :         union arg *argtable;    /* args, built due to positional arg */
     176         768 :         union arg statargtable [STATIC_ARG_TBL_SIZE];
     177         768 :         int nextarg;            /* 1-based argument index */
     178         768 :         va_list orgap;          /* original argument pointer */
     179         768 :         char *convbuf;          /* wide to multibyte conversion result */
     180         768 :         char *extstart = NULL;  /* where printfrr_ext* started printing */
     181         768 :         struct fbuf cb_copy, *cb;
     182         768 :         struct fmt_outpos *opos;
     183             : 
     184         768 :         static const char xdigs_lower[16] = "0123456789abcdef";
     185         768 :         static const char xdigs_upper[16] = "0123456789ABCDEF";
     186             : 
     187             :         /* BEWARE, these `goto error' on error. */
     188             : #define PRINT(ptr, len) { \
     189             :         if (io_print(&io, (ptr), (len)))    \
     190             :                 goto error; \
     191             : }
     192             : #define PAD(howmany, with) { \
     193             :         if (io_pad(&io, (howmany), (with))) \
     194             :                 goto error; \
     195             : }
     196             : #define PRINTANDPAD(p, ep, len, with) { \
     197             :         if (io_printandpad(&io, (p), (ep), (len), (with))) \
     198             :                 goto error; \
     199             : }
     200             : #define FLUSH() do { } while (0)
     201             : 
     202             :         /*
     203             :          * Get the argument indexed by nextarg.   If the argument table is
     204             :          * built, use it to get the argument.  If its not, get the next
     205             :          * argument (and arguments must be gotten sequentially).
     206             :          */
     207             : #define GETARG(type) \
     208             :         ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
     209             :             (nextarg++, va_arg(ap, type)))
     210             : 
     211             :         /*
     212             :          * To extend shorts properly, we need both signed and unsigned
     213             :          * argument extraction methods.
     214             :          */
     215             : #define SARG() \
     216             :         (flags&LONGINT ? GETARG(long) : \
     217             :             flags&SHORTINT ? (long)(short)GETARG(int) : \
     218             :             flags&CHARINT ? (long)(signed char)GETARG(int) : \
     219             :             (long)GETARG(int))
     220             : #define UARG() \
     221             :         (flags&LONGINT ? GETARG(u_long) : \
     222             :             flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
     223             :             flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
     224             :             (u_long)GETARG(u_int))
     225             : #define INTMAX_SIZE     (INTMAXT|SIZET|PTRDIFFT|LLONGINT|LONGDBL)
     226             : #define SJARG() \
     227             :         (flags&LONGDBL ? GETARG(int64_t) : \
     228             :             flags&INTMAXT ? GETARG(intmax_t) : \
     229             :             flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
     230             :             flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
     231             :             (intmax_t)GETARG(long long))
     232             : #define UJARG() \
     233             :         (flags&LONGDBL ? GETARG(uint64_t) : \
     234             :             flags&INTMAXT ? GETARG(uintmax_t) : \
     235             :             flags&SIZET ? (uintmax_t)GETARG(size_t) : \
     236             :             flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
     237             :             (uintmax_t)GETARG(unsigned long long))
     238             : 
     239             :         /*
     240             :          * Get * arguments, including the form *nn$.  Preserve the nextarg
     241             :          * that the argument can be gotten once the type is determined.
     242             :          */
     243             : #define GETASTER(val) \
     244             :         n2 = 0; \
     245             :         cp = fmt; \
     246             :         while (is_digit(*cp)) { \
     247             :                 n2 = 10 * n2 + to_digit(*cp); \
     248             :                 cp++; \
     249             :         } \
     250             :         if (*cp == '$') { \
     251             :                 int hold = nextarg; \
     252             :                 if (argtable == NULL) { \
     253             :                         argtable = statargtable; \
     254             :                         if (_frr_find_arguments (fmt0, orgap, &argtable)) { \
     255             :                                 ret = EOF; \
     256             :                                 goto error; \
     257             :                         } \
     258             :                 } \
     259             :                 nextarg = n2; \
     260             :                 val = GETARG (int); \
     261             :                 nextarg = hold; \
     262             :                 fmt = ++cp; \
     263             :         } else { \
     264             :                 val = GETARG (int); \
     265             :         }
     266             : 
     267         768 :         xdigs = xdigs_lower;
     268         768 :         saved_errno = errno;
     269         768 :         convbuf = NULL;
     270         768 :         fmt = (char *)fmt0;
     271         768 :         argtable = NULL;
     272         768 :         nextarg = 1;
     273         768 :         va_copy(orgap, ap);
     274             : 
     275         768 :         if (cb_in) {
     276             :                 /* prevent printfrr exts from polluting cb->outpos */
     277         768 :                 cb_copy = *cb_in;
     278         768 :                 cb_copy.outpos = NULL;
     279         768 :                 cb_copy.outpos_n = cb_copy.outpos_i = 0;
     280         768 :                 cb = &cb_copy;
     281             :         } else
     282             :                 cb = NULL;
     283             : 
     284         768 :         io_init(&io, cb);
     285         768 :         ret = 0;
     286             : 
     287             :         /*
     288             :          * Scan the format for conversions (`%' character).
     289             :          */
     290        2323 :         for (;;) {
     291       11418 :                 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
     292             :                         /* void */;
     293        2323 :                 if ((n = fmt - cp) != 0) {
     294        1405 :                         if ((unsigned)ret + n > INT_MAX) {
     295           0 :                                 ret = EOF;
     296           0 :                                 errno = EOVERFLOW;
     297           0 :                                 goto error;
     298             :                         }
     299        1405 :                         PRINT(cp, n);
     300        1405 :                         ret += n;
     301             :                 }
     302        2323 :                 if (ch == '\0')
     303         768 :                         goto done;
     304        1555 :                 fmt++;          /* skip over '%' */
     305             : 
     306        1555 :                 flags = 0;
     307        1555 :                 dprec = 0;
     308        1555 :                 width = -1;
     309        1555 :                 prec = -1;
     310        1555 :                 sign = '\0';
     311        1555 :                 ox[1] = '\0';
     312             : 
     313        1555 :                 if (cb_in && cb_in->outpos_i < cb_in->outpos_n)
     314         766 :                         opos = &cb_in->outpos[cb_in->outpos_i];
     315             :                 else
     316        1555 :                         opos = NULL;
     317             : 
     318        2892 : rflag:          ch = *fmt++;
     319        3602 : reswitch:       switch (ch) {
     320           0 :                 case ' ':
     321             :                         /*-
     322             :                          * ``If the space and + flags both appear, the space
     323             :                          * flag will be ignored.''
     324             :                          *      -- ANSI X3J11
     325             :                          */
     326           0 :                         if (!sign)
     327           0 :                                 sign = ' ';
     328           0 :                         goto rflag;
     329          46 :                 case '#':
     330          46 :                         flags |= ALT;
     331          46 :                         goto rflag;
     332             :                 case '*':
     333             :                         /*-
     334             :                          * ``A negative field width argument is taken as a
     335             :                          * - flag followed by a positive field width.''
     336             :                          *      -- ANSI X3J11
     337             :                          * They don't exclude field widths read from args.
     338             :                          */
     339           0 :                         GETASTER (width);
     340           0 :                         if (width >= 0)
     341           0 :                                 goto rflag;
     342           0 :                         width = -width;
     343             :                         /* FALLTHROUGH */
     344          34 :                 case '-':
     345          34 :                         flags |= LADJUST;
     346          34 :                         goto rflag;
     347         216 :                 case '+':
     348         216 :                         sign = '+';
     349         216 :                         goto rflag;
     350           0 :                 case '\'':
     351           0 :                         flags |= GROUPING;
     352           0 :                         goto rflag;
     353           6 :                 case '.':
     354           6 :                         if ((ch = *fmt++) == '*') {
     355           6 :                                 GETASTER (prec);
     356           6 :                                 goto rflag;
     357             :                         }
     358             :                         prec = 0;
     359           0 :                         while (is_digit(ch)) {
     360           0 :                                 prec = 10 * prec + to_digit(ch);
     361           0 :                                 ch = *fmt++;
     362             :                         }
     363           0 :                         goto reswitch;
     364         648 :                 case '0':
     365             :                         /*-
     366             :                          * ``Note that 0 is taken as a flag, not as the
     367             :                          * beginning of a field width.''
     368             :                          *      -- ANSI X3J11
     369             :                          */
     370         648 :                         flags |= ZEROPAD;
     371         648 :                         goto rflag;
     372             :                 case '1': case '2': case '3': case '4':
     373             :                 case '5': case '6': case '7': case '8': case '9':
     374             :                         n = 0;
     375         740 :                         do {
     376         740 :                                 n = 10 * n + to_digit(ch);
     377         740 :                                 ch = *fmt++;
     378         740 :                         } while (is_digit(ch));
     379         710 :                         if (ch == '$') {
     380           0 :                                 nextarg = n;
     381           0 :                                 if (argtable == NULL) {
     382           0 :                                         argtable = statargtable;
     383           0 :                                         if (_frr_find_arguments (fmt0, orgap,
     384             :                                                               &argtable)) {
     385           0 :                                                 ret = EOF;
     386           0 :                                                 goto error;
     387             :                                         }
     388             :                                 }
     389           0 :                                 goto rflag;
     390             :                         }
     391         710 :                         width = n;
     392         710 :                         goto reswitch;
     393           0 :                 case 'L':
     394           0 :                         flags |= LONGDBL;
     395           0 :                         goto rflag;
     396           0 :                 case 'h':
     397           0 :                         if (flags & SHORTINT) {
     398           0 :                                 flags &= ~SHORTINT;
     399           0 :                                 flags |= CHARINT;
     400             :                         } else
     401           0 :                                 flags |= SHORTINT;
     402           0 :                         goto rflag;
     403          14 :                 case 'j':
     404          14 :                         flags |= INTMAXT;
     405          14 :                         goto rflag;
     406         345 :                 case 'l':
     407         345 :                         if (flags & LONGINT) {
     408          60 :                                 flags &= ~LONGINT;
     409          60 :                                 flags |= LLONGINT;
     410             :                         } else
     411         285 :                                 flags |= LONGINT;
     412         345 :                         goto rflag;
     413           0 :                 case 'q':
     414           0 :                         flags |= LLONGINT;      /* not necessarily */
     415           0 :                         goto rflag;
     416           0 :                 case 't':
     417           0 :                         flags |= PTRDIFFT;
     418           0 :                         goto rflag;
     419          28 :                 case 'z':
     420          28 :                         flags |= SIZET;
     421          28 :                         goto rflag;
     422           0 :                 case 'C':
     423           0 :                         flags |= LONGINT;
     424             :                         /*FALLTHROUGH*/
     425           0 :                 case 'c':
     426             : #ifdef WCHAR_SUPPORT
     427             :                         if (flags & LONGINT) {
     428             :                                 static const mbstate_t initial;
     429             :                                 mbstate_t mbs;
     430             :                                 size_t mbseqlen;
     431             : 
     432             :                                 mbs = initial;
     433             :                                 mbseqlen = wcrtomb(cp = buf,
     434             :                                     (wchar_t)GETARG(wint_t), &mbs);
     435             :                                 if (mbseqlen == (size_t)-1) {
     436             :                                         goto error;
     437             :                                 }
     438             :                                 size = (int)mbseqlen;
     439             :                         } else
     440             : #endif /* WCHAR_SUPPORT */
     441             :                         {
     442           0 :                                 buf[0] = GETARG(int);
     443           0 :                                 cp = buf;
     444           0 :                                 size = 1;
     445             :                         }
     446           0 :                         sign = '\0';
     447           0 :                         break;
     448           0 :                 case 'D':
     449           0 :                         flags |= LONGINT;
     450             :                         /*FALLTHROUGH*/
     451         676 :                 case 'd':
     452             :                 case 'i':
     453         676 :                         if (flags & INTMAX_SIZE)
     454          14 :                                 ujval = SJARG();
     455             :                         else
     456         662 :                                 ulval = SARG();
     457             : 
     458         676 :                         if (printfrr_ext_char(fmt[0])) {
     459           0 :                                 struct printfrr_eargs ea = {
     460             :                                         .fmt = fmt,
     461             :                                         .precision = prec,
     462             :                                         .width = width,
     463           0 :                                         .alt_repr = !!(flags & ALT),
     464           0 :                                         .leftadj = !!(flags & LADJUST),
     465             :                                 };
     466             : 
     467           0 :                                 if (cb)
     468           0 :                                         extstart = cb->pos;
     469             : 
     470           0 :                                 size = printfrr_exti(cb, &ea,
     471             :                                                 (flags & INTMAX_SIZE) ? ujval
     472             :                                                 : (uintmax_t)ulval);
     473           0 :                                 if (size >= 0) {
     474           0 :                                         fmt = ea.fmt;
     475           0 :                                         width = ea.width;
     476           0 :                                         goto ext_printed;
     477             :                                 }
     478             :                         }
     479         676 :                         if (flags & INTMAX_SIZE) {
     480          14 :                                 if ((intmax_t)ujval < 0) {
     481           0 :                                         ujval = -ujval;
     482           0 :                                         sign = '-';
     483             :                                 }
     484             :                         } else {
     485         662 :                                 if ((long)ulval < 0) {
     486           0 :                                         ulval = -ulval;
     487           0 :                                         sign = '-';
     488             :                                 }
     489             :                         }
     490         676 :                         base = 10;
     491         676 :                         goto number;
     492             : #ifndef NO_FLOATING_POINT
     493           0 :                 case 'a':
     494             :                 case 'A':
     495             :                 case 'e':
     496             :                 case 'E':
     497             :                 case 'f':
     498             :                 case 'F':
     499             :                 case 'g':
     500             :                 case 'G':
     501           0 :                         if (flags & LONGDBL) {
     502           0 :                                 long double arg = GETARG(long double);
     503           0 :                                 char fmt[6] = "%.*L";
     504           0 :                                 fmt[4] = ch;
     505           0 :                                 fmt[5] = '\0';
     506             : 
     507             : #pragma GCC diagnostic push
     508             : #pragma GCC diagnostic ignored "-Wformat-nonliteral"
     509           0 :                                 snprintf(buf, sizeof(buf), fmt, prec, arg);
     510             : #pragma GCC diagnostic pop
     511             :                         } else {
     512           0 :                                 double arg = GETARG(double);
     513           0 :                                 char fmt[5] = "%.*";
     514           0 :                                 fmt[3] = ch;
     515           0 :                                 fmt[4] = '\0';
     516             : 
     517             : #pragma GCC diagnostic push
     518             : #pragma GCC diagnostic ignored "-Wformat-nonliteral"
     519           0 :                                 snprintf(buf, sizeof(buf), fmt, prec, arg);
     520             : #pragma GCC diagnostic pop
     521             :                         }
     522           0 :                         cp = buf;
     523             :                         /* for proper padding */
     524           0 :                         if (*cp == '-') {
     525           0 :                                 cp++;
     526           0 :                                 sign = '-';
     527             :                         }
     528             :                         /* "inf" */
     529           0 :                         if (!is_digit(*cp) && *cp != '.')
     530           0 :                                 flags &= ~ZEROPAD;
     531           0 :                         size = strlen(buf);
     532           0 :                         break;
     533             : #endif
     534           0 :                 case 'm':
     535           0 :                         cp = strerror(saved_errno);
     536           0 :                         size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
     537           0 :                         sign = '\0';
     538           0 :                         break;
     539           0 :                 case 'O':
     540           0 :                         flags |= LONGINT;
     541             :                         /*FALLTHROUGH*/
     542           0 :                 case 'o':
     543           0 :                         if (flags & INTMAX_SIZE)
     544           0 :                                 ujval = UJARG();
     545             :                         else
     546           0 :                                 ulval = UARG();
     547           0 :                         base = 8;
     548           0 :                         goto nosign;
     549          40 :                 case 'p':
     550             :                         /*-
     551             :                          * ``The argument shall be a pointer to void.  The
     552             :                          * value of the pointer is converted to a sequence
     553             :                          * of printable characters, in an implementation-
     554             :                          * defined manner.''
     555             :                          *      -- ANSI X3J11
     556             :                          */
     557          40 :                         ptrval = GETARG(void *);
     558          40 :                         if (printfrr_ext_char(fmt[0])) {
     559          40 :                                 struct printfrr_eargs ea = {
     560             :                                         .fmt = fmt,
     561             :                                         .precision = prec,
     562             :                                         .width = width,
     563          40 :                                         .alt_repr = !!(flags & ALT),
     564          40 :                                         .leftadj = !!(flags & LADJUST),
     565             :                                 };
     566             : 
     567          40 :                                 if (cb)
     568          40 :                                         extstart = cb->pos;
     569             : 
     570          40 :                                 size = printfrr_extp(cb, &ea, ptrval);
     571          40 :                                 if (size >= 0) {
     572          40 :                                         fmt = ea.fmt;
     573          40 :                                         width = ea.width;
     574          40 :                                         goto ext_printed;
     575             :                                 }
     576             :                         }
     577           0 :                         ujval = (uintmax_t)(uintptr_t)ptrval;
     578           0 :                         base = 16;
     579           0 :                         xdigs = xdigs_lower;
     580           0 :                         flags = flags | INTMAXT;
     581           0 :                         ox[1] = 'x';
     582           0 :                         goto nosign;
     583           0 :                 case 'S':
     584           0 :                         flags |= LONGINT;
     585             :                         /*FALLTHROUGH*/
     586         394 :                 case 's':
     587             : #ifdef WCHAR_SUPPORT
     588             :                         if (flags & LONGINT) {
     589             :                                 wchar_t *wcp;
     590             : 
     591             :                                 if (convbuf != NULL)
     592             :                                         free(convbuf);
     593             :                                 if ((wcp = GETARG(wchar_t *)) == NULL)
     594             :                                         cp = "(null)";
     595             :                                 else {
     596             :                                         convbuf = __wcsconv(wcp, prec);
     597             :                                         if (convbuf == NULL) {
     598             :                                                 goto error;
     599             :                                         }
     600             :                                         cp = convbuf;
     601             :                                 }
     602             :                         } else
     603             : #endif
     604         394 :                         if ((cp = GETARG(char *)) == NULL)
     605           0 :                                 cp = "(null)";
     606         394 :                         size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
     607         394 :                         sign = '\0';
     608         394 :                         break;
     609           0 :                 case 'U':
     610           0 :                         flags |= LONGINT;
     611             :                         /*FALLTHROUGH*/
     612         383 :                 case 'u':
     613         383 :                         if (flags & INTMAX_SIZE)
     614          28 :                                 ujval = UJARG();
     615             :                         else
     616         355 :                                 ulval = UARG();
     617         383 :                         base = 10;
     618         383 :                         goto nosign;
     619           0 :                 case 'X':
     620           0 :                         xdigs = xdigs_upper;
     621           0 :                         goto hex;
     622             :                 case 'x':
     623             :                         xdigs = xdigs_lower;
     624          60 : hex:
     625          60 :                         if (flags & INTMAX_SIZE)
     626          60 :                                 ujval = UJARG();
     627             :                         else
     628           0 :                                 ulval = UARG();
     629          60 :                         base = 16;
     630             :                         /* leading 0x/X only if non-zero */
     631          60 :                         if (flags & ALT &&
     632             :                             (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
     633          46 :                                 ox[1] = ch;
     634             : 
     635          60 :                         flags &= ~GROUPING;
     636             :                         /* unsigned conversions */
     637         443 : nosign:                 sign = '\0';
     638             :                         /*-
     639             :                          * ``... diouXx conversions ... if a precision is
     640             :                          * specified, the 0 flag will be ignored.''
     641             :                          *      -- ANSI X3J11
     642             :                          */
     643        1119 : number:                 if ((dprec = prec) >= 0)
     644           0 :                                 flags &= ~ZEROPAD;
     645             : 
     646             :                         /*-
     647             :                          * ``The result of converting a zero value with an
     648             :                          * explicit precision of zero is no characters.''
     649             :                          *      -- ANSI X3J11
     650             :                          *
     651             :                          * ``The C Standard is clear enough as is.  The call
     652             :                          * printf("%#.0o", 0) should print 0.''
     653             :                          *      -- Defect Report #151
     654             :                          */
     655        1119 :                         cp = buf + BUF;
     656        1119 :                         if (flags & INTMAX_SIZE) {
     657         102 :                                 if (ujval != 0 || prec != 0 ||
     658           0 :                                     (flags & ALT && base == 8))
     659         102 :                                         cp = __ujtoa(ujval, buf + BUF, base,
     660             :                                             flags & ALT, xdigs);
     661             :                         } else {
     662        1017 :                                 if (ulval != 0 || prec != 0 ||
     663           0 :                                     (flags & ALT && base == 8))
     664        1017 :                                         cp = __ultoa(ulval, buf + BUF, base,
     665             :                                             flags & ALT, xdigs);
     666             :                         }
     667        1119 :                         size = buf + BUF - cp;
     668        1119 :                         if (size > BUF)      /* should never happen */
     669           0 :                                 abort();
     670             :                         break;
     671           2 :                 default:        /* "%?" prints ?, unless ? is NUL */
     672           2 :                         if (ch == '\0')
     673           0 :                                 goto done;
     674             :                         /* pretend it was %c with argument ch */
     675           2 :                         buf[0] = ch;
     676           2 :                         cp = buf;
     677           2 :                         size = 1;
     678           2 :                         sign = '\0';
     679           2 :                         opos = NULL;
     680           2 :                         break;
     681             :                 }
     682             : 
     683             :                 /*
     684             :                  * All reasonable formats wind up here.  At this point, `cp'
     685             :                  * points to a string which (if not flags&LADJUST) should be
     686             :                  * padded out to `width' places.  If flags&ZEROPAD, it should
     687             :                  * first be prefixed by any sign or other prefix; otherwise,
     688             :                  * it should be blank padded before the prefix is emitted.
     689             :                  * After any left-hand padding and prefixing, emit zeroes
     690             :                  * required by a decimal [diouxX] precision, then print the
     691             :                  * string proper, then emit zeroes required by any leftover
     692             :                  * floating precision; finally, if LADJUST, pad with blanks.
     693             :                  *
     694             :                  * Compute actual size, so we know how much to pad.
     695             :                  * size excludes decimal prec; realsz includes it.
     696             :                  */
     697        1515 :                 if (width < 0)
     698             :                         width = 0;
     699             : 
     700        1515 :                 realsz = dprec > size ? dprec : size;
     701        1515 :                 if (sign)
     702         216 :                         realsz++;
     703        1515 :                 if (ox[1])
     704          46 :                         realsz += 2;
     705             : 
     706        1515 :                 prsize = width > realsz ? width : realsz;
     707        1515 :                 if ((unsigned int)ret + prsize > INT_MAX) {
     708           0 :                         ret = EOF;
     709           0 :                         errno = EOVERFLOW;
     710           0 :                         goto error;
     711             :                 }
     712             : 
     713             :                 /* right-adjusting blank padding */
     714        1515 :                 if ((flags & (LADJUST|ZEROPAD)) == 0)
     715         833 :                         PAD(width - realsz, blanks);
     716             : 
     717        1515 :                 if (opos)
     718         728 :                         opos->off_start = cb->pos - cb->buf;
     719             : 
     720             :                 /* prefix */
     721        1515 :                 if (sign)
     722         216 :                         PRINT(&sign, 1);
     723             : 
     724        1515 :                 if (ox[1]) {    /* ox[1] is either x, X, or \0 */
     725          46 :                         ox[0] = '0';
     726          46 :                         PRINT(ox, 2);
     727             :                 }
     728             : 
     729             :                 /* right-adjusting zero padding */
     730        1515 :                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
     731         648 :                         PAD(width - realsz, zeroes);
     732             : 
     733             :                 /* the string or number proper */
     734             :                 /* leading zeroes from decimal precision */
     735        1515 :                 PAD(dprec - size, zeroes);
     736        1515 :                 PRINT(cp, size);
     737             : 
     738        1515 :                 if (opos) {
     739         728 :                         opos->off_end = cb->pos - cb->buf;
     740         728 :                         cb_in->outpos_i++;
     741             :                 }
     742             : 
     743             :                 /* left-adjusting padding (always blank) */
     744        1515 :                 if (flags & LADJUST)
     745          34 :                         PAD(width - realsz, blanks);
     746             : 
     747             :                 /* finally, adjust ret */
     748        1515 :                 ret += prsize;
     749             : 
     750        1515 :                 FLUSH();        /* copy out the I/O vectors */
     751        1515 :                 continue;
     752             : 
     753          40 : ext_printed:
     754             :                 /* when we arrive here, a printfrr extension has written to cb
     755             :                  * (if non-NULL), but we still need to handle padding.  The
     756             :                  * original cb->pos is in extstart;  the return value from the
     757             :                  * ext is in size.
     758             :                  *
     759             :                  * Keep analogous to code above please.
     760             :                  */
     761             : 
     762          40 :                 if (width < 0)
     763             :                         width = 0;
     764             : 
     765          40 :                 realsz = size;
     766          40 :                 prsize = width > realsz ? width : realsz;
     767          40 :                 if ((unsigned int)ret + prsize > INT_MAX) {
     768           0 :                         ret = EOF;
     769           0 :                         errno = EOVERFLOW;
     770           0 :                         goto error;
     771             :                 }
     772             : 
     773             :                 /* right-adjusting blank padding - need to move the chars
     774             :                  * that the extension has already written.  Should be very
     775             :                  * rare.
     776             :                  */
     777          40 :                 if (cb && width > size && (flags & (LADJUST|ZEROPAD)) == 0) {
     778           0 :                         size_t nwritten = cb->pos - extstart;
     779           0 :                         size_t navail = cb->buf + cb->len - extstart;
     780           0 :                         size_t npad = width - realsz;
     781           0 :                         size_t nmove;
     782             : 
     783           0 :                         if (navail < npad)
     784             :                                 navail = 0;
     785             :                         else
     786           0 :                                 navail -= npad;
     787           0 :                         nmove = MIN(nwritten, navail);
     788             : 
     789           0 :                         memmove(extstart + npad, extstart, nmove);
     790             : 
     791           0 :                         cb->pos = extstart;
     792           0 :                         PAD(npad, blanks);
     793           0 :                         cb->pos += nmove;
     794           0 :                         extstart += npad;
     795             :                 }
     796             : 
     797          40 :                 io.avail = cb ? cb->len - (cb->pos - cb->buf) : 0;
     798             : 
     799          40 :                 if (opos && extstart <= cb->pos) {
     800          38 :                         opos->off_start = extstart - cb->buf;
     801          38 :                         opos->off_end = cb->pos - cb->buf;
     802          38 :                         cb_in->outpos_i++;
     803             :                 }
     804             : 
     805             :                 /* left-adjusting padding (always blank) */
     806          40 :                 if (flags & LADJUST)
     807           0 :                         PAD(width - realsz, blanks);
     808             : 
     809             :                 /* finally, adjust ret */
     810          40 :                 ret += prsize;
     811             : 
     812             :                 FLUSH();        /* copy out the I/O vectors */
     813             :         }
     814         768 : done:
     815         768 :         FLUSH();
     816         768 : error:
     817         768 :         va_end(orgap);
     818         768 :         if (convbuf != NULL)
     819             :                 free(convbuf);
     820         768 :         if ((argtable != NULL) && (argtable != statargtable))
     821           0 :                 free (argtable);
     822         768 :         if (cb_in)
     823         768 :                 cb_in->pos = cb->pos;
     824         768 :         return (ret);
     825             :         /* NOTREACHED */
     826             : }
     827             : 

Generated by: LCOV version v1.16-topotato