LCOV - differential code coverage report
Current view: top level - src/port - snprintf.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC CBC EUB ECB DUB
Current: Differential Code Coverage HEAD vs 15 Lines: 67.6 % 614 415 2 30 98 69 28 220 167 100 218 2
Current Date: 2023-04-08 15:15:32 Functions: 91.7 % 24 22 2 22 2 22
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, 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 ECB             : 
     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 GIC    70273981 : pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
     175 ECB             : {
     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 CBC    70273981 :     if (count == 0)
     186 ECB             :     {
     187 CBC       44711 :         str = onebyte;
     188           44711 :         count = 1;
     189                 :     }
     190 GIC    70273981 :     target.bufstart = target.bufptr = str;
     191        70273981 :     target.bufend = str + count - 1;
     192 CBC    70273981 :     target.stream = NULL;
     193 GIC    70273981 :     target.nchars = 0;
     194        70273981 :     target.failed = false;
     195        70273981 :     dopr(&target, fmt, args);
     196        70273981 :     *(target.bufptr) = '\0';
     197 CBC   140547962 :     return target.failed ? -1 : (target.bufptr - target.bufstart
     198        70273981 :                                  + target.nchars);
     199 ECB             : }
     200                 : 
     201                 : int
     202 GIC     9581971 : pg_snprintf(char *str, size_t count, const char *fmt,...)
     203                 : {
     204 ECB             :     int         len;
     205                 :     va_list     args;
     206                 : 
     207 GIC     9581971 :     va_start(args, fmt);
     208 CBC     9581971 :     len = pg_vsnprintf(str, count, fmt, args);
     209         9581977 :     va_end(args);
     210         9581977 :     return len;
     211 ECB             : }
     212                 : 
     213                 : int
     214 CBC     3124419 : pg_vsprintf(char *str, const char *fmt, va_list args)
     215 ECB             : {
     216                 :     PrintfTarget target;
     217                 : 
     218 GIC     3124419 :     target.bufstart = target.bufptr = str;
     219         3124419 :     target.bufend = NULL;
     220 CBC     3124419 :     target.stream = NULL;
     221 GIC     3124419 :     target.nchars = 0;          /* not really used in this case */
     222         3124419 :     target.failed = false;
     223         3124419 :     dopr(&target, fmt, args);
     224         3124419 :     *(target.bufptr) = '\0';
     225 CBC     6248838 :     return target.failed ? -1 : (target.bufptr - target.bufstart
     226         3124419 :                                  + target.nchars);
     227 ECB             : }
     228                 : 
     229                 : int
     230 GIC     3124415 : pg_sprintf(char *str, const char *fmt,...)
     231                 : {
     232 ECB             :     int         len;
     233                 :     va_list     args;
     234                 : 
     235 GIC     3124415 :     va_start(args, fmt);
     236         3124415 :     len = pg_vsprintf(str, fmt, args);
     237 CBC     3124423 :     va_end(args);
     238 GIC     3124423 :     return len;
     239 EUB             : }
     240                 : 
     241                 : int
     242 CBC      993442 : pg_vfprintf(FILE *stream, const char *fmt, va_list args)
     243 ECB             : {
     244                 :     PrintfTarget target;
     245                 :     char        buffer[1024];   /* size is arbitrary */
     246                 : 
     247 CBC      993442 :     if (stream == NULL)
     248                 :     {
     249 LBC           0 :         errno = EINVAL;
     250               0 :         return -1;
     251                 :     }
     252 GIC      993442 :     target.bufstart = target.bufptr = buffer;
     253          993442 :     target.bufend = buffer + sizeof(buffer);    /* use the whole buffer */
     254 CBC      993442 :     target.stream = stream;
     255 GIC      993442 :     target.nchars = 0;
     256          993442 :     target.failed = false;
     257          993442 :     dopr(&target, fmt, args);
     258                 :     /* dump any remaining buffer contents */
     259 CBC      993442 :     flushbuffer(&target);
     260          993442 :     return target.failed ? -1 : target.nchars;
     261 ECB             : }
     262                 : 
     263                 : int
     264 GIC      729096 : pg_fprintf(FILE *stream, const char *fmt,...)
     265                 : {
     266 EUB             :     int         len;
     267                 :     va_list     args;
     268                 : 
     269 GIC      729096 :     va_start(args, fmt);
     270          729096 :     len = pg_vfprintf(stream, fmt, args);
     271          729096 :     va_end(args);
     272 CBC      729096 :     return len;
     273                 : }
     274                 : 
     275                 : int
     276 UIC           0 : pg_vprintf(const char *fmt, va_list args)
     277 ECB             : {
     278 LBC           0 :     return pg_vfprintf(stdout, fmt, args);
     279 ECB             : }
     280                 : 
     281                 : int
     282 GIC      257015 : pg_printf(const char *fmt,...)
     283                 : {
     284                 :     int         len;
     285                 :     va_list     args;
     286                 : 
     287          257015 :     va_start(args, fmt);
     288 CBC      257015 :     len = pg_vfprintf(stdout, fmt, args);
     289 GIC      257015 :     va_end(args);
     290 CBC      257015 :     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 ECB             :  */
     297                 : static void
     298 GIC      993712 : flushbuffer(PrintfTarget *target)
     299                 : {
     300 CBC      993712 :     size_t      nc = target->bufptr - target->bufstart;
     301 ECB             : 
     302                 :     /*
     303 EUB             :      * Don't write anything if we already failed; this is to ensure we
     304                 :      * preserve the original failure's errno.
     305 ECB             :      */
     306 CBC      993712 :     if (!target->failed && nc > 0)
     307                 :     {
     308                 :         size_t      written;
     309                 : 
     310 GIC      880810 :         written = fwrite(target->bufstart, 1, nc, target->stream);
     311          880810 :         target->nchars += written;
     312          880810 :         if (written != nc)
     313 UIC           0 :             target->failed = true;
     314                 :     }
     315 GIC      993712 :     target->bufptr = target->bufstart;
     316          993712 : }
     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), it's a good bit faster than the
     342                 :  * equivalent manual loop.  If it doesn't exist, provide a replacement.
     343                 :  *
     344                 :  * Note: glibc declares this as returning "char *", but that would require
     345                 :  * casting away const internally, so we don't follow that detail.
     346                 :  */
     347                 : #ifndef HAVE_STRCHRNUL
     348                 : 
     349                 : static inline const char *
     350                 : strchrnul(const char *s, int c)
     351                 : {
     352                 :     while (*s != '\0' && *s != c)
     353                 :         s++;
     354                 :     return s;
     355                 : }
     356                 : 
     357                 : #else
     358                 : 
     359                 : /*
     360                 :  * glibc's <string.h> declares strchrnul only if _GNU_SOURCE is defined.
     361                 :  * While we typically use that on glibc platforms, configure will set
     362                 :  * HAVE_STRCHRNUL whether it's used or not.  Fill in the missing declaration
     363                 :  * so that this file will compile cleanly with or without _GNU_SOURCE.
     364                 :  */
     365                 : #ifndef _GNU_SOURCE
     366 ECB             : extern char *strchrnul(const char *s, int c);
     367                 : #endif
     368                 : 
     369                 : #endif                          /* HAVE_STRCHRNUL */
     370                 : 
     371                 : 
     372                 : /*
     373                 :  * dopr(): the guts of *printf for all cases.
     374                 :  */
     375                 : static void
     376 GIC    74391835 : dopr(PrintfTarget *target, const char *format, va_list args)
     377                 : {
     378        74391835 :     int         save_errno = errno;
     379        74391835 :     const char *first_pct = NULL;
     380                 :     int         ch;
     381                 :     bool        have_dollar;
     382                 :     bool        have_star;
     383                 :     bool        afterstar;
     384                 :     int         accum;
     385                 :     int         longlongflag;
     386                 :     int         longflag;
     387                 :     int         pointflag;
     388                 :     int         leftjust;
     389                 :     int         fieldwidth;
     390                 :     int         precision;
     391                 :     int         zpad;
     392                 :     int         forcesign;
     393                 :     int         fmtpos;
     394                 :     int         cvalue;
     395                 :     long long   numvalue;
     396 ECB             :     double      fvalue;
     397                 :     const char *strvalue;
     398                 :     PrintfArgValue argvalues[PG_NL_ARGMAX + 1];
     399                 : 
     400                 :     /*
     401                 :      * Initially, we suppose the format string does not use %n$.  The first
     402                 :      * time we come to a conversion spec that has that, we'll call
     403                 :      * find_arguments() to check for consistent use of %n$ and fill the
     404                 :      * argvalues array with the argument values in the correct order.
     405                 :      */
     406 GIC    74391835 :     have_dollar = false;
     407 ECB             : 
     408 CBC   155809903 :     while (*format != '\0')
     409 EUB             :     {
     410                 :         /* Locate next conversion specifier */
     411 CBC    89752455 :         if (*format != '%')
     412 ECB             :         {
     413                 :             /* Scan to next '%' or end of string */
     414 GIC    70003911 :             const char *next_pct = strchrnul(format + 1, '%');
     415                 : 
     416                 :             /* Dump literal data we just scanned over */
     417        70003911 :             dostr(format, next_pct - format, target);
     418        70003917 :             if (target->failed)
     419 UIC           0 :                 break;
     420                 : 
     421 CBC    70003917 :             if (*next_pct == '\0')
     422         8334384 :                 break;
     423 GIC    61669533 :             format = next_pct;
     424                 :         }
     425 ECB             : 
     426                 :         /*
     427                 :          * Remember start of first conversion spec; if we find %n$, then it's
     428                 :          * sufficient for find_arguments() to start here, without rescanning
     429                 :          * earlier literal text.
     430                 :          */
     431 CBC    81418077 :         if (first_pct == NULL)
     432        73874022 :             first_pct = format;
     433 EUB             : 
     434 ECB             :         /* Process conversion spec starting at *format */
     435 CBC    81418077 :         format++;
     436 EUB             : 
     437 ECB             :         /* Fast path for conversion spec that is exactly %s */
     438 GIC    81418077 :         if (*format == 's')
     439                 :         {
     440 CBC    14092193 :             format++;
     441        14092193 :             strvalue = va_arg(args, char *);
     442        14092193 :             if (strvalue == NULL)
     443 LBC           0 :                 strvalue = "(null)";
     444 CBC    14092193 :             dostr(strvalue, strlen(strvalue), target);
     445        14092193 :             if (target->failed)
     446 LBC           0 :                 break;
     447 GIC    14092193 :             continue;
     448 ECB             :         }
     449                 : 
     450 CBC    67325884 :         fieldwidth = precision = zpad = leftjust = forcesign = 0;
     451        67325884 :         longflag = longlongflag = pointflag = 0;
     452        67325884 :         fmtpos = accum = 0;
     453        67325884 :         have_star = afterstar = false;
     454         9394442 : nextch2:
     455 GIC    76720326 :         ch = *format++;
     456 CBC    76720326 :         switch (ch)
     457 ECB             :         {
     458 GIC      220365 :             case '-':
     459          220365 :                 leftjust = 1;
     460          220365 :                 goto nextch2;
     461             132 :             case '+':
     462             132 :                 forcesign = 1;
     463             132 :                 goto nextch2;
     464         2858010 :             case '0':
     465                 :                 /* set zero padding if no nonzero digits yet */
     466         2858010 :                 if (accum == 0 && !pointflag)
     467         2839251 :                     zpad = '0';
     468 ECB             :                 /* FALL THRU */
     469                 :             case '1':
     470                 :             case '2':
     471                 :             case '3':
     472 EUB             :             case '4':
     473                 :             case '5':
     474 ECB             :             case '6':
     475                 :             case '7':
     476                 :             case '8':
     477                 :             case '9':
     478 CBC     5713876 :                 accum = accum * 10 + (ch - '0');
     479         5713876 :                 goto nextch2;
     480 GIC       72745 :             case '.':
     481           72745 :                 if (have_star)
     482 UIC           0 :                     have_star = false;
     483                 :                 else
     484 GIC       72745 :                     fieldwidth = accum;
     485           72745 :                 pointflag = 1;
     486 GBC       72745 :                 accum = 0;
     487 GIC       72745 :                 goto nextch2;
     488          642957 :             case '*':
     489          642957 :                 if (have_dollar)
     490                 :                 {
     491 ECB             :                     /*
     492                 :                      * We'll process value after reading n$.  Note it's OK to
     493                 :                      * assume have_dollar is set correctly, because in a valid
     494                 :                      * format string the initial % must have had n$ if * does.
     495                 :                      */
     496 LBC           0 :                     afterstar = true;
     497                 :                 }
     498 EUB             :                 else
     499                 :                 {
     500                 :                     /* fetch and process value now */
     501 GIC      642957 :                     int         starval = va_arg(args, int);
     502                 : 
     503          642957 :                     if (pointflag)
     504 ECB             :                     {
     505 CBC       28299 :                         precision = starval;
     506 GIC       28299 :                         if (precision < 0)
     507 ECB             :                         {
     508 LBC           0 :                             precision = 0;
     509 UIC           0 :                             pointflag = 0;
     510                 :                         }
     511                 :                     }
     512 ECB             :                     else
     513                 :                     {
     514 CBC      614658 :                         fieldwidth = starval;
     515 GBC      614658 :                         if (fieldwidth < 0)
     516                 :                         {
     517            2823 :                             leftjust = 1;
     518 GIC        2823 :                             fieldwidth = -fieldwidth;
     519                 :                         }
     520 EUB             :                     }
     521 ECB             :                 }
     522 GBC      642957 :                 have_star = true;
     523 GIC      642957 :                 accum = 0;
     524 GBC      642957 :                 goto nextch2;
     525 UIC           0 :             case '$':
     526                 :                 /* First dollar sign? */
     527 UBC           0 :                 if (!have_dollar)
     528                 :                 {
     529 EUB             :                     /* Yup, so examine all conversion specs in format */
     530 UIC           0 :                     if (!find_arguments(first_pct, args, argvalues))
     531 GBC           9 :                         goto bad_format;
     532 UBC           0 :                     have_dollar = true;
     533                 :                 }
     534               0 :                 if (afterstar)
     535 EUB             :                 {
     536                 :                     /* fetch and process star value */
     537 UIC           0 :                     int         starval = argvalues[accum].i;
     538                 : 
     539               0 :                     if (pointflag)
     540 EUB             :                     {
     541 UBC           0 :                         precision = starval;
     542 UIC           0 :                         if (precision < 0)
     543 EUB             :                         {
     544 UBC           0 :                             precision = 0;
     545 UIC           0 :                             pointflag = 0;
     546                 :                         }
     547 EUB             :                     }
     548                 :                     else
     549                 :                     {
     550 UBC           0 :                         fieldwidth = starval;
     551               0 :                         if (fieldwidth < 0)
     552 EUB             :                         {
     553 LBC           0 :                             leftjust = 1;
     554               0 :                             fieldwidth = -fieldwidth;
     555 ECB             :                         }
     556                 :                     }
     557 LBC           0 :                     afterstar = false;
     558 ECB             :                 }
     559                 :                 else
     560 UIC           0 :                     fmtpos = accum;
     561               0 :                 accum = 0;
     562 LBC           0 :                 goto nextch2;
     563 GIC     2611698 :             case 'l':
     564         2611698 :                 if (longflag)
     565           22372 :                     longlongflag = 1;
     566                 :                 else
     567         2589326 :                     longflag = 1;
     568         2611698 :                 goto nextch2;
     569          132656 :             case 'z':
     570                 : #if SIZEOF_SIZE_T == 8
     571 ECB             : #ifdef HAVE_LONG_INT_64
     572 CBC      132656 :                 longflag = 1;
     573                 : #elif defined(HAVE_LONG_LONG_INT_64)
     574                 :                 longlongflag = 1;
     575 ECB             : #else
     576                 : #error "Don't know how to print 64bit integers"
     577                 : #endif
     578                 : #else
     579                 :                 /* assume size_t is same size as int */
     580                 : #endif
     581 GBC      132656 :                 goto nextch2;
     582 GIC          22 :             case 'h':
     583 ECB             :             case '\'':
     584                 :                 /* ignore these */
     585 CBC          22 :                 goto nextch2;
     586 GIC    36697384 :             case 'd':
     587 EUB             :             case 'i':
     588 GBC    36697384 :                 if (!have_star)
     589 EUB             :                 {
     590 GBC    36677831 :                     if (pointflag)
     591 UIC           0 :                         precision = accum;
     592 EUB             :                     else
     593 GIC    36677831 :                         fieldwidth = accum;
     594                 :                 }
     595        36697384 :                 if (have_dollar)
     596 ECB             :                 {
     597 LBC           0 :                     if (longlongflag)
     598               0 :                         numvalue = argvalues[fmtpos].ll;
     599               0 :                     else if (longflag)
     600 UIC           0 :                         numvalue = argvalues[fmtpos].l;
     601 ECB             :                     else
     602 UIC           0 :                         numvalue = argvalues[fmtpos].i;
     603 ECB             :                 }
     604                 :                 else
     605                 :                 {
     606 CBC    36697384 :                     if (longlongflag)
     607 GIC       22181 :                         numvalue = va_arg(args, long long);
     608        36675203 :                     else if (longflag)
     609         2250759 :                         numvalue = va_arg(args, long);
     610 ECB             :                     else
     611 GIC    34424444 :                         numvalue = va_arg(args, int);
     612 ECB             :                 }
     613 GBC    36697384 :                 fmtint(numvalue, ch, forcesign, leftjust, fieldwidth, zpad,
     614                 :                        precision, pointflag, target);
     615 CBC    36697400 :                 break;
     616 GIC    29806409 :             case 'o':
     617 ECB             :             case 'u':
     618                 :             case 'x':
     619 EUB             :             case 'X':
     620 GBC    29806409 :                 if (!have_star)
     621 EUB             :                 {
     622 GBC    29806409 :                     if (pointflag)
     623 UIC           0 :                         precision = accum;
     624 EUB             :                     else
     625 GIC    29806409 :                         fieldwidth = accum;
     626                 :                 }
     627        29806409 :                 if (have_dollar)
     628 ECB             :                 {
     629 LBC           0 :                     if (longlongflag)
     630               0 :                         numvalue = (unsigned long long) argvalues[fmtpos].ll;
     631               0 :                     else if (longflag)
     632 UIC           0 :                         numvalue = (unsigned long) argvalues[fmtpos].l;
     633 ECB             :                     else
     634 UIC           0 :                         numvalue = (unsigned int) argvalues[fmtpos].i;
     635 ECB             :                 }
     636                 :                 else
     637                 :                 {
     638 CBC    29806409 :                     if (longlongflag)
     639             191 :                         numvalue = (unsigned long long) va_arg(args, long long);
     640 GIC    29806218 :                     else if (longflag)
     641 CBC      448851 :                         numvalue = (unsigned long) va_arg(args, long);
     642 EUB             :                     else
     643 GIC    29357367 :                         numvalue = (unsigned int) va_arg(args, int);
     644 ECB             :                 }
     645 GIC    29806409 :                 fmtint(numvalue, ch, forcesign, leftjust, fieldwidth, zpad,
     646 ECB             :                        precision, pointflag, target);
     647 GBC    29806409 :                 break;
     648 GIC       19436 :             case 'c':
     649 CBC       19436 :                 if (!have_star)
     650 ECB             :                 {
     651 CBC       19415 :                     if (pointflag)
     652 LBC           0 :                         precision = accum;
     653 ECB             :                     else
     654 GIC       19415 :                         fieldwidth = accum;
     655 ECB             :                 }
     656 GBC       19436 :                 if (have_dollar)
     657 UIC           0 :                     cvalue = (unsigned char) argvalues[fmtpos].i;
     658 ECB             :                 else
     659 GIC       19436 :                     cvalue = (unsigned char) va_arg(args, int);
     660 CBC       19436 :                 fmtchar(cvalue, leftjust, fieldwidth, target);
     661 GBC       19436 :                 break;
     662 GIC      606533 :             case 's':
     663 CBC      606533 :                 if (!have_star)
     664                 :                 {
     665            2500 :                     if (pointflag)
     666 UBC           0 :                         precision = accum;
     667 ECB             :                     else
     668 GIC        2500 :                         fieldwidth = accum;
     669 ECB             :                 }
     670 CBC      606533 :                 if (have_dollar)
     671 UIC           0 :                     strvalue = argvalues[fmtpos].cptr;
     672 ECB             :                 else
     673 GBC      606533 :                     strvalue = va_arg(args, char *);
     674                 :                 /* If string is NULL, silently substitute "(null)" */
     675 CBC      606533 :                 if (strvalue == NULL)
     676 LBC           0 :                     strvalue = "(null)";
     677 CBC      606533 :                 fmtstr(strvalue, leftjust, fieldwidth, precision, pointflag,
     678 ECB             :                        target);
     679 GIC      606533 :                 break;
     680              65 :             case 'p':
     681                 :                 /* fieldwidth/leftjust are ignored ... */
     682              65 :                 if (have_dollar)
     683 LBC           0 :                     strvalue = argvalues[fmtpos].cptr;
     684                 :                 else
     685 CBC          65 :                     strvalue = va_arg(args, char *);
     686              65 :                 fmtptr((const void *) strvalue, target);
     687 GIC          65 :                 break;
     688 CBC      194581 :             case 'e':
     689                 :             case 'E':
     690 ECB             :             case 'f':
     691 EUB             :             case 'g':
     692                 :             case 'G':
     693 CBC      194581 :                 if (!have_star)
     694 ECB             :                 {
     695 GIC      175232 :                     if (pointflag)
     696           44446 :                         precision = accum;
     697                 :                     else
     698 CBC      130786 :                         fieldwidth = accum;
     699 ECB             :                 }
     700 GIC      194581 :                 if (have_dollar)
     701 UIC           0 :                     fvalue = argvalues[fmtpos].d;
     702 ECB             :                 else
     703 GIC      194581 :                     fvalue = va_arg(args, double);
     704          194581 :                 fmtfloat(fvalue, ch, forcesign, leftjust,
     705 ECB             :                          fieldwidth, zpad,
     706                 :                          precision, pointflag,
     707                 :                          target);
     708 CBC      194581 :                 break;
     709             133 :             case 'm':
     710 ECB             :                 {
     711 EUB             :                     char        errbuf[PG_STRERROR_R_BUFLEN];
     712 GIC         133 :                     const char *errm = strerror_r(save_errno,
     713                 :                                                   errbuf, sizeof(errbuf));
     714                 : 
     715             133 :                     dostr(errm, strlen(errm), target);
     716                 :                 }
     717 GBC         133 :                 break;
     718 GIC        1334 :             case '%':
     719            1334 :                 dopr_outch('%', target);
     720            1334 :                 break;
     721 LBC           0 :             default:
     722 EUB             : 
     723                 :                 /*
     724                 :                  * Anything else --- in particular, '\0' indicating end of
     725 ECB             :                  * format string --- is bogus.
     726                 :                  */
     727 LBC           0 :                 goto bad_format;
     728 ECB             :         }
     729                 : 
     730                 :         /* Check for failure after each conversion spec */
     731 GIC    67325875 :         if (target->failed)
     732 UIC           0 :             break;
     733                 :     }
     734                 : 
     735 GIC    74391832 :     return;
     736                 : 
     737               9 : bad_format:
     738               9 :     errno = EINVAL;
     739 GBC           9 :     target->failed = true;
     740                 : }
     741                 : 
     742                 : /*
     743                 :  * find_arguments(): sort out the arguments for a format spec with %n$
     744                 :  *
     745                 :  * If format is valid, return true and fill argvalues[i] with the value
     746                 :  * for the conversion spec that has %i$ or *i$.  Else return false.
     747                 :  */
     748                 : static bool
     749 UBC           0 : find_arguments(const char *format, va_list args,
     750 EUB             :                PrintfArgValue *argvalues)
     751                 : {
     752                 :     int         ch;
     753                 :     bool        afterstar;
     754                 :     int         accum;
     755                 :     int         longlongflag;
     756                 :     int         longflag;
     757                 :     int         fmtpos;
     758                 :     int         i;
     759 UNC           0 :     int         last_dollar = 0;    /* Init to "no dollar arguments known" */
     760               0 :     PrintfArgType argtypes[PG_NL_ARGMAX + 1] = {0};
     761                 : 
     762 EUB             :     /*
     763                 :      * This loop must accept the same format strings as the one in dopr().
     764                 :      * However, we don't need to analyze them to the same level of detail.
     765                 :      *
     766                 :      * Since we're only called if there's a dollar-type spec somewhere, we can
     767                 :      * fail immediately if we find a non-dollar spec.  Per the C99 standard,
     768                 :      * all argument references in the format string must be one or the other.
     769                 :      */
     770 UBC           0 :     while (*format != '\0')
     771 EUB             :     {
     772                 :         /* Locate next conversion specifier */
     773 UBC           0 :         if (*format != '%')
     774 EUB             :         {
     775                 :             /* Unlike dopr, we can just quit if there's no more specifiers */
     776 UBC           0 :             format = strchr(format + 1, '%');
     777 UIC           0 :             if (format == NULL)
     778 UBC           0 :                 break;
     779 EUB             :         }
     780                 : 
     781                 :         /* Process conversion spec starting at *format */
     782 UIC           0 :         format++;
     783               0 :         longflag = longlongflag = 0;
     784               0 :         fmtpos = accum = 0;
     785               0 :         afterstar = false;
     786               0 : nextch1:
     787               0 :         ch = *format++;
     788               0 :         switch (ch)
     789 EUB             :         {
     790 UBC           0 :             case '-':
     791 EUB             :             case '+':
     792 UBC           0 :                 goto nextch1;
     793               0 :             case '0':
     794 EUB             :             case '1':
     795                 :             case '2':
     796                 :             case '3':
     797                 :             case '4':
     798                 :             case '5':
     799                 :             case '6':
     800                 :             case '7':
     801                 :             case '8':
     802                 :             case '9':
     803 UBC           0 :                 accum = accum * 10 + (ch - '0');
     804 UIC           0 :                 goto nextch1;
     805 UBC           0 :             case '.':
     806               0 :                 accum = 0;
     807               0 :                 goto nextch1;
     808               0 :             case '*':
     809               0 :                 if (afterstar)
     810               0 :                     return false;   /* previous star missing dollar */
     811 UIC           0 :                 afterstar = true;
     812               0 :                 accum = 0;
     813 UBC           0 :                 goto nextch1;
     814               0 :             case '$':
     815               0 :                 if (accum <= 0 || accum > PG_NL_ARGMAX)
     816               0 :                     return false;
     817               0 :                 if (afterstar)
     818 EUB             :                 {
     819 UIC           0 :                     if (argtypes[accum] &&
     820 UBC           0 :                         argtypes[accum] != ATYPE_INT)
     821               0 :                         return false;
     822               0 :                     argtypes[accum] = ATYPE_INT;
     823 UIC           0 :                     last_dollar = Max(last_dollar, accum);
     824               0 :                     afterstar = false;
     825 EUB             :                 }
     826                 :                 else
     827 UIC           0 :                     fmtpos = accum;
     828               0 :                 accum = 0;
     829               0 :                 goto nextch1;
     830               0 :             case 'l':
     831               0 :                 if (longflag)
     832               0 :                     longlongflag = 1;
     833                 :                 else
     834 UBC           0 :                     longflag = 1;
     835               0 :                 goto nextch1;
     836 UIC           0 :             case 'z':
     837                 : #if SIZEOF_SIZE_T == 8
     838 EUB             : #ifdef HAVE_LONG_INT_64
     839 UBC           0 :                 longflag = 1;
     840                 : #elif defined(HAVE_LONG_LONG_INT_64)
     841                 :                 longlongflag = 1;
     842                 : #else
     843                 : #error "Don't know how to print 64bit integers"
     844                 : #endif
     845 EUB             : #else
     846                 :                 /* assume size_t is same size as int */
     847                 : #endif
     848 UIC           0 :                 goto nextch1;
     849 UBC           0 :             case 'h':
     850 EUB             :             case '\'':
     851                 :                 /* ignore these */
     852 UBC           0 :                 goto nextch1;
     853 UIC           0 :             case 'd':
     854 EUB             :             case 'i':
     855                 :             case 'o':
     856                 :             case 'u':
     857                 :             case 'x':
     858                 :             case 'X':
     859 UBC           0 :                 if (fmtpos)
     860                 :                 {
     861                 :                     PrintfArgType atype;
     862 EUB             : 
     863 UBC           0 :                     if (longlongflag)
     864               0 :                         atype = ATYPE_LONGLONG;
     865               0 :                     else if (longflag)
     866 UIC           0 :                         atype = ATYPE_LONG;
     867 EUB             :                     else
     868 UBC           0 :                         atype = ATYPE_INT;
     869               0 :                     if (argtypes[fmtpos] &&
     870               0 :                         argtypes[fmtpos] != atype)
     871               0 :                         return false;
     872 UIC           0 :                     argtypes[fmtpos] = atype;
     873               0 :                     last_dollar = Max(last_dollar, fmtpos);
     874 EUB             :                 }
     875                 :                 else
     876 UBC           0 :                     return false;   /* non-dollar conversion spec */
     877 UIC           0 :                 break;
     878 UBC           0 :             case 'c':
     879 UIC           0 :                 if (fmtpos)
     880 EUB             :                 {
     881 UBC           0 :                     if (argtypes[fmtpos] &&
     882               0 :                         argtypes[fmtpos] != ATYPE_INT)
     883               0 :                         return false;
     884               0 :                     argtypes[fmtpos] = ATYPE_INT;
     885 UIC           0 :                     last_dollar = Max(last_dollar, fmtpos);
     886                 :                 }
     887 EUB             :                 else
     888 UBC           0 :                     return false;   /* non-dollar conversion spec */
     889               0 :                 break;
     890 UIC           0 :             case 's':
     891                 :             case 'p':
     892               0 :                 if (fmtpos)
     893                 :                 {
     894 UBC           0 :                     if (argtypes[fmtpos] &&
     895 UIC           0 :                         argtypes[fmtpos] != ATYPE_CHARPTR)
     896 UBC           0 :                         return false;
     897               0 :                     argtypes[fmtpos] = ATYPE_CHARPTR;
     898               0 :                     last_dollar = Max(last_dollar, fmtpos);
     899 EUB             :                 }
     900                 :                 else
     901 UIC           0 :                     return false;   /* non-dollar conversion spec */
     902               0 :                 break;
     903 UBC           0 :             case 'e':
     904 EUB             :             case 'E':
     905                 :             case 'f':
     906                 :             case 'g':
     907                 :             case 'G':
     908 UBC           0 :                 if (fmtpos)
     909 EUB             :                 {
     910 UIC           0 :                     if (argtypes[fmtpos] &&
     911               0 :                         argtypes[fmtpos] != ATYPE_DOUBLE)
     912               0 :                         return false;
     913               0 :                     argtypes[fmtpos] = ATYPE_DOUBLE;
     914               0 :                     last_dollar = Max(last_dollar, fmtpos);
     915                 :                 }
     916 EUB             :                 else
     917 UBC           0 :                     return false;   /* non-dollar conversion spec */
     918 UIC           0 :                 break;
     919               0 :             case 'm':
     920                 :             case '%':
     921               0 :                 break;
     922               0 :             default:
     923               0 :                 return false;   /* bogus format string */
     924                 :         }
     925 EUB             : 
     926                 :         /*
     927                 :          * If we finish the spec with afterstar still set, there's a
     928                 :          * non-dollar star in there.
     929                 :          */
     930 UBC           0 :         if (afterstar)
     931               0 :             return false;       /* non-dollar conversion spec */
     932 EUB             :     }
     933                 : 
     934                 :     /*
     935                 :      * Format appears valid so far, so collect the arguments in physical
     936                 :      * order.  (Since we rejected any non-dollar specs that would have
     937                 :      * collected arguments, we know that dopr() hasn't collected any yet.)
     938                 :      */
     939 UBC           0 :     for (i = 1; i <= last_dollar; i++)
     940 EUB             :     {
     941 UBC           0 :         switch (argtypes[i])
     942 EUB             :         {
     943 UBC           0 :             case ATYPE_NONE:
     944               0 :                 return false;
     945               0 :             case ATYPE_INT:
     946 UIC           0 :                 argvalues[i].i = va_arg(args, int);
     947               0 :                 break;
     948               0 :             case ATYPE_LONG:
     949 UBC           0 :                 argvalues[i].l = va_arg(args, long);
     950 UIC           0 :                 break;
     951               0 :             case ATYPE_LONGLONG:
     952               0 :                 argvalues[i].ll = va_arg(args, long long);
     953 LBC           0 :                 break;
     954 UIC           0 :             case ATYPE_DOUBLE:
     955               0 :                 argvalues[i].d = va_arg(args, double);
     956               0 :                 break;
     957               0 :             case ATYPE_CHARPTR:
     958               0 :                 argvalues[i].cptr = va_arg(args, char *);
     959               0 :                 break;
     960                 :         }
     961                 :     }
     962                 : 
     963 LBC           0 :     return true;
     964 ECB             : }
     965                 : 
     966                 : static void
     967 GIC      606533 : fmtstr(const char *value, int leftjust, int minlen, int maxwidth,
     968 ECB             :        int pointflag, PrintfTarget *target)
     969                 : {
     970                 :     int         padlen,
     971                 :                 vallen;         /* amount to pad */
     972                 : 
     973                 :     /*
     974                 :      * If a maxwidth (precision) is specified, we must not fetch more bytes
     975                 :      * than that.
     976                 :      */
     977 GIC      606533 :     if (pointflag)
     978 CBC        8950 :         vallen = strnlen(value, maxwidth);
     979 ECB             :     else
     980 GIC      597583 :         vallen = strlen(value);
     981                 : 
     982 CBC      606533 :     padlen = compute_padlen(minlen, vallen, leftjust);
     983                 : 
     984 GIC      606533 :     if (padlen > 0)
     985                 :     {
     986          256081 :         dopr_outchmulti(' ', padlen, target);
     987          256081 :         padlen = 0;
     988 ECB             :     }
     989                 : 
     990 GBC      606533 :     dostr(value, vallen, target);
     991                 : 
     992 CBC      606533 :     trailing_pad(padlen, target);
     993          606533 : }
     994                 : 
     995                 : static void
     996              65 : fmtptr(const void *value, PrintfTarget *target)
     997                 : {
     998                 :     int         vallen;
     999                 :     char        convert[64];
    1000                 : 
    1001                 :     /* we rely on regular C library's snprintf to do the basic conversion */
    1002 GIC          65 :     vallen = snprintf(convert, sizeof(convert), "%p", value);
    1003 CBC          65 :     if (vallen < 0)
    1004 LBC           0 :         target->failed = true;
    1005                 :     else
    1006 CBC          65 :         dostr(convert, vallen, target);
    1007 GIC          65 : }
    1008                 : 
    1009                 : static void
    1010 CBC    66503795 : fmtint(long long value, char type, int forcesign, int leftjust,
    1011                 :        int minlen, int zpad, int precision, int pointflag,
    1012 ECB             :        PrintfTarget *target)
    1013                 : {
    1014                 :     unsigned long long uvalue;
    1015                 :     int         base;
    1016                 :     int         dosign;
    1017 CBC    66503795 :     const char *cvt = "0123456789abcdef";
    1018        66503795 :     int         signvalue = 0;
    1019 ECB             :     char        convert[64];
    1020 CBC    66503795 :     int         vallen = 0;
    1021 ECB             :     int         padlen;         /* amount to pad */
    1022                 :     int         zeropad;        /* extra leading zeroes */
    1023                 : 
    1024 CBC    66503795 :     switch (type)
    1025 ECB             :     {
    1026 CBC    36697388 :         case 'd':
    1027 ECB             :         case 'i':
    1028 CBC    36697388 :             base = 10;
    1029        36697388 :             dosign = 1;
    1030        36697388 :             break;
    1031            3562 :         case 'o':
    1032            3562 :             base = 8;
    1033            3562 :             dosign = 0;
    1034 GBC        3562 :             break;
    1035        29543853 :         case 'u':
    1036 GIC    29543853 :             base = 10;
    1037        29543853 :             dosign = 0;
    1038        29543853 :             break;
    1039           27655 :         case 'x':
    1040           27655 :             base = 16;
    1041           27655 :             dosign = 0;
    1042           27655 :             break;
    1043          231339 :         case 'X':
    1044 CBC      231339 :             cvt = "0123456789ABCDEF";
    1045          231339 :             base = 16;
    1046 GIC      231339 :             dosign = 0;
    1047 CBC      231339 :             break;
    1048 UIC           0 :         default:
    1049               0 :             return;             /* keep compiler quiet */
    1050                 :     }
    1051                 : 
    1052                 :     /* disable MSVC warning about applying unary minus to an unsigned value */
    1053                 : #ifdef _MSC_VER
    1054                 : #pragma warning(push)
    1055                 : #pragma warning(disable: 4146)
    1056 ECB             : #endif
    1057 EUB             :     /* Handle +/- */
    1058 GIC    66503797 :     if (dosign && adjust_sign((value < 0), forcesign, &signvalue))
    1059         6664234 :         uvalue = -(unsigned long long) value;
    1060                 :     else
    1061        59839564 :         uvalue = (unsigned long long) value;
    1062                 : #ifdef _MSC_VER
    1063                 : #pragma warning(pop)
    1064                 : #endif
    1065                 : 
    1066 ECB             :     /*
    1067                 :      * SUS: the result of converting 0 with an explicit precision of 0 is no
    1068                 :      * characters
    1069                 :      */
    1070 CBC    66503798 :     if (value == 0 && pointflag && precision == 0)
    1071 LBC           0 :         vallen = 0;
    1072 ECB             :     else
    1073                 :     {
    1074                 :         /*
    1075                 :          * Convert integer to string.  We special-case each of the possible
    1076                 :          * base values so as to avoid general-purpose divisions.  On most
    1077                 :          * machines, division by a fixed constant can be done much more
    1078                 :          * cheaply than a general divide.
    1079                 :          */
    1080 CBC    66503798 :         if (base == 10)
    1081                 :         {
    1082                 :             do
    1083                 :             {
    1084 GIC   131512845 :                 convert[sizeof(convert) - (++vallen)] = cvt[uvalue % 10];
    1085       131512845 :                 uvalue = uvalue / 10;
    1086 CBC   131512845 :             } while (uvalue);
    1087 ECB             :         }
    1088 CBC      262556 :         else if (base == 16)
    1089                 :         {
    1090                 :             do
    1091                 :             {
    1092          710389 :                 convert[sizeof(convert) - (++vallen)] = cvt[uvalue % 16];
    1093 GIC      710389 :                 uvalue = uvalue / 16;
    1094 CBC      710389 :             } while (uvalue);
    1095                 :         }
    1096 ECB             :         else                    /* base == 8 */
    1097                 :         {
    1098                 :             do
    1099 EUB             :             {
    1100 GIC       10686 :                 convert[sizeof(convert) - (++vallen)] = cvt[uvalue % 8];
    1101 CBC       10686 :                 uvalue = uvalue / 8;
    1102 GIC       10686 :             } while (uvalue);
    1103 ECB             :         }
    1104                 :     }
    1105                 : 
    1106 GIC    66503798 :     zeropad = Max(0, precision - vallen);
    1107 ECB             : 
    1108 GIC    66503798 :     padlen = compute_padlen(minlen, vallen + zeropad, leftjust);
    1109                 : 
    1110        66503800 :     leading_pad(zpad, signvalue, &padlen, target);
    1111 ECB             : 
    1112 GIC    66503800 :     if (zeropad > 0)
    1113 LBC           0 :         dopr_outchmulti('0', zeropad, target);
    1114                 : 
    1115 CBC    66503800 :     dostr(convert + sizeof(convert) - vallen, vallen, target);
    1116 ECB             : 
    1117 GIC    66503803 :     trailing_pad(padlen, target);
    1118                 : }
    1119 ECB             : 
    1120                 : static void
    1121 CBC       19436 : fmtchar(int value, int leftjust, int minlen, PrintfTarget *target)
    1122 ECB             : {
    1123                 :     int         padlen;         /* amount to pad */
    1124                 : 
    1125 CBC       19436 :     padlen = compute_padlen(minlen, 1, leftjust);
    1126                 : 
    1127 GIC       19436 :     if (padlen > 0)
    1128                 :     {
    1129 CBC          21 :         dopr_outchmulti(' ', padlen, target);
    1130 GIC          21 :         padlen = 0;
    1131                 :     }
    1132                 : 
    1133           19436 :     dopr_outch(value, target);
    1134 ECB             : 
    1135 GIC       19436 :     trailing_pad(padlen, target);
    1136           19436 : }
    1137                 : 
    1138                 : static void
    1139          194581 : fmtfloat(double value, char type, int forcesign, int leftjust,
    1140                 :          int minlen, int zpad, int precision, int pointflag,
    1141                 :          PrintfTarget *target)
    1142                 : {
    1143          194581 :     int         signvalue = 0;
    1144                 :     int         prec;
    1145                 :     int         vallen;
    1146                 :     char        fmt[8];
    1147                 :     char        convert[1024];
    1148          194581 :     int         zeropadlen = 0; /* amount to pad with zeroes */
    1149                 :     int         padlen;         /* amount to pad with spaces */
    1150                 : 
    1151                 :     /*
    1152                 :      * We rely on the regular C library's snprintf to do the basic conversion,
    1153                 :      * then handle padding considerations here.
    1154 ECB             :      *
    1155 EUB             :      * The dynamic range of "double" is about 1E+-308 for IEEE math, and not
    1156 ECB             :      * too wildly more than that with other hardware.  In "f" format, snprintf
    1157                 :      * could therefore generate at most 308 characters to the left of the
    1158                 :      * decimal point; while we need to allow the precision to get as high as
    1159                 :      * 308+17 to ensure that we don't truncate significant digits from very
    1160                 :      * small values.  To handle both these extremes, we use a buffer of 1024
    1161                 :      * bytes and limit requested precision to 350 digits; this should prevent
    1162                 :      * buffer overrun even with non-IEEE math.  If the original precision
    1163                 :      * request was more than 350, separately pad with zeroes.
    1164                 :      *
    1165                 :      * We handle infinities and NaNs specially to ensure platform-independent
    1166                 :      * output.
    1167                 :      */
    1168 GIC      194581 :     if (precision < 0)           /* cover possible overflow of "accum" */
    1169 UIC           0 :         precision = 0;
    1170 GIC      194581 :     prec = Min(precision, 350);
    1171                 : 
    1172          194581 :     if (isnan(value))
    1173                 :     {
    1174 CBC          67 :         strcpy(convert, "NaN");
    1175              67 :         vallen = 3;
    1176 ECB             :         /* no zero padding, regardless of precision spec */
    1177                 :     }
    1178                 :     else
    1179                 :     {
    1180                 :         /*
    1181                 :          * Handle sign (NaNs have no sign, so we don't do this in the case
    1182                 :          * above).  "value < 0.0" will not be true for IEEE minus zero, so we
    1183                 :          * detect that by looking for the case where value equals 0.0
    1184                 :          * according to == but not according to memcmp.
    1185                 :          */
    1186                 :         static const double dzero = 0.0;
    1187                 : 
    1188 CBC      384474 :         if (adjust_sign((value < 0.0 ||
    1189          189960 :                          (value == 0.0 &&
    1190           35006 :                           memcmp(&value, &dzero, sizeof(double)) != 0)),
    1191 ECB             :                         forcesign, &signvalue))
    1192 CBC        4554 :             value = -value;
    1193 ECB             : 
    1194 CBC      194514 :         if (isinf(value))
    1195                 :         {
    1196 GIC          48 :             strcpy(convert, "Infinity");
    1197              48 :             vallen = 8;
    1198 ECB             :             /* no zero padding, regardless of precision spec */
    1199                 :         }
    1200 CBC      194466 :         else if (pointflag)
    1201 ECB             :         {
    1202 GIC       63680 :             zeropadlen = precision - prec;
    1203 CBC       63680 :             fmt[0] = '%';
    1204 GBC       63680 :             fmt[1] = '.';
    1205 GIC       63680 :             fmt[2] = '*';
    1206           63680 :             fmt[3] = type;
    1207           63680 :             fmt[4] = '\0';
    1208           63680 :             vallen = snprintf(convert, sizeof(convert), fmt, prec, value);
    1209                 :         }
    1210                 :         else
    1211                 :         {
    1212          130786 :             fmt[0] = '%';
    1213          130786 :             fmt[1] = type;
    1214          130786 :             fmt[2] = '\0';
    1215          130786 :             vallen = snprintf(convert, sizeof(convert), fmt, value);
    1216                 :         }
    1217          194514 :         if (vallen < 0)
    1218 UIC           0 :             goto fail;
    1219                 : 
    1220                 :         /*
    1221                 :          * Windows, alone among our supported platforms, likes to emit
    1222                 :          * three-digit exponent fields even when two digits would do.  Hack
    1223 ECB             :          * such results to look like the way everyone else does it.
    1224                 :          */
    1225                 : #ifdef WIN32
    1226                 :         if (vallen >= 6 &&
    1227                 :             convert[vallen - 5] == 'e' &&
    1228                 :             convert[vallen - 3] == '0')
    1229                 :         {
    1230 EUB             :             convert[vallen - 3] = convert[vallen - 2];
    1231                 :             convert[vallen - 2] = convert[vallen - 1];
    1232                 :             vallen--;
    1233                 :         }
    1234                 : #endif
    1235                 :     }
    1236                 : 
    1237 GBC      194581 :     padlen = compute_padlen(minlen, vallen + zeropadlen, leftjust);
    1238 EUB             : 
    1239 GBC      194581 :     leading_pad(zpad, signvalue, &padlen, target);
    1240                 : 
    1241 GIC      194581 :     if (zeropadlen > 0)
    1242                 :     {
    1243                 :         /* If 'e' or 'E' format, inject zeroes before the exponent */
    1244 UBC           0 :         char       *epos = strrchr(convert, 'e');
    1245 EUB             : 
    1246 UIC           0 :         if (!epos)
    1247               0 :             epos = strrchr(convert, 'E');
    1248               0 :         if (epos)
    1249                 :         {
    1250                 :             /* pad before exponent */
    1251 LBC           0 :             dostr(convert, epos - convert, target);
    1252 UIC           0 :             dopr_outchmulti('0', zeropadlen, target);
    1253               0 :             dostr(epos, vallen - (epos - convert), target);
    1254 ECB             :         }
    1255                 :         else
    1256                 :         {
    1257 EUB             :             /* no exponent, pad after the digits */
    1258 UBC           0 :             dostr(convert, vallen, target);
    1259 UIC           0 :             dopr_outchmulti('0', zeropadlen, target);
    1260                 :         }
    1261                 :     }
    1262                 :     else
    1263                 :     {
    1264                 :         /* no zero padding, just emit the number as-is */
    1265 GIC      194581 :         dostr(convert, vallen, target);
    1266                 :     }
    1267                 : 
    1268          194581 :     trailing_pad(padlen, target);
    1269          194581 :     return;
    1270                 : 
    1271 LBC           0 : fail:
    1272 UIC           0 :     target->failed = true;
    1273                 : }
    1274 ECB             : 
    1275                 : /*
    1276                 :  * Nonstandard entry point to print a double value efficiently.
    1277                 :  *
    1278                 :  * This is approximately equivalent to strfromd(), but has an API more
    1279                 :  * adapted to what float8out() wants.  The behavior is like snprintf()
    1280                 :  * with a format of "%.ng", where n is the specified precision.
    1281                 :  * However, the target buffer must be nonempty (i.e. count > 0), and
    1282                 :  * the precision is silently bounded to a sane range.
    1283                 :  */
    1284                 : int
    1285 CBC      114994 : pg_strfromd(char *str, size_t count, int precision, double value)
    1286                 : {
    1287                 :     PrintfTarget target;
    1288 GIC      114994 :     int         signvalue = 0;
    1289                 :     int         vallen;
    1290                 :     char        fmt[8];
    1291                 :     char        convert[64];
    1292 ECB             : 
    1293 EUB             :     /* Set up the target like pg_snprintf, but require nonempty buffer */
    1294 CBC      114994 :     Assert(count > 0);
    1295 GBC      114994 :     target.bufstart = target.bufptr = str;
    1296 GIC      114994 :     target.bufend = str + count - 1;
    1297          114994 :     target.stream = NULL;
    1298          114994 :     target.nchars = 0;
    1299          114994 :     target.failed = false;
    1300                 : 
    1301 ECB             :     /*
    1302                 :      * We bound precision to a reasonable range; the combination of this and
    1303                 :      * the knowledge that we're using "g" format without padding allows the
    1304                 :      * convert[] buffer to be reasonably small.
    1305                 :      */
    1306 GIC      114994 :     if (precision < 1)
    1307 UIC           0 :         precision = 1;
    1308 GIC      114994 :     else if (precision > 32)
    1309 UIC           0 :         precision = 32;
    1310 ECB             : 
    1311                 :     /*
    1312                 :      * The rest is just an inlined version of the fmtfloat() logic above,
    1313                 :      * simplified using the knowledge that no padding is wanted.
    1314                 :      */
    1315 CBC      114994 :     if (isnan(value))
    1316                 :     {
    1317 GIC        6042 :         strcpy(convert, "NaN");
    1318 CBC        6042 :         vallen = 3;
    1319                 :     }
    1320 ECB             :     else
    1321                 :     {
    1322                 :         static const double dzero = 0.0;
    1323                 : 
    1324 GIC      108952 :         if (value < 0.0 ||
    1325 CBC       92755 :             (value == 0.0 &&
    1326           13433 :              memcmp(&value, &dzero, sizeof(double)) != 0))
    1327 ECB             :         {
    1328 CBC       16230 :             signvalue = '-';
    1329           16230 :             value = -value;
    1330 ECB             :         }
    1331                 : 
    1332 GIC      108952 :         if (isinf(value))
    1333 EUB             :         {
    1334 GBC        3546 :             strcpy(convert, "Infinity");
    1335 GIC        3546 :             vallen = 8;
    1336                 :         }
    1337                 :         else
    1338                 :         {
    1339          105406 :             fmt[0] = '%';
    1340          105406 :             fmt[1] = '.';
    1341          105406 :             fmt[2] = '*';
    1342          105406 :             fmt[3] = 'g';
    1343          105406 :             fmt[4] = '\0';
    1344          105406 :             vallen = snprintf(convert, sizeof(convert), fmt, precision, value);
    1345          105406 :             if (vallen < 0)
    1346                 :             {
    1347 UIC           0 :                 target.failed = true;
    1348               0 :                 goto fail;
    1349                 :             }
    1350 ECB             : 
    1351                 : #ifdef WIN32
    1352                 :             if (vallen >= 6 &&
    1353                 :                 convert[vallen - 5] == 'e' &&
    1354                 :                 convert[vallen - 3] == '0')
    1355                 :             {
    1356                 :                 convert[vallen - 3] = convert[vallen - 2];
    1357                 :                 convert[vallen - 2] = convert[vallen - 1];
    1358                 :                 vallen--;
    1359                 :             }
    1360                 : #endif
    1361                 :         }
    1362                 :     }
    1363                 : 
    1364 GIC      114994 :     if (signvalue)
    1365           16230 :         dopr_outch(signvalue, &target);
    1366 ECB             : 
    1367 GIC      114994 :     dostr(convert, vallen, &target);
    1368 ECB             : 
    1369 CBC      114994 : fail:
    1370 GIC      114994 :     *(target.bufptr) = '\0';
    1371          229988 :     return target.failed ? -1 : (target.bufptr - target.bufstart
    1372 CBC      114994 :                                  + target.nchars);
    1373                 : }
    1374                 : 
    1375                 : 
    1376 ECB             : static void
    1377 CBC   151516206 : dostr(const char *str, int slen, PrintfTarget *target)
    1378                 : {
    1379 ECB             :     /* fast path for common case of slen == 1 */
    1380 CBC   151516206 :     if (slen == 1)
    1381                 :     {
    1382 GIC    55737028 :         dopr_outch(*str, target);
    1383 CBC    55737031 :         return;
    1384                 :     }
    1385 ECB             : 
    1386 CBC   190540911 :     while (slen > 0)
    1387                 :     {
    1388 ECB             :         int         avail;
    1389                 : 
    1390 GIC    94898471 :         if (target->bufend != NULL)
    1391 CBC    92966699 :             avail = target->bufend - target->bufptr;
    1392 ECB             :         else
    1393 CBC     1931772 :             avail = slen;
    1394        94898471 :         if (avail <= 0)
    1395 ECB             :         {
    1396                 :             /* buffer full, can we dump to stream? */
    1397 GIC      136848 :             if (target->stream == NULL)
    1398                 :             {
    1399          136738 :                 target->nchars += slen; /* no, lose the data */
    1400 CBC      136738 :                 return;
    1401                 :             }
    1402             110 :             flushbuffer(target);
    1403 GIC         110 :             continue;
    1404                 :         }
    1405 CBC    94761623 :         avail = Min(avail, slen);
    1406 GIC    94761623 :         memmove(target->bufptr, str, avail);
    1407 CBC    94761623 :         target->bufptr += avail;
    1408        94761623 :         str += avail;
    1409 GIC    94761623 :         slen -= avail;
    1410 EUB             :     }
    1411                 : }
    1412 ECB             : 
    1413                 : static void
    1414 GIC    63685546 : dopr_outch(int c, PrintfTarget *target)
    1415                 : {
    1416 CBC    63685546 :     if (target->bufend != NULL && target->bufptr >= target->bufend)
    1417                 :     {
    1418                 :         /* buffer full, can we dump to stream? */
    1419           23003 :         if (target->stream == NULL)
    1420                 :         {
    1421           23003 :             target->nchars++;    /* no, lose the data */
    1422           23003 :             return;
    1423                 :         }
    1424 UIC           0 :         flushbuffer(target);
    1425 ECB             :     }
    1426 GIC    63662546 :     *(target->bufptr++) = c;
    1427                 : }
    1428                 : 
    1429 ECB             : static void
    1430 CBC     1591677 : dopr_outchmulti(int c, int slen, PrintfTarget *target)
    1431                 : {
    1432 ECB             :     /* fast path for common case of slen == 1 */
    1433 CBC     1591677 :     if (slen == 1)
    1434                 :     {
    1435 GIC     1242641 :         dopr_outch(c, target);
    1436 CBC     1242641 :         return;
    1437                 :     }
    1438 EUB             : 
    1439 GBC      698389 :     while (slen > 0)
    1440                 :     {
    1441 ECB             :         int         avail;
    1442                 : 
    1443 GIC      349353 :         if (target->bufend != NULL)
    1444 CBC      345041 :             avail = target->bufend - target->bufptr;
    1445 ECB             :         else
    1446 CBC        4312 :             avail = slen;
    1447          349353 :         if (avail <= 0)
    1448                 :         {
    1449                 :             /* buffer full, can we dump to stream? */
    1450 GIC         160 :             if (target->stream == NULL)
    1451                 :             {
    1452 UIC           0 :                 target->nchars += slen; /* no, lose the data */
    1453 LBC           0 :                 return;
    1454                 :             }
    1455 CBC         160 :             flushbuffer(target);
    1456 GIC         160 :             continue;
    1457 ECB             :         }
    1458 CBC      349193 :         avail = Min(avail, slen);
    1459 GIC      349193 :         memset(target->bufptr, c, avail);
    1460 CBC      349193 :         target->bufptr += avail;
    1461          349193 :         slen -= avail;
    1462 ECB             :     }
    1463                 : }
    1464                 : 
    1465                 : 
    1466                 : static int
    1467 CBC    36891898 : adjust_sign(int is_negative, int forcesign, int *signvalue)
    1468                 : {
    1469 GIC    36891898 :     if (is_negative)
    1470                 :     {
    1471 CBC     6668788 :         *signvalue = '-';
    1472         6668788 :         return true;
    1473 ECB             :     }
    1474 CBC    30223110 :     else if (forcesign)
    1475              93 :         *signvalue = '+';
    1476        30223110 :     return false;
    1477                 : }
    1478                 : 
    1479                 : 
    1480                 : static int
    1481        67324347 : compute_padlen(int minlen, int vallen, int leftjust)
    1482                 : {
    1483                 :     int         padlen;
    1484                 : 
    1485        67324347 :     padlen = minlen - vallen;
    1486 GIC    67324347 :     if (padlen < 0)
    1487 CBC    63887213 :         padlen = 0;
    1488 GIC    67324347 :     if (leftjust)
    1489 CBC      223188 :         padlen = -padlen;
    1490        67324347 :     return padlen;
    1491 ECB             : }
    1492                 : 
    1493                 : 
    1494                 : static void
    1495 CBC    66698375 : leading_pad(int zpad, int signvalue, int *padlen, PrintfTarget *target)
    1496 ECB             : {
    1497                 :     int         maxpad;
    1498                 : 
    1499 CBC    66698375 :     if (*padlen > 0 && zpad)
    1500 ECB             :     {
    1501 GIC     1248275 :         if (signvalue)
    1502 ECB             :         {
    1503 CBC          90 :             dopr_outch(signvalue, target);
    1504 GIC          90 :             --(*padlen);
    1505 CBC          90 :             signvalue = 0;
    1506                 :         }
    1507         1248275 :         if (*padlen > 0)
    1508 ECB             :         {
    1509 GBC     1248266 :             dopr_outchmulti(zpad, *padlen, target);
    1510 CBC     1248266 :             *padlen = 0;
    1511 EUB             :         }
    1512                 :     }
    1513 CBC    66698375 :     maxpad = (signvalue != 0);
    1514 GIC    66698375 :     if (*padlen > maxpad)
    1515                 :     {
    1516            5264 :         dopr_outchmulti(' ', *padlen - maxpad, target);
    1517 CBC        5264 :         *padlen = maxpad;
    1518                 :     }
    1519        66698375 :     if (signvalue)
    1520 ECB             :     {
    1521 CBC     6668791 :         dopr_outch(signvalue, target);
    1522 GIC     6668791 :         if (*padlen > 0)
    1523 UIC           0 :             --(*padlen);
    1524 GIC     6668791 :         else if (*padlen < 0)
    1525 UIC           0 :             ++(*padlen);
    1526                 :     }
    1527 GIC    66698375 : }
    1528                 : 
    1529                 : 
    1530                 : static void
    1531        67324353 : trailing_pad(int padlen, PrintfTarget *target)
    1532                 : {
    1533        67324353 :     if (padlen < 0)
    1534           82045 :         dopr_outchmulti(' ', -padlen, target);
    1535        67324353 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a