LCOV - code coverage report
Current view: top level - src/port - snprintf.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 67.5 % 619 418
Test Date: 2026-03-03 14:15:12 Functions: 91.7 % 24 22
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 1983, 1995, 1996 Eric P. Allman
       3              :  * Copyright (c) 1988, 1993
       4              :  *  The Regents of the University of California.  All rights reserved.
       5              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       6              :  *
       7              :  * Redistribution and use in source and binary forms, with or without
       8              :  * modification, are permitted provided that the following conditions
       9              :  * are met:
      10              :  * 1. Redistributions of source code must retain the above copyright
      11              :  *    notice, this list of conditions and the following disclaimer.
      12              :  * 2. Redistributions in binary form must reproduce the above copyright
      13              :  *    notice, this list of conditions and the following disclaimer in the
      14              :  *    documentation and/or other materials provided with the distribution.
      15              :  * 3. Neither the name of the University nor the names of its contributors
      16              :  *    may be used to endorse or promote products derived from this software
      17              :  *    without specific prior written permission.
      18              :  *
      19              :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      20              :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      21              :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      22              :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      23              :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      24              :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      25              :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      26              :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      27              :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      28              :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      29              :  * SUCH DAMAGE.
      30              :  *
      31              :  * src/port/snprintf.c
      32              :  */
      33              : 
      34              : #include "c.h"
      35              : 
      36              : #include <math.h>
      37              : 
      38              : /*
      39              :  * We used to use the platform's NL_ARGMAX here, but that's a bad idea,
      40              :  * first because the point of this module is to remove platform dependencies
      41              :  * not perpetuate them, and second because some platforms use ridiculously
      42              :  * large values, leading to excessive stack consumption in dopr().
      43              :  */
      44              : #define PG_NL_ARGMAX 31
      45              : 
      46              : 
      47              : /*
      48              :  *  SNPRINTF, VSNPRINTF and friends
      49              :  *
      50              :  * These versions have been grabbed off the net.  They have been
      51              :  * cleaned up to compile properly and support for most of the C99
      52              :  * specification has been added.  Remaining unimplemented features are:
      53              :  *
      54              :  * 1. No locale support: the radix character is always '.' and the '
      55              :  * (single quote) format flag is ignored.
      56              :  *
      57              :  * 2. No support for the "%n" format specification.
      58              :  *
      59              :  * 3. No support for wide characters ("lc" and "ls" formats).
      60              :  *
      61              :  * 4. No support for "long double" ("Lf" and related formats).
      62              :  *
      63              :  * 5. Space and '#' flags are not implemented.
      64              :  *
      65              :  * In addition, we support some extensions over C99:
      66              :  *
      67              :  * 1. Argument order control through "%n$" and "*n$", as required by POSIX.
      68              :  *
      69              :  * 2. "%m" expands to the value of strerror(errno), where errno is the
      70              :  * value that variable had at the start of the call.  This is a glibc
      71              :  * extension, but a very useful one.
      72              :  *
      73              :  *
      74              :  * Historically the result values of sprintf/snprintf varied across platforms.
      75              :  * This implementation now follows the C99 standard:
      76              :  *
      77              :  * 1. -1 is returned if an error is detected in the format string, or if
      78              :  * a write to the target stream fails (as reported by fwrite).  Note that
      79              :  * overrunning snprintf's target buffer is *not* an error.
      80              :  *
      81              :  * 2. For successful writes to streams, the actual number of bytes written
      82              :  * to the stream is returned.
      83              :  *
      84              :  * 3. For successful sprintf/snprintf, the number of bytes that would have
      85              :  * been written to an infinite-size buffer (excluding the trailing '\0')
      86              :  * is returned.  snprintf will truncate its output to fit in the buffer
      87              :  * (ensuring a trailing '\0' unless count == 0), but this is not reflected
      88              :  * in the function result.
      89              :  *
      90              :  * snprintf buffer overrun can be detected by checking for function result
      91              :  * greater than or equal to the supplied count.
      92              :  */
      93              : 
      94              : /**************************************************************
      95              :  * Original:
      96              :  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
      97              :  * A bombproof version of doprnt (dopr) included.
      98              :  * Sigh.  This sort of thing is always nasty do deal with.  Note that
      99              :  * the version here does not include floating point. (now it does ... tgl)
     100              :  **************************************************************/
     101              : 
     102              : /* Prevent recursion */
     103              : #undef  vsnprintf
     104              : #undef  snprintf
     105              : #undef  vsprintf
     106              : #undef  sprintf
     107              : #undef  vfprintf
     108              : #undef  fprintf
     109              : #undef  vprintf
     110              : #undef  printf
     111              : 
     112              : /*
     113              :  * Info about where the formatted output is going.
     114              :  *
     115              :  * dopr and subroutines will not write at/past bufend, but snprintf
     116              :  * reserves one byte, ensuring it may place the trailing '\0' there.
     117              :  *
     118              :  * In snprintf, we use nchars to count the number of bytes dropped on the
     119              :  * floor due to buffer overrun.  The correct result of snprintf is thus
     120              :  * (bufptr - bufstart) + nchars.  (This isn't as inconsistent as it might
     121              :  * seem: nchars is the number of emitted bytes that are not in the buffer now,
     122              :  * either because we sent them to the stream or because we couldn't fit them
     123              :  * into the buffer to begin with.)
     124              :  */
     125              : typedef struct
     126              : {
     127              :     char       *bufptr;         /* next buffer output position */
     128              :     char       *bufstart;       /* first buffer element */
     129              :     char       *bufend;         /* last+1 buffer element, or NULL */
     130              :     /* bufend == NULL is for sprintf, where we assume buf is big enough */
     131              :     FILE       *stream;         /* eventual output destination, or NULL */
     132              :     int         nchars;         /* # chars sent to stream, or dropped */
     133              :     bool        failed;         /* call is a failure; errno is set */
     134              : } PrintfTarget;
     135              : 
     136              : /*
     137              :  * Info about the type and value of a formatting parameter.  Note that we
     138              :  * don't currently support "long double", "wint_t", or "wchar_t *" data,
     139              :  * nor the '%n' formatting code; else we'd need more types.  Also, at this
     140              :  * level we need not worry about signed vs unsigned values.
     141              :  */
     142              : typedef enum
     143              : {
     144              :     ATYPE_NONE = 0,
     145              :     ATYPE_INT,
     146              :     ATYPE_LONG,
     147              :     ATYPE_LONGLONG,
     148              :     ATYPE_DOUBLE,
     149              :     ATYPE_CHARPTR
     150              : } PrintfArgType;
     151              : 
     152              : typedef union
     153              : {
     154              :     int         i;
     155              :     long        l;
     156              :     long long   ll;
     157              :     double      d;
     158              :     char       *cptr;
     159              : } PrintfArgValue;
     160              : 
     161              : 
     162              : static void flushbuffer(PrintfTarget *target);
     163              : static void dopr(PrintfTarget *target, const char *format, va_list args);
     164              : 
     165              : 
     166              : /*
     167              :  * Externally visible entry points.
     168              :  *
     169              :  * All of these are just wrappers around dopr().  Note it's essential that
     170              :  * they not change the value of "errno" before reaching dopr().
     171              :  */
     172              : 
     173              : int
     174    270679065 : pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
     175              : {
     176              :     PrintfTarget target;
     177              :     char        onebyte[1];
     178              : 
     179              :     /*
     180              :      * C99 allows the case str == NULL when count == 0.  Rather than
     181              :      * special-casing this situation further down, we substitute a one-byte
     182              :      * local buffer.  Callers cannot tell, since the function result doesn't
     183              :      * depend on count.
     184              :      */
     185    270679065 :     if (count == 0)
     186              :     {
     187       129022 :         str = onebyte;
     188       129022 :         count = 1;
     189              :     }
     190    270679065 :     target.bufstart = target.bufptr = str;
     191    270679065 :     target.bufend = str + count - 1;
     192    270679065 :     target.stream = NULL;
     193    270679065 :     target.nchars = 0;
     194    270679065 :     target.failed = false;
     195    270679065 :     dopr(&target, fmt, args);
     196    270679061 :     *(target.bufptr) = '\0';
     197    541358122 :     return target.failed ? -1 : (target.bufptr - target.bufstart
     198    270679061 :                                  + target.nchars);
     199              : }
     200              : 
     201              : int
     202     25310010 : pg_snprintf(char *str, size_t count, const char *fmt,...)
     203              : {
     204              :     int         len;
     205              :     va_list     args;
     206              : 
     207     25310010 :     va_start(args, fmt);
     208     25310010 :     len = pg_vsnprintf(str, count, fmt, args);
     209     25310006 :     va_end(args);
     210     25310006 :     return len;
     211              : }
     212              : 
     213              : int
     214      9395231 : pg_vsprintf(char *str, const char *fmt, va_list args)
     215              : {
     216              :     PrintfTarget target;
     217              : 
     218      9395231 :     target.bufstart = target.bufptr = str;
     219      9395231 :     target.bufend = NULL;
     220      9395231 :     target.stream = NULL;
     221      9395231 :     target.nchars = 0;          /* not really used in this case */
     222      9395231 :     target.failed = false;
     223      9395231 :     dopr(&target, fmt, args);
     224      9395237 :     *(target.bufptr) = '\0';
     225     18790474 :     return target.failed ? -1 : (target.bufptr - target.bufstart
     226      9395237 :                                  + target.nchars);
     227              : }
     228              : 
     229              : int
     230      9395238 : pg_sprintf(char *str, const char *fmt,...)
     231              : {
     232              :     int         len;
     233              :     va_list     args;
     234              : 
     235      9395238 :     va_start(args, fmt);
     236      9395238 :     len = pg_vsprintf(str, fmt, args);
     237      9395240 :     va_end(args);
     238      9395240 :     return len;
     239              : }
     240              : 
     241              : int
     242      2338674 : pg_vfprintf(FILE *stream, const char *fmt, va_list args)
     243              : {
     244              :     PrintfTarget target;
     245              :     char        buffer[1024];   /* size is arbitrary */
     246              : 
     247      2338674 :     if (stream == NULL)
     248              :     {
     249            0 :         errno = EINVAL;
     250            0 :         return -1;
     251              :     }
     252      2338674 :     target.bufstart = target.bufptr = buffer;
     253      2338674 :     target.bufend = buffer + sizeof(buffer);    /* use the whole buffer */
     254      2338674 :     target.stream = stream;
     255      2338674 :     target.nchars = 0;
     256      2338674 :     target.failed = false;
     257      2338674 :     dopr(&target, fmt, args);
     258              :     /* dump any remaining buffer contents */
     259      2338674 :     flushbuffer(&target);
     260      2338674 :     return target.failed ? -1 : target.nchars;
     261              : }
     262              : 
     263              : int
     264      1211948 : pg_fprintf(FILE *stream, const char *fmt,...)
     265              : {
     266              :     int         len;
     267              :     va_list     args;
     268              : 
     269      1211948 :     va_start(args, fmt);
     270      1211948 :     len = pg_vfprintf(stream, fmt, args);
     271      1211948 :     va_end(args);
     272      1211948 :     return len;
     273              : }
     274              : 
     275              : int
     276            0 : pg_vprintf(const char *fmt, va_list args)
     277              : {
     278            0 :     return pg_vfprintf(stdout, fmt, args);
     279              : }
     280              : 
     281              : int
     282      1115025 : pg_printf(const char *fmt,...)
     283              : {
     284              :     int         len;
     285              :     va_list     args;
     286              : 
     287      1115025 :     va_start(args, fmt);
     288      1115025 :     len = pg_vfprintf(stdout, fmt, args);
     289      1115025 :     va_end(args);
     290      1115025 :     return len;
     291              : }
     292              : 
     293              : /*
     294              :  * Attempt to write the entire buffer to target->stream; discard the entire
     295              :  * buffer in any case.  Call this only when target->stream is defined.
     296              :  */
     297              : static void
     298      2338985 : flushbuffer(PrintfTarget *target)
     299              : {
     300      2338985 :     size_t      nc = target->bufptr - target->bufstart;
     301              : 
     302              :     /*
     303              :      * Don't write anything if we already failed; this is to ensure we
     304              :      * preserve the original failure's errno.
     305              :      */
     306      2338985 :     if (!target->failed && nc > 0)
     307              :     {
     308              :         size_t      written;
     309              : 
     310      2204424 :         written = fwrite(target->bufstart, 1, nc, target->stream);
     311      2204424 :         target->nchars += written;
     312      2204424 :         if (written != nc)
     313            0 :             target->failed = true;
     314              :     }
     315      2338985 :     target->bufptr = target->bufstart;
     316      2338985 : }
     317              : 
     318              : 
     319              : static bool find_arguments(const char *format, va_list args,
     320              :                            PrintfArgValue *argvalues);
     321              : static void fmtstr(const char *value, int leftjust, int minlen, int maxwidth,
     322              :                    int pointflag, PrintfTarget *target);
     323              : static void fmtptr(const void *value, PrintfTarget *target);
     324              : static void fmtint(long long value, char type, int forcesign,
     325              :                    int leftjust, int minlen, int zpad, int precision, int pointflag,
     326              :                    PrintfTarget *target);
     327              : static void fmtchar(int value, int leftjust, int minlen, PrintfTarget *target);
     328              : static void fmtfloat(double value, char type, int forcesign,
     329              :                      int leftjust, int minlen, int zpad, int precision, int pointflag,
     330              :                      PrintfTarget *target);
     331              : static void dostr(const char *str, int slen, PrintfTarget *target);
     332              : static void dopr_outch(int c, PrintfTarget *target);
     333              : static void dopr_outchmulti(int c, int slen, PrintfTarget *target);
     334              : static int  adjust_sign(int is_negative, int forcesign, int *signvalue);
     335              : static int  compute_padlen(int minlen, int vallen, int leftjust);
     336              : static void leading_pad(int zpad, int signvalue, int *padlen,
     337              :                         PrintfTarget *target);
     338              : static void trailing_pad(int padlen, PrintfTarget *target);
     339              : 
     340              : /*
     341              :  * If strchrnul exists (it's a glibc-ism, but since adopted by some other
     342              :  * platforms), it's a good bit faster than the equivalent manual loop.
     343              :  * Use it if possible, and if it doesn't exist, use this replacement.
     344              :  *
     345              :  * Note: glibc declares this as returning "char *", but that would require
     346              :  * casting away const internally, so we don't follow that detail.
     347              :  *
     348              :  * Note: macOS has this too as of Sequoia 15.4, but it's hidden behind
     349              :  * a deployment-target check that causes compile errors if the deployment
     350              :  * target isn't high enough.  So !HAVE_DECL_STRCHRNUL may mean "yes it's
     351              :  * declared, but it doesn't compile".  To avoid failing in that scenario,
     352              :  * use a macro to avoid matching <string.h>'s name.
     353              :  */
     354              : #if !HAVE_DECL_STRCHRNUL
     355              : 
     356              : #define strchrnul pg_strchrnul
     357              : 
     358              : static inline const char *
     359              : strchrnul(const char *s, int c)
     360              : {
     361              :     while (*s != '\0' && *s != c)
     362              :         s++;
     363              :     return s;
     364              : }
     365              : 
     366              : #endif                          /* !HAVE_DECL_STRCHRNUL */
     367              : 
     368              : 
     369              : /*
     370              :  * dopr(): the guts of *printf for all cases.
     371              :  */
     372              : static void
     373    282412957 : dopr(PrintfTarget *target, const char *format, va_list args)
     374              : {
     375    282412957 :     int         save_errno = errno;
     376    282412957 :     const char *first_pct = NULL;
     377              :     int         ch;
     378              :     bool        have_dollar;
     379              :     bool        have_star;
     380              :     bool        afterstar;
     381              :     int         accum;
     382              :     int         longlongflag;
     383              :     int         longflag;
     384              :     int         pointflag;
     385              :     int         leftjust;
     386              :     int         fieldwidth;
     387              :     int         precision;
     388              :     int         zpad;
     389              :     int         forcesign;
     390              :     int         fmtpos;
     391              :     int         cvalue;
     392              :     long long   numvalue;
     393              :     double      fvalue;
     394              :     const char *strvalue;
     395              :     PrintfArgValue argvalues[PG_NL_ARGMAX + 1];
     396              : 
     397              :     /*
     398              :      * Initially, we suppose the format string does not use %n$.  The first
     399              :      * time we come to a conversion spec that has that, we'll call
     400              :      * find_arguments() to check for consistent use of %n$ and fill the
     401              :      * argvalues array with the argument values in the correct order.
     402              :      */
     403    282412957 :     have_dollar = false;
     404              : 
     405    583048859 :     while (*format != '\0')
     406              :     {
     407              :         /* Locate next conversion specifier */
     408    378757721 :         if (*format != '%')
     409              :         {
     410              :             /* Scan to next '%' or end of string */
     411    273330433 :             const char *next_pct = strchrnul(format + 1, '%');
     412              : 
     413              :             /* Dump literal data we just scanned over */
     414    273330433 :             dostr(format, next_pct - format, target);
     415    273330445 :             if (target->failed)
     416            0 :                 break;
     417              : 
     418    273330445 :             if (*next_pct == '\0')
     419     78121821 :                 break;
     420    195208624 :             format = next_pct;
     421              :         }
     422              : 
     423              :         /*
     424              :          * Remember start of first conversion spec; if we find %n$, then it's
     425              :          * sufficient for find_arguments() to start here, without rescanning
     426              :          * earlier literal text.
     427              :          */
     428    300635912 :         if (first_pct == NULL)
     429    278205888 :             first_pct = format;
     430              : 
     431              :         /* Process conversion spec starting at *format */
     432    300635912 :         format++;
     433              : 
     434              :         /* Fast path for conversion spec that is exactly %s */
     435    300635912 :         if (*format == 's')
     436              :         {
     437     49054714 :             format++;
     438     49054714 :             strvalue = va_arg(args, char *);
     439     49054721 :             if (strvalue == NULL)
     440           22 :                 strvalue = "(null)";
     441     49054721 :             dostr(strvalue, strlen(strvalue), target);
     442     49054719 :             if (target->failed)
     443            0 :                 break;
     444     49054719 :             continue;
     445              :         }
     446              : 
     447    251581198 :         fieldwidth = precision = zpad = leftjust = forcesign = 0;
     448    251581198 :         longflag = longlongflag = pointflag = 0;
     449    251581198 :         fmtpos = accum = 0;
     450    251581198 :         have_star = afterstar = false;
     451     42159801 : nextch2:
     452    293740999 :         ch = *format++;
     453    293740999 :         switch (ch)
     454              :         {
     455       558924 :             case '-':
     456       558924 :                 leftjust = 1;
     457       558924 :                 goto nextch2;
     458          141 :             case '+':
     459          141 :                 forcesign = 1;
     460          141 :                 goto nextch2;
     461     15960420 :             case '0':
     462              :                 /* set zero padding if no nonzero digits yet */
     463     15960420 :                 if (accum == 0 && !pointflag)
     464     15675839 :                     zpad = '0';
     465              :                 pg_fallthrough;
     466              :             case '1':
     467              :             case '2':
     468              :             case '3':
     469              :             case '4':
     470              :             case '5':
     471              :             case '6':
     472              :             case '7':
     473              :             case '8':
     474              :             case '9':
     475     33678157 :                 accum = accum * 10 + (ch - '0');
     476     33678157 :                 goto nextch2;
     477       730790 :             case '.':
     478       730790 :                 if (have_star)
     479          928 :                     have_star = false;
     480              :                 else
     481       729862 :                     fieldwidth = accum;
     482       730790 :                 pointflag = 1;
     483       730790 :                 accum = 0;
     484       730790 :                 goto nextch2;
     485       745186 :             case '*':
     486       745186 :                 if (have_dollar)
     487              :                 {
     488              :                     /*
     489              :                      * We'll process value after reading n$.  Note it's OK to
     490              :                      * assume have_dollar is set correctly, because in a valid
     491              :                      * format string the initial % must have had n$ if * does.
     492              :                      */
     493            0 :                     afterstar = true;
     494              :                 }
     495              :                 else
     496              :                 {
     497              :                     /* fetch and process value now */
     498       745186 :                     int         starval = va_arg(args, int);
     499              : 
     500       745186 :                     if (pointflag)
     501              :                     {
     502        30602 :                         precision = starval;
     503        30602 :                         if (precision < 0)
     504              :                         {
     505            0 :                             precision = 0;
     506            0 :                             pointflag = 0;
     507              :                         }
     508              :                     }
     509              :                     else
     510              :                     {
     511       714584 :                         fieldwidth = starval;
     512       714584 :                         if (fieldwidth < 0)
     513              :                         {
     514         2823 :                             leftjust = 1;
     515         2823 :                             fieldwidth = -fieldwidth;
     516              :                         }
     517              :                     }
     518              :                 }
     519       745186 :                 have_star = true;
     520       745186 :                 accum = 0;
     521       745186 :                 goto nextch2;
     522            0 :             case '$':
     523              :                 /* First dollar sign? */
     524            0 :                 if (!have_dollar)
     525              :                 {
     526              :                     /* Yup, so examine all conversion specs in format */
     527            0 :                     if (!find_arguments(first_pct, args, argvalues))
     528           11 :                         goto bad_format;
     529            0 :                     have_dollar = true;
     530              :                 }
     531            0 :                 if (afterstar)
     532              :                 {
     533              :                     /* fetch and process star value */
     534            0 :                     int         starval = argvalues[accum].i;
     535              : 
     536            0 :                     if (pointflag)
     537              :                     {
     538            0 :                         precision = starval;
     539            0 :                         if (precision < 0)
     540              :                         {
     541            0 :                             precision = 0;
     542            0 :                             pointflag = 0;
     543              :                         }
     544              :                     }
     545              :                     else
     546              :                     {
     547            0 :                         fieldwidth = starval;
     548            0 :                         if (fieldwidth < 0)
     549              :                         {
     550            0 :                             leftjust = 1;
     551            0 :                             fieldwidth = -fieldwidth;
     552              :                         }
     553              :                     }
     554            0 :                     afterstar = false;
     555              :                 }
     556              :                 else
     557            0 :                     fmtpos = accum;
     558            0 :                 accum = 0;
     559            0 :                 goto nextch2;
     560      4912793 :             case 'l':
     561      4912793 :                 if (longflag)
     562         4636 :                     longlongflag = 1;
     563              :                 else
     564      4908157 :                     longflag = 1;
     565      4912793 :                 goto nextch2;
     566            0 :             case 'j':
     567              : #if SIZEOF_INTMAX_T == SIZEOF_LONG
     568            0 :                 longflag = 1;
     569              : #elif SIZEOF_INTMAX_T == SIZEOF_LONG_LONG
     570              :                 longlongflag = 1;
     571              : #else
     572              : #error "cannot find integer type of the same size as intmax_t"
     573              : #endif
     574            0 :                 goto nextch2;
     575      1533777 :             case 'z':
     576              : #if SIZEOF_SIZE_T == SIZEOF_LONG
     577      1533777 :                 longflag = 1;
     578              : #elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
     579              :                 longlongflag = 1;
     580              : #else
     581              : #error "cannot find integer type of the same size as size_t"
     582              : #endif
     583      1533777 :                 goto nextch2;
     584           44 :             case 'h':
     585              :             case '\'':
     586              :                 /* ignore these */
     587           44 :                 goto nextch2;
     588    166388699 :             case 'd':
     589              :             case 'i':
     590    166388699 :                 if (!have_star)
     591              :                 {
     592    166367701 :                     if (pointflag)
     593            0 :                         precision = accum;
     594              :                     else
     595    166367701 :                         fieldwidth = accum;
     596              :                 }
     597    166388699 :                 if (have_dollar)
     598              :                 {
     599            0 :                     if (longlongflag)
     600            0 :                         numvalue = argvalues[fmtpos].ll;
     601            0 :                     else if (longflag)
     602            0 :                         numvalue = argvalues[fmtpos].l;
     603              :                     else
     604            0 :                         numvalue = argvalues[fmtpos].i;
     605              :                 }
     606              :                 else
     607              :                 {
     608    166388699 :                     if (longlongflag)
     609         4618 :                         numvalue = va_arg(args, long long);
     610    166384081 :                     else if (longflag)
     611      3921598 :                         numvalue = va_arg(args, long);
     612              :                     else
     613    162462483 :                         numvalue = va_arg(args, int);
     614              :                 }
     615    166388699 :                 fmtint(numvalue, ch, forcesign, leftjust, fieldwidth, zpad,
     616              :                        precision, pointflag, target);
     617    166388717 :                 break;
     618     82938667 :             case 'o':
     619              :             case 'u':
     620              :             case 'x':
     621              :             case 'X':
     622     82938667 :                 if (!have_star)
     623              :                 {
     624     82938667 :                     if (pointflag)
     625            0 :                         precision = accum;
     626              :                     else
     627     82938667 :                         fieldwidth = accum;
     628              :                 }
     629     82938667 :                 if (have_dollar)
     630              :                 {
     631            0 :                     if (longlongflag)
     632            0 :                         numvalue = (unsigned long long) argvalues[fmtpos].ll;
     633            0 :                     else if (longflag)
     634            0 :                         numvalue = (unsigned long) argvalues[fmtpos].l;
     635              :                     else
     636            0 :                         numvalue = (unsigned int) argvalues[fmtpos].i;
     637              :                 }
     638              :                 else
     639              :                 {
     640     82938667 :                     if (longlongflag)
     641           18 :                         numvalue = (unsigned long long) va_arg(args, long long);
     642     82938649 :                     else if (longflag)
     643      2515700 :                         numvalue = (unsigned long) va_arg(args, long);
     644              :                     else
     645     80422949 :                         numvalue = (unsigned int) va_arg(args, int);
     646              :                 }
     647     82938667 :                 fmtint(numvalue, ch, forcesign, leftjust, fieldwidth, zpad,
     648              :                        precision, pointflag, target);
     649     82938667 :                 break;
     650        20204 :             case 'c':
     651        20204 :                 if (!have_star)
     652              :                 {
     653        20183 :                     if (pointflag)
     654            0 :                         precision = accum;
     655              :                     else
     656        20183 :                         fieldwidth = accum;
     657              :                 }
     658        20204 :                 if (have_dollar)
     659            0 :                     cvalue = (unsigned char) argvalues[fmtpos].i;
     660              :                 else
     661        20204 :                     cvalue = (unsigned char) va_arg(args, int);
     662        20204 :                 fmtchar(cvalue, leftjust, fieldwidth, target);
     663        20204 :                 break;
     664       998416 :             case 's':
     665       998416 :                 if (!have_star)
     666              :                 {
     667       295397 :                     if (pointflag)
     668            0 :                         precision = accum;
     669              :                     else
     670       295397 :                         fieldwidth = accum;
     671              :                 }
     672       998416 :                 if (have_dollar)
     673            0 :                     strvalue = argvalues[fmtpos].cptr;
     674              :                 else
     675       998416 :                     strvalue = va_arg(args, char *);
     676              :                 /* If string is NULL, silently substitute "(null)" */
     677       998416 :                 if (strvalue == NULL)
     678            0 :                     strvalue = "(null)";
     679       998416 :                 fmtstr(strvalue, leftjust, fieldwidth, precision, pointflag,
     680              :                        target);
     681       998416 :                 break;
     682          201 :             case 'p':
     683              :                 /* fieldwidth/leftjust are ignored ... */
     684          201 :                 if (have_dollar)
     685            0 :                     strvalue = argvalues[fmtpos].cptr;
     686              :                 else
     687          201 :                     strvalue = va_arg(args, char *);
     688          201 :                 fmtptr((const void *) strvalue, target);
     689          201 :                 break;
     690       955049 :             case 'e':
     691              :             case 'E':
     692              :             case 'f':
     693              :             case 'g':
     694              :             case 'G':
     695       955049 :                 if (!have_star)
     696              :                 {
     697       934831 :                     if (pointflag)
     698       700188 :                         precision = accum;
     699              :                     else
     700       234643 :                         fieldwidth = accum;
     701              :                 }
     702       955049 :                 if (have_dollar)
     703            0 :                     fvalue = argvalues[fmtpos].d;
     704              :                 else
     705       955049 :                     fvalue = va_arg(args, double);
     706       955049 :                 fmtfloat(fvalue, ch, forcesign, leftjust,
     707              :                          fieldwidth, zpad,
     708              :                          precision, pointflag,
     709              :                          target);
     710       955049 :                 break;
     711          223 :             case 'm':
     712              :                 {
     713              :                     char        errbuf[PG_STRERROR_R_BUFLEN];
     714          223 :                     const char *errm = strerror_r(save_errno,
     715              :                                                   errbuf, sizeof(errbuf));
     716              : 
     717          223 :                     dostr(errm, strlen(errm), target);
     718              :                 }
     719          218 :                 break;
     720       279728 :             case '%':
     721       279728 :                 dopr_outch('%', target);
     722       279728 :                 break;
     723            0 :             default:
     724              : 
     725              :                 /*
     726              :                  * Anything else --- in particular, '\0' indicating end of
     727              :                  * format string --- is bogus.
     728              :                  */
     729            0 :                 goto bad_format;
     730              :         }
     731              : 
     732              :         /* Check for failure after each conversion spec */
     733    251581183 :         if (target->failed)
     734            0 :             break;
     735              :     }
     736              : 
     737    282412959 :     return;
     738              : 
     739           11 : bad_format:
     740           11 :     errno = EINVAL;
     741           11 :     target->failed = true;
     742              : }
     743              : 
     744              : /*
     745              :  * find_arguments(): sort out the arguments for a format spec with %n$
     746              :  *
     747              :  * If format is valid, return true and fill argvalues[i] with the value
     748              :  * for the conversion spec that has %i$ or *i$.  Else return false.
     749              :  */
     750              : static bool
     751            0 : find_arguments(const char *format, va_list args,
     752              :                PrintfArgValue *argvalues)
     753              : {
     754              :     int         ch;
     755              :     bool        afterstar;
     756              :     int         accum;
     757              :     int         longlongflag;
     758              :     int         longflag;
     759              :     int         fmtpos;
     760              :     int         i;
     761            0 :     int         last_dollar = 0;    /* Init to "no dollar arguments known" */
     762            0 :     PrintfArgType argtypes[PG_NL_ARGMAX + 1] = {0};
     763              : 
     764              :     /*
     765              :      * This loop must accept the same format strings as the one in dopr().
     766              :      * However, we don't need to analyze them to the same level of detail.
     767              :      *
     768              :      * Since we're only called if there's a dollar-type spec somewhere, we can
     769              :      * fail immediately if we find a non-dollar spec.  Per the C99 standard,
     770              :      * all argument references in the format string must be one or the other.
     771              :      */
     772            0 :     while (*format != '\0')
     773              :     {
     774              :         /* Locate next conversion specifier */
     775            0 :         if (*format != '%')
     776              :         {
     777              :             /* Unlike dopr, we can just quit if there's no more specifiers */
     778            0 :             format = strchr(format + 1, '%');
     779            0 :             if (format == NULL)
     780            0 :                 break;
     781              :         }
     782              : 
     783              :         /* Process conversion spec starting at *format */
     784            0 :         format++;
     785            0 :         longflag = longlongflag = 0;
     786            0 :         fmtpos = accum = 0;
     787            0 :         afterstar = false;
     788            0 : nextch1:
     789            0 :         ch = *format++;
     790            0 :         switch (ch)
     791              :         {
     792            0 :             case '-':
     793              :             case '+':
     794            0 :                 goto nextch1;
     795            0 :             case '0':
     796              :             case '1':
     797              :             case '2':
     798              :             case '3':
     799              :             case '4':
     800              :             case '5':
     801              :             case '6':
     802              :             case '7':
     803              :             case '8':
     804              :             case '9':
     805            0 :                 accum = accum * 10 + (ch - '0');
     806            0 :                 goto nextch1;
     807            0 :             case '.':
     808            0 :                 accum = 0;
     809            0 :                 goto nextch1;
     810            0 :             case '*':
     811            0 :                 if (afterstar)
     812            0 :                     return false;   /* previous star missing dollar */
     813            0 :                 afterstar = true;
     814            0 :                 accum = 0;
     815            0 :                 goto nextch1;
     816            0 :             case '$':
     817            0 :                 if (accum <= 0 || accum > PG_NL_ARGMAX)
     818            0 :                     return false;
     819            0 :                 if (afterstar)
     820              :                 {
     821            0 :                     if (argtypes[accum] &&
     822            0 :                         argtypes[accum] != ATYPE_INT)
     823            0 :                         return false;
     824            0 :                     argtypes[accum] = ATYPE_INT;
     825            0 :                     last_dollar = Max(last_dollar, accum);
     826            0 :                     afterstar = false;
     827              :                 }
     828              :                 else
     829            0 :                     fmtpos = accum;
     830            0 :                 accum = 0;
     831            0 :                 goto nextch1;
     832            0 :             case 'l':
     833            0 :                 if (longflag)
     834            0 :                     longlongflag = 1;
     835              :                 else
     836            0 :                     longflag = 1;
     837            0 :                 goto nextch1;
     838            0 :             case 'j':
     839              : #if SIZEOF_INTMAX_T == SIZEOF_LONG
     840            0 :                 longflag = 1;
     841              : #elif SIZEOF_INTMAX_T == SIZEOF_LONG_LONG
     842              :                 longlongflag = 1;
     843              : #else
     844              : #error "cannot find integer type of the same size as intmax_t"
     845              : #endif
     846            0 :                 goto nextch1;
     847            0 :             case 'z':
     848              : #if SIZEOF_SIZE_T == SIZEOF_LONG
     849            0 :                 longflag = 1;
     850              : #elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
     851              :                 longlongflag = 1;
     852              : #else
     853              : #error "cannot find integer type of the same size as size_t"
     854              : #endif
     855            0 :                 goto nextch1;
     856            0 :             case 'h':
     857              :             case '\'':
     858              :                 /* ignore these */
     859            0 :                 goto nextch1;
     860            0 :             case 'd':
     861              :             case 'i':
     862              :             case 'o':
     863              :             case 'u':
     864              :             case 'x':
     865              :             case 'X':
     866            0 :                 if (fmtpos)
     867              :                 {
     868              :                     PrintfArgType atype;
     869              : 
     870            0 :                     if (longlongflag)
     871            0 :                         atype = ATYPE_LONGLONG;
     872            0 :                     else if (longflag)
     873            0 :                         atype = ATYPE_LONG;
     874              :                     else
     875            0 :                         atype = ATYPE_INT;
     876            0 :                     if (argtypes[fmtpos] &&
     877            0 :                         argtypes[fmtpos] != atype)
     878            0 :                         return false;
     879            0 :                     argtypes[fmtpos] = atype;
     880            0 :                     last_dollar = Max(last_dollar, fmtpos);
     881              :                 }
     882              :                 else
     883            0 :                     return false;   /* non-dollar conversion spec */
     884            0 :                 break;
     885            0 :             case 'c':
     886            0 :                 if (fmtpos)
     887              :                 {
     888            0 :                     if (argtypes[fmtpos] &&
     889            0 :                         argtypes[fmtpos] != ATYPE_INT)
     890            0 :                         return false;
     891            0 :                     argtypes[fmtpos] = ATYPE_INT;
     892            0 :                     last_dollar = Max(last_dollar, fmtpos);
     893              :                 }
     894              :                 else
     895            0 :                     return false;   /* non-dollar conversion spec */
     896            0 :                 break;
     897            0 :             case 's':
     898              :             case 'p':
     899            0 :                 if (fmtpos)
     900              :                 {
     901            0 :                     if (argtypes[fmtpos] &&
     902            0 :                         argtypes[fmtpos] != ATYPE_CHARPTR)
     903            0 :                         return false;
     904            0 :                     argtypes[fmtpos] = ATYPE_CHARPTR;
     905            0 :                     last_dollar = Max(last_dollar, fmtpos);
     906              :                 }
     907              :                 else
     908            0 :                     return false;   /* non-dollar conversion spec */
     909            0 :                 break;
     910            0 :             case 'e':
     911              :             case 'E':
     912              :             case 'f':
     913              :             case 'g':
     914              :             case 'G':
     915            0 :                 if (fmtpos)
     916              :                 {
     917            0 :                     if (argtypes[fmtpos] &&
     918            0 :                         argtypes[fmtpos] != ATYPE_DOUBLE)
     919            0 :                         return false;
     920            0 :                     argtypes[fmtpos] = ATYPE_DOUBLE;
     921            0 :                     last_dollar = Max(last_dollar, fmtpos);
     922              :                 }
     923              :                 else
     924            0 :                     return false;   /* non-dollar conversion spec */
     925            0 :                 break;
     926            0 :             case 'm':
     927              :             case '%':
     928            0 :                 break;
     929            0 :             default:
     930            0 :                 return false;   /* bogus format string */
     931              :         }
     932              : 
     933              :         /*
     934              :          * If we finish the spec with afterstar still set, there's a
     935              :          * non-dollar star in there.
     936              :          */
     937            0 :         if (afterstar)
     938            0 :             return false;       /* non-dollar conversion spec */
     939              :     }
     940              : 
     941              :     /*
     942              :      * Format appears valid so far, so collect the arguments in physical
     943              :      * order.  (Since we rejected any non-dollar specs that would have
     944              :      * collected arguments, we know that dopr() hasn't collected any yet.)
     945              :      */
     946            0 :     for (i = 1; i <= last_dollar; i++)
     947              :     {
     948            0 :         switch (argtypes[i])
     949              :         {
     950            0 :             case ATYPE_NONE:
     951            0 :                 return false;
     952            0 :             case ATYPE_INT:
     953            0 :                 argvalues[i].i = va_arg(args, int);
     954            0 :                 break;
     955            0 :             case ATYPE_LONG:
     956            0 :                 argvalues[i].l = va_arg(args, long);
     957            0 :                 break;
     958            0 :             case ATYPE_LONGLONG:
     959            0 :                 argvalues[i].ll = va_arg(args, long long);
     960            0 :                 break;
     961            0 :             case ATYPE_DOUBLE:
     962            0 :                 argvalues[i].d = va_arg(args, double);
     963            0 :                 break;
     964            0 :             case ATYPE_CHARPTR:
     965            0 :                 argvalues[i].cptr = va_arg(args, char *);
     966            0 :                 break;
     967              :         }
     968              :     }
     969              : 
     970            0 :     return true;
     971              : }
     972              : 
     973              : static void
     974       998416 : fmtstr(const char *value, int leftjust, int minlen, int maxwidth,
     975              :        int pointflag, PrintfTarget *target)
     976              : {
     977              :     int         padlen,
     978              :                 vallen;         /* amount to pad */
     979              : 
     980              :     /*
     981              :      * If a maxwidth (precision) is specified, we must not fetch more bytes
     982              :      * than that.
     983              :      */
     984       998416 :     if (pointflag)
     985        10384 :         vallen = strnlen(value, maxwidth);
     986              :     else
     987       988032 :         vallen = strlen(value);
     988              : 
     989       998416 :     padlen = compute_padlen(minlen, vallen, leftjust);
     990              : 
     991       998416 :     if (padlen > 0)
     992              :     {
     993       301287 :         dopr_outchmulti(' ', padlen, target);
     994       301287 :         padlen = 0;
     995              :     }
     996              : 
     997       998416 :     dostr(value, vallen, target);
     998              : 
     999       998416 :     trailing_pad(padlen, target);
    1000       998416 : }
    1001              : 
    1002              : static void
    1003          201 : fmtptr(const void *value, PrintfTarget *target)
    1004              : {
    1005              :     int         vallen;
    1006              :     char        convert[64];
    1007              : 
    1008              :     /* we rely on regular C library's snprintf to do the basic conversion */
    1009          201 :     vallen = snprintf(convert, sizeof(convert), "%p", value);
    1010          201 :     if (vallen < 0)
    1011            0 :         target->failed = true;
    1012              :     else
    1013          201 :         dostr(convert, vallen, target);
    1014          201 : }
    1015              : 
    1016              : static void
    1017    249327364 : fmtint(long long value, char type, int forcesign, int leftjust,
    1018              :        int minlen, int zpad, int precision, int pointflag,
    1019              :        PrintfTarget *target)
    1020              : {
    1021              :     unsigned long long uvalue;
    1022              :     int         base;
    1023              :     int         dosign;
    1024    249327364 :     const char *cvt = "0123456789abcdef";
    1025    249327364 :     int         signvalue = 0;
    1026              :     char        convert[64];
    1027    249327364 :     int         vallen = 0;
    1028              :     int         padlen;         /* amount to pad */
    1029              :     int         zeropad;        /* extra leading zeroes */
    1030              : 
    1031    249327364 :     switch (type)
    1032              :     {
    1033    166388700 :         case 'd':
    1034              :         case 'i':
    1035    166388700 :             base = 10;
    1036    166388700 :             dosign = 1;
    1037    166388700 :             break;
    1038         5806 :         case 'o':
    1039         5806 :             base = 8;
    1040         5806 :             dosign = 0;
    1041         5806 :             break;
    1042     73733129 :         case 'u':
    1043     73733129 :             base = 10;
    1044     73733129 :             dosign = 0;
    1045     73733129 :             break;
    1046        34894 :         case 'x':
    1047        34894 :             base = 16;
    1048        34894 :             dosign = 0;
    1049        34894 :             break;
    1050      9164838 :         case 'X':
    1051      9164838 :             cvt = "0123456789ABCDEF";
    1052      9164838 :             base = 16;
    1053      9164838 :             dosign = 0;
    1054      9164838 :             break;
    1055            0 :         default:
    1056            0 :             return;             /* keep compiler quiet */
    1057              :     }
    1058              : 
    1059              :     /* disable MSVC warning about applying unary minus to an unsigned value */
    1060              : #ifdef _MSC_VER
    1061              : #pragma warning(push)
    1062              : #pragma warning(disable: 4146)
    1063              : #endif
    1064              :     /* Handle +/- */
    1065    249327367 :     if (dosign && adjust_sign((value < 0), forcesign, &signvalue))
    1066     18405997 :         uvalue = -(unsigned long long) value;
    1067              :     else
    1068    230921371 :         uvalue = (unsigned long long) value;
    1069              : #ifdef _MSC_VER
    1070              : #pragma warning(pop)
    1071              : #endif
    1072              : 
    1073              :     /*
    1074              :      * SUS: the result of converting 0 with an explicit precision of 0 is no
    1075              :      * characters
    1076              :      */
    1077    249327368 :     if (value == 0 && pointflag && precision == 0)
    1078            0 :         vallen = 0;
    1079              :     else
    1080              :     {
    1081              :         /*
    1082              :          * Convert integer to string.  We special-case each of the possible
    1083              :          * base values so as to avoid general-purpose divisions.  On most
    1084              :          * machines, division by a fixed constant can be done much more
    1085              :          * cheaply than a general divide.
    1086              :          */
    1087    249327368 :         if (base == 10)
    1088              :         {
    1089              :             do
    1090              :             {
    1091    415651278 :                 convert[sizeof(convert) - (++vallen)] = cvt[uvalue % 10];
    1092    415651278 :                 uvalue = uvalue / 10;
    1093    415651278 :             } while (uvalue);
    1094              :         }
    1095      9205538 :         else if (base == 16)
    1096              :         {
    1097              :             do
    1098              :             {
    1099     34776901 :                 convert[sizeof(convert) - (++vallen)] = cvt[uvalue % 16];
    1100     34776901 :                 uvalue = uvalue / 16;
    1101     34776901 :             } while (uvalue);
    1102              :         }
    1103              :         else                    /* base == 8 */
    1104              :         {
    1105              :             do
    1106              :             {
    1107        17418 :                 convert[sizeof(convert) - (++vallen)] = cvt[uvalue % 8];
    1108        17418 :                 uvalue = uvalue / 8;
    1109        17418 :             } while (uvalue);
    1110              :         }
    1111              :     }
    1112              : 
    1113    249327368 :     zeropad = Max(0, precision - vallen);
    1114              : 
    1115    249327368 :     padlen = compute_padlen(minlen, vallen + zeropad, leftjust);
    1116              : 
    1117    249327369 :     leading_pad(zpad, signvalue, &padlen, target);
    1118              : 
    1119    249327364 :     if (zeropad > 0)
    1120            0 :         dopr_outchmulti('0', zeropad, target);
    1121              : 
    1122    249327364 :     dostr(convert + sizeof(convert) - vallen, vallen, target);
    1123              : 
    1124    249327373 :     trailing_pad(padlen, target);
    1125              : }
    1126              : 
    1127              : static void
    1128        20204 : fmtchar(int value, int leftjust, int minlen, PrintfTarget *target)
    1129              : {
    1130              :     int         padlen;         /* amount to pad */
    1131              : 
    1132        20204 :     padlen = compute_padlen(minlen, 1, leftjust);
    1133              : 
    1134        20204 :     if (padlen > 0)
    1135              :     {
    1136           21 :         dopr_outchmulti(' ', padlen, target);
    1137           21 :         padlen = 0;
    1138              :     }
    1139              : 
    1140        20204 :     dopr_outch(value, target);
    1141              : 
    1142        20204 :     trailing_pad(padlen, target);
    1143        20204 : }
    1144              : 
    1145              : static void
    1146       955049 : fmtfloat(double value, char type, int forcesign, int leftjust,
    1147              :          int minlen, int zpad, int precision, int pointflag,
    1148              :          PrintfTarget *target)
    1149              : {
    1150       955049 :     int         signvalue = 0;
    1151              :     int         prec;
    1152              :     int         vallen;
    1153              :     char        fmt[8];
    1154              :     char        convert[1024];
    1155       955049 :     int         zeropadlen = 0; /* amount to pad with zeroes */
    1156              :     int         padlen;         /* amount to pad with spaces */
    1157              : 
    1158              :     /*
    1159              :      * We rely on the regular C library's snprintf to do the basic conversion,
    1160              :      * then handle padding considerations here.
    1161              :      *
    1162              :      * The dynamic range of "double" is about 1E+-308 for IEEE math, and not
    1163              :      * too wildly more than that with other hardware.  In "f" format, snprintf
    1164              :      * could therefore generate at most 308 characters to the left of the
    1165              :      * decimal point; while we need to allow the precision to get as high as
    1166              :      * 308+17 to ensure that we don't truncate significant digits from very
    1167              :      * small values.  To handle both these extremes, we use a buffer of 1024
    1168              :      * bytes and limit requested precision to 350 digits; this should prevent
    1169              :      * buffer overrun even with non-IEEE math.  If the original precision
    1170              :      * request was more than 350, separately pad with zeroes.
    1171              :      *
    1172              :      * We handle infinities and NaNs specially to ensure platform-independent
    1173              :      * output.
    1174              :      */
    1175       955049 :     if (precision < 0)           /* cover possible overflow of "accum" */
    1176            0 :         precision = 0;
    1177       955049 :     prec = Min(precision, 350);
    1178              : 
    1179       955049 :     if (isnan(value))
    1180              :     {
    1181           27 :         strcpy(convert, "NaN");
    1182           27 :         vallen = 3;
    1183              :         /* no zero padding, regardless of precision spec */
    1184              :     }
    1185              :     else
    1186              :     {
    1187              :         /*
    1188              :          * Handle sign (NaNs have no sign, so we don't do this in the case
    1189              :          * above).  "value < 0.0" will not be true for IEEE minus zero, so we
    1190              :          * detect that by looking for the case where value equals 0.0
    1191              :          * according to == but not according to memcmp.
    1192              :          */
    1193              :         static const double dzero = 0.0;
    1194              : 
    1195      1902632 :         if (adjust_sign((value < 0.0 ||
    1196       947610 :                          (value == 0.0 &&
    1197       315655 :                           memcmp(&value, &dzero, sizeof(double)) != 0)),
    1198              :                         forcesign, &signvalue))
    1199         7412 :             value = -value;
    1200              : 
    1201       955022 :         if (isinf(value))
    1202              :         {
    1203           57 :             strcpy(convert, "Infinity");
    1204           57 :             vallen = 8;
    1205              :             /* no zero padding, regardless of precision spec */
    1206              :         }
    1207       954965 :         else if (pointflag)
    1208              :         {
    1209       720334 :             zeropadlen = precision - prec;
    1210       720334 :             fmt[0] = '%';
    1211       720334 :             fmt[1] = '.';
    1212       720334 :             fmt[2] = '*';
    1213       720334 :             fmt[3] = type;
    1214       720334 :             fmt[4] = '\0';
    1215       720334 :             vallen = snprintf(convert, sizeof(convert), fmt, prec, value);
    1216              :         }
    1217              :         else
    1218              :         {
    1219       234631 :             fmt[0] = '%';
    1220       234631 :             fmt[1] = type;
    1221       234631 :             fmt[2] = '\0';
    1222       234631 :             vallen = snprintf(convert, sizeof(convert), fmt, value);
    1223              :         }
    1224       955022 :         if (vallen < 0)
    1225            0 :             goto fail;
    1226              :     }
    1227              : 
    1228       955049 :     padlen = compute_padlen(minlen, vallen + zeropadlen, leftjust);
    1229              : 
    1230       955049 :     leading_pad(zpad, signvalue, &padlen, target);
    1231              : 
    1232       955049 :     if (zeropadlen > 0)
    1233              :     {
    1234              :         /* If 'e' or 'E' format, inject zeroes before the exponent */
    1235            0 :         char       *epos = strrchr(convert, 'e');
    1236              : 
    1237            0 :         if (!epos)
    1238            0 :             epos = strrchr(convert, 'E');
    1239            0 :         if (epos)
    1240              :         {
    1241              :             /* pad before exponent */
    1242            0 :             dostr(convert, epos - convert, target);
    1243            0 :             dopr_outchmulti('0', zeropadlen, target);
    1244            0 :             dostr(epos, vallen - (epos - convert), target);
    1245              :         }
    1246              :         else
    1247              :         {
    1248              :             /* no exponent, pad after the digits */
    1249            0 :             dostr(convert, vallen, target);
    1250            0 :             dopr_outchmulti('0', zeropadlen, target);
    1251              :         }
    1252              :     }
    1253              :     else
    1254              :     {
    1255              :         /* no zero padding, just emit the number as-is */
    1256       955049 :         dostr(convert, vallen, target);
    1257              :     }
    1258              : 
    1259       955049 :     trailing_pad(padlen, target);
    1260       955049 :     return;
    1261              : 
    1262            0 : fail:
    1263            0 :     target->failed = true;
    1264              : }
    1265              : 
    1266              : /*
    1267              :  * Nonstandard entry point to print a double value efficiently.
    1268              :  *
    1269              :  * This is approximately equivalent to strfromd(), but has an API more
    1270              :  * adapted to what float8out() wants.  The behavior is like snprintf()
    1271              :  * with a format of "%.ng", where n is the specified precision.
    1272              :  * However, the target buffer must be nonempty (i.e. count > 0), and
    1273              :  * the precision is silently bounded to a sane range.
    1274              :  */
    1275              : int
    1276       115153 : pg_strfromd(char *str, size_t count, int precision, double value)
    1277              : {
    1278              :     PrintfTarget target;
    1279       115153 :     int         signvalue = 0;
    1280              :     int         vallen;
    1281              :     char        fmt[8];
    1282              :     char        convert[64];
    1283              : 
    1284              :     /* Set up the target like pg_snprintf, but require nonempty buffer */
    1285              :     Assert(count > 0);
    1286       115153 :     target.bufstart = target.bufptr = str;
    1287       115153 :     target.bufend = str + count - 1;
    1288       115153 :     target.stream = NULL;
    1289       115153 :     target.nchars = 0;
    1290       115153 :     target.failed = false;
    1291              : 
    1292              :     /*
    1293              :      * We bound precision to a reasonable range; the combination of this and
    1294              :      * the knowledge that we're using "g" format without padding allows the
    1295              :      * convert[] buffer to be reasonably small.
    1296              :      */
    1297       115153 :     if (precision < 1)
    1298            0 :         precision = 1;
    1299       115153 :     else if (precision > 32)
    1300            0 :         precision = 32;
    1301              : 
    1302              :     /*
    1303              :      * The rest is just an inlined version of the fmtfloat() logic above,
    1304              :      * simplified using the knowledge that no padding is wanted.
    1305              :      */
    1306       115153 :     if (isnan(value))
    1307              :     {
    1308         6069 :         strcpy(convert, "NaN");
    1309         6069 :         vallen = 3;
    1310              :     }
    1311              :     else
    1312              :     {
    1313              :         static const double dzero = 0.0;
    1314              : 
    1315       109084 :         if (value < 0.0 ||
    1316        92884 :             (value == 0.0 &&
    1317        13439 :              memcmp(&value, &dzero, sizeof(double)) != 0))
    1318              :         {
    1319        16233 :             signvalue = '-';
    1320        16233 :             value = -value;
    1321              :         }
    1322              : 
    1323       109084 :         if (isinf(value))
    1324              :         {
    1325         3558 :             strcpy(convert, "Infinity");
    1326         3558 :             vallen = 8;
    1327              :         }
    1328              :         else
    1329              :         {
    1330       105526 :             fmt[0] = '%';
    1331       105526 :             fmt[1] = '.';
    1332       105526 :             fmt[2] = '*';
    1333       105526 :             fmt[3] = 'g';
    1334       105526 :             fmt[4] = '\0';
    1335       105526 :             vallen = snprintf(convert, sizeof(convert), fmt, precision, value);
    1336       105526 :             if (vallen < 0)
    1337              :             {
    1338            0 :                 target.failed = true;
    1339            0 :                 goto fail;
    1340              :             }
    1341              :         }
    1342              :     }
    1343              : 
    1344       115153 :     if (signvalue)
    1345        16233 :         dopr_outch(signvalue, &target);
    1346              : 
    1347       115153 :     dostr(convert, vallen, &target);
    1348              : 
    1349       115153 : fail:
    1350       115153 :     *(target.bufptr) = '\0';
    1351       230306 :     return target.failed ? -1 : (target.bufptr - target.bufstart
    1352       115153 :                                  + target.nchars);
    1353              : }
    1354              : 
    1355              : 
    1356              : static void
    1357    573781553 : dostr(const char *str, int slen, PrintfTarget *target)
    1358              : {
    1359              :     /* fast path for common case of slen == 1 */
    1360    573781553 :     if (slen == 1)
    1361              :     {
    1362    239999836 :         dopr_outch(*str, target);
    1363    239999839 :         return;
    1364              :     }
    1365              : 
    1366    665916712 :     while (slen > 0)
    1367              :     {
    1368              :         int         avail;
    1369              : 
    1370    332559464 :         if (target->bufend != NULL)
    1371    322265030 :             avail = target->bufend - target->bufptr;
    1372              :         else
    1373     10294434 :             avail = slen;
    1374    332559464 :         if (avail <= 0)
    1375              :         {
    1376              :             /* buffer full, can we dump to stream? */
    1377       424723 :             if (target->stream == NULL)
    1378              :             {
    1379       424469 :                 target->nchars += slen; /* no, lose the data */
    1380       424469 :                 return;
    1381              :             }
    1382          254 :             flushbuffer(target);
    1383          254 :             continue;
    1384              :         }
    1385    332134741 :         avail = Min(avail, slen);
    1386    332134741 :         memmove(target->bufptr, str, avail);
    1387    332134741 :         target->bufptr += avail;
    1388    332134741 :         str += avail;
    1389    332134741 :         slen -= avail;
    1390              :     }
    1391              : }
    1392              : 
    1393              : static void
    1394    263596526 : dopr_outch(int c, PrintfTarget *target)
    1395              : {
    1396    263596526 :     if (target->bufend != NULL && target->bufptr >= target->bufend)
    1397              :     {
    1398              :         /* buffer full, can we dump to stream? */
    1399       137682 :         if (target->stream == NULL)
    1400              :         {
    1401       137682 :             target->nchars++;    /* no, lose the data */
    1402       137682 :             return;
    1403              :         }
    1404            0 :         flushbuffer(target);
    1405              :     }
    1406    263458858 :     *(target->bufptr++) = c;
    1407              : }
    1408              : 
    1409              : static void
    1410      6490184 : dopr_outchmulti(int c, int slen, PrintfTarget *target)
    1411              : {
    1412              :     /* fast path for common case of slen == 1 */
    1413      6490184 :     if (slen == 1)
    1414              :     {
    1415      4867030 :         dopr_outch(c, target);
    1416      4867030 :         return;
    1417              :     }
    1418              : 
    1419      3246334 :     while (slen > 0)
    1420              :     {
    1421              :         int         avail;
    1422              : 
    1423      1623265 :         if (target->bufend != NULL)
    1424      1601201 :             avail = target->bufend - target->bufptr;
    1425              :         else
    1426        22064 :             avail = slen;
    1427      1623265 :         if (avail <= 0)
    1428              :         {
    1429              :             /* buffer full, can we dump to stream? */
    1430          142 :             if (target->stream == NULL)
    1431              :             {
    1432           85 :                 target->nchars += slen; /* no, lose the data */
    1433           85 :                 return;
    1434              :             }
    1435           57 :             flushbuffer(target);
    1436           57 :             continue;
    1437              :         }
    1438      1623123 :         avail = Min(avail, slen);
    1439      1623123 :         memset(target->bufptr, c, avail);
    1440      1623123 :         target->bufptr += avail;
    1441      1623123 :         slen -= avail;
    1442              :     }
    1443              : }
    1444              : 
    1445              : 
    1446              : static int
    1447    167343718 : adjust_sign(int is_negative, int forcesign, int *signvalue)
    1448              : {
    1449    167343718 :     if (is_negative)
    1450              :     {
    1451     18413409 :         *signvalue = '-';
    1452     18413409 :         return true;
    1453              :     }
    1454    148930309 :     else if (forcesign)
    1455          102 :         *signvalue = '+';
    1456    148930309 :     return false;
    1457              : }
    1458              : 
    1459              : 
    1460              : static int
    1461    251301037 : compute_padlen(int minlen, int vallen, int leftjust)
    1462              : {
    1463              :     int         padlen;
    1464              : 
    1465    251301037 :     padlen = minlen - vallen;
    1466    251301037 :     if (padlen < 0)
    1467    233856336 :         padlen = 0;
    1468    251301037 :     if (leftjust)
    1469       561747 :         padlen = -padlen;
    1470    251301037 :     return padlen;
    1471              : }
    1472              : 
    1473              : 
    1474              : static void
    1475    250282413 : leading_pad(int zpad, int signvalue, int *padlen, PrintfTarget *target)
    1476              : {
    1477              :     int         maxpad;
    1478              : 
    1479    250282413 :     if (*padlen > 0 && zpad)
    1480              :     {
    1481      5036966 :         if (signvalue)
    1482              :         {
    1483          112 :             dopr_outch(signvalue, target);
    1484          112 :             --(*padlen);
    1485          112 :             signvalue = 0;
    1486              :         }
    1487      5036966 :         if (*padlen > 0)
    1488              :         {
    1489      5036957 :             dopr_outchmulti(zpad, *padlen, target);
    1490      5036957 :             *padlen = 0;
    1491              :         }
    1492              :     }
    1493    250282413 :     maxpad = (signvalue != 0);
    1494    250282413 :     if (*padlen > maxpad)
    1495              :     {
    1496       782909 :         dopr_outchmulti(' ', *padlen - maxpad, target);
    1497       782909 :         *padlen = maxpad;
    1498              :     }
    1499    250282413 :     if (signvalue)
    1500              :     {
    1501     18413399 :         dopr_outch(signvalue, target);
    1502     18413399 :         if (*padlen > 0)
    1503            0 :             --(*padlen);
    1504     18413399 :         else if (*padlen < 0)
    1505            0 :             ++(*padlen);
    1506              :     }
    1507    250282413 : }
    1508              : 
    1509              : 
    1510              : static void
    1511    251301045 : trailing_pad(int padlen, PrintfTarget *target)
    1512              : {
    1513    251301045 :     if (padlen < 0)
    1514       369010 :         dopr_outchmulti(' ', -padlen, target);
    1515    251301045 : }
        

Generated by: LCOV version 2.0-1