LTP GCOV extension - code coverage report
Current view: directory - home/smbbuild/build_farm/samba_4_0_test/lib/replace - snprintf.c
Test: samba_4_0_test.lcov.info
Date: 2010-08-06 Instrumented lines: 1
Code covered: 0.0 % Executed lines: 0

       1                 : /*
       2                 :  * NOTE: If you change this file, please merge it into rsync, samba, etc.
       3                 :  */
       4                 : 
       5                 : /*
       6                 :  * Copyright Patrick Powell 1995
       7                 :  * This code is based on code written by Patrick Powell (papowell@astart.com)
       8                 :  * It may be used for any purpose as long as this notice remains intact
       9                 :  * on all source code distributions
      10                 :  */
      11                 : 
      12                 : /**************************************************************
      13                 :  * Original:
      14                 :  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
      15                 :  * A bombproof version of doprnt (dopr) included.
      16                 :  * Sigh.  This sort of thing is always nasty do deal with.  Note that
      17                 :  * the version here does not include floating point...
      18                 :  *
      19                 :  * snprintf() is used instead of sprintf() as it does limit checks
      20                 :  * for string length.  This covers a nasty loophole.
      21                 :  *
      22                 :  * The other functions are there to prevent NULL pointers from
      23                 :  * causing nast effects.
      24                 :  *
      25                 :  * More Recently:
      26                 :  *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
      27                 :  *  This was ugly.  It is still ugly.  I opted out of floating point
      28                 :  *  numbers, but the formatter understands just about everything
      29                 :  *  from the normal C string format, at least as far as I can tell from
      30                 :  *  the Solaris 2.5 printf(3S) man page.
      31                 :  *
      32                 :  *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
      33                 :  *    Ok, added some minimal floating point support, which means this
      34                 :  *    probably requires libm on most operating systems.  Don't yet
      35                 :  *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
      36                 :  *    was pretty badly broken, it just wasn't being exercised in ways
      37                 :  *    which showed it, so that's been fixed.  Also, formated the code
      38                 :  *    to mutt conventions, and removed dead code left over from the
      39                 :  *    original.  Also, there is now a builtin-test, just compile with:
      40                 :  *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
      41                 :  *    and run snprintf for results.
      42                 :  * 
      43                 :  *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
      44                 :  *    The PGP code was using unsigned hexadecimal formats. 
      45                 :  *    Unfortunately, unsigned formats simply didn't work.
      46                 :  *
      47                 :  *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
      48                 :  *    The original code assumed that both snprintf() and vsnprintf() were
      49                 :  *    missing.  Some systems only have snprintf() but not vsnprintf(), so
      50                 :  *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
      51                 :  *
      52                 :  *  Andrew Tridgell (tridge@samba.org) Oct 1998
      53                 :  *    fixed handling of %.0f
      54                 :  *    added test for HAVE_LONG_DOUBLE
      55                 :  *
      56                 :  * tridge@samba.org, idra@samba.org, April 2001
      57                 :  *    got rid of fcvt code (twas buggy and made testing harder)
      58                 :  *    added C99 semantics
      59                 :  *
      60                 :  * date: 2002/12/19 19:56:31;  author: herb;  state: Exp;  lines: +2 -0
      61                 :  * actually print args for %g and %e
      62                 :  * 
      63                 :  * date: 2002/06/03 13:37:52;  author: jmcd;  state: Exp;  lines: +8 -0
      64                 :  * Since includes.h isn't included here, VA_COPY has to be defined here.  I don't
      65                 :  * see any include file that is guaranteed to be here, so I'm defining it
      66                 :  * locally.  Fixes AIX and Solaris builds.
      67                 :  * 
      68                 :  * date: 2002/06/03 03:07:24;  author: tridge;  state: Exp;  lines: +5 -13
      69                 :  * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
      70                 :  * functions
      71                 :  * 
      72                 :  * date: 2002/05/17 14:51:22;  author: jmcd;  state: Exp;  lines: +21 -4
      73                 :  * Fix usage of va_list passed as an arg.  Use __va_copy before using it
      74                 :  * when it exists.
      75                 :  * 
      76                 :  * date: 2002/04/16 22:38:04;  author: idra;  state: Exp;  lines: +20 -14
      77                 :  * Fix incorrect zpadlen handling in fmtfp.
      78                 :  * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
      79                 :  * few mods to make it easier to compile the tests.
      80                 :  * addedd the "Ollie" test to the floating point ones.
      81                 :  *
      82                 :  * Martin Pool (mbp@samba.org) April 2003
      83                 :  *    Remove NO_CONFIG_H so that the test case can be built within a source
      84                 :  *    tree with less trouble.
      85                 :  *    Remove unnecessary SAFE_FREE() definition.
      86                 :  *
      87                 :  * Martin Pool (mbp@samba.org) May 2003
      88                 :  *    Put in a prototype for dummy_snprintf() to quiet compiler warnings.
      89                 :  *
      90                 :  *    Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
      91                 :  *    if the C library has some snprintf functions already.
      92                 :  *
      93                 :  * Darren Tucker (dtucker@zip.com.au) 2005
      94                 :  *    Fix bug allowing read overruns of the source string with "%.*s"
      95                 :  *    Usually harmless unless the read runs outside the process' allocation
      96                 :  *    (eg if your malloc does guard pages) in which case it will segfault.
      97                 :  *    From OpenSSH.  Also added test for same.
      98                 :  *
      99                 :  * Simo Sorce (idra@samba.org) Jan 2006
     100                 :  * 
     101                 :  *    Add support for position independent parameters 
     102                 :  *    fix fmtstr now it conforms to sprintf wrt min.max
     103                 :  *
     104                 :  **************************************************************/
     105                 : 
     106                 : #include "replace.h"
     107                 : #include "system/locale.h"
     108                 : 
     109                 : #ifdef TEST_SNPRINTF /* need math library headers for testing */
     110                 : 
     111                 : /* In test mode, we pretend that this system doesn't have any snprintf
     112                 :  * functions, regardless of what config.h says. */
     113                 : #  undef HAVE_SNPRINTF
     114                 : #  undef HAVE_VSNPRINTF
     115                 : #  undef HAVE_C99_VSNPRINTF
     116                 : #  undef HAVE_ASPRINTF
     117                 : #  undef HAVE_VASPRINTF
     118                 : #  include <math.h>
     119                 : #endif /* TEST_SNPRINTF */
     120                 : 
     121                 : #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
     122                 : /* only include stdio.h if we are not re-defining snprintf or vsnprintf */
     123                 : #include <stdio.h>
     124                 :  /* make the compiler happy with an empty file */
     125                 :  void dummy_snprintf(void);
     126               0 :  void dummy_snprintf(void) {} 
     127                 : #endif /* HAVE_SNPRINTF, etc */
     128                 : 
     129                 : /* yes this really must be a ||. Don't muck with this (tridge) */
     130                 : #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
     131                 : 
     132                 : #ifdef HAVE_LONG_DOUBLE
     133                 : #define LDOUBLE long double
     134                 : #else
     135                 : #define LDOUBLE double
     136                 : #endif
     137                 : 
     138                 : #ifdef HAVE_LONG_LONG
     139                 : #define LLONG long long
     140                 : #else
     141                 : #define LLONG long
     142                 : #endif
     143                 : 
     144                 : #ifndef VA_COPY
     145                 : #ifdef HAVE_VA_COPY
     146                 : #define VA_COPY(dest, src) va_copy(dest, src)
     147                 : #else
     148                 : #ifdef HAVE___VA_COPY
     149                 : #define VA_COPY(dest, src) __va_copy(dest, src)
     150                 : #else
     151                 : #define VA_COPY(dest, src) (dest) = (src)
     152                 : #endif
     153                 : #endif
     154                 : 
     155                 : /*
     156                 :  * dopr(): poor man's version of doprintf
     157                 :  */
     158                 : 
     159                 : /* format read states */
     160                 : #define DP_S_DEFAULT 0
     161                 : #define DP_S_FLAGS   1
     162                 : #define DP_S_MIN     2
     163                 : #define DP_S_DOT     3
     164                 : #define DP_S_MAX     4
     165                 : #define DP_S_MOD     5
     166                 : #define DP_S_CONV    6
     167                 : #define DP_S_DONE    7
     168                 : 
     169                 : /* format flags - Bits */
     170                 : #define DP_F_MINUS      (1 << 0)
     171                 : #define DP_F_PLUS       (1 << 1)
     172                 : #define DP_F_SPACE      (1 << 2)
     173                 : #define DP_F_NUM        (1 << 3)
     174                 : #define DP_F_ZERO       (1 << 4)
     175                 : #define DP_F_UP         (1 << 5)
     176                 : #define DP_F_UNSIGNED   (1 << 6)
     177                 : 
     178                 : /* Conversion Flags */
     179                 : #define DP_C_CHAR    1
     180                 : #define DP_C_SHORT   2
     181                 : #define DP_C_LONG    3
     182                 : #define DP_C_LDOUBLE 4
     183                 : #define DP_C_LLONG   5
     184                 : #define DP_C_SIZET   6
     185                 : 
     186                 : /* Chunk types */
     187                 : #define CNK_FMT_STR 0
     188                 : #define CNK_INT     1
     189                 : #define CNK_OCTAL   2
     190                 : #define CNK_UINT    3
     191                 : #define CNK_HEX     4
     192                 : #define CNK_FLOAT   5
     193                 : #define CNK_CHAR    6
     194                 : #define CNK_STRING  7
     195                 : #define CNK_PTR     8
     196                 : #define CNK_NUM     9
     197                 : #define CNK_PRCNT   10
     198                 : 
     199                 : #define char_to_int(p) ((p)- '0')
     200                 : #ifndef MAX
     201                 : #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
     202                 : #endif
     203                 : 
     204                 : struct pr_chunk {
     205                 :         int type; /* chunk type */
     206                 :         int num; /* parameter number */
     207                 :         int min; 
     208                 :         int max;
     209                 :         int flags;
     210                 :         int cflags;
     211                 :         int start;
     212                 :         int len;
     213                 :         LLONG value;
     214                 :         LDOUBLE fvalue;
     215                 :         char *strvalue;
     216                 :         void *pnum;
     217                 :         struct pr_chunk *min_star;
     218                 :         struct pr_chunk *max_star;
     219                 :         struct pr_chunk *next;
     220                 : };
     221                 : 
     222                 : struct pr_chunk_x {
     223                 :         struct pr_chunk **chunks;
     224                 :         int num;
     225                 : };
     226                 : 
     227                 : static int dopr(char *buffer, size_t maxlen, const char *format, 
     228                 :                    va_list args_in);
     229                 : static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
     230                 :                     char *value, int flags, int min, int max);
     231                 : static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
     232                 :                     LLONG value, int base, int min, int max, int flags);
     233                 : static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
     234                 :                    LDOUBLE fvalue, int min, int max, int flags);
     235                 : static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
     236                 : static struct pr_chunk *new_chunk(void);
     237                 : static int add_cnk_list_entry(struct pr_chunk_x **list,
     238                 :                                 int max_num, struct pr_chunk *chunk);
     239                 : 
     240                 : static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
     241                 : {
     242                 :         char ch;
     243                 :         int state;
     244                 :         int pflag;
     245                 :         int pnum;
     246                 :         int pfirst;
     247                 :         size_t currlen;
     248                 :         va_list args;
     249                 :         const char *base;
     250                 :         struct pr_chunk *chunks = NULL;
     251                 :         struct pr_chunk *cnk = NULL;
     252                 :         struct pr_chunk_x *clist = NULL;
     253                 :         int max_pos;
     254                 :         int ret = -1;
     255                 : 
     256                 :         VA_COPY(args, args_in);
     257                 : 
     258                 :         state = DP_S_DEFAULT;
     259                 :         pfirst = 1;
     260                 :         pflag = 0;
     261                 :         pnum = 0;
     262                 : 
     263                 :         max_pos = 0;
     264                 :         base = format;
     265                 :         ch = *format++;
     266                 :         
     267                 :         /* retrieve the string structure as chunks */
     268                 :         while (state != DP_S_DONE) {
     269                 :                 if (ch == '\0') 
     270                 :                         state = DP_S_DONE;
     271                 : 
     272                 :                 switch(state) {
     273                 :                 case DP_S_DEFAULT:
     274                 :                         
     275                 :                         if (cnk) {
     276                 :                                 cnk->next = new_chunk();
     277                 :                                 cnk = cnk->next;
     278                 :                         } else {
     279                 :                                 cnk = new_chunk();
     280                 :                         }
     281                 :                         if (!cnk) goto done;
     282                 :                         if (!chunks) chunks = cnk;
     283                 :                         
     284                 :                         if (ch == '%') {
     285                 :                                 state = DP_S_FLAGS;
     286                 :                                 ch = *format++;
     287                 :                         } else {
     288                 :                                 cnk->type = CNK_FMT_STR;
     289                 :                                 cnk->start = format - base -1;
     290                 :                                 while ((ch != '\0') && (ch != '%')) ch = *format++;
     291                 :                                 cnk->len = format - base - cnk->start -1;
     292                 :                         }
     293                 :                         break;
     294                 :                 case DP_S_FLAGS:
     295                 :                         switch (ch) {
     296                 :                         case '-':
     297                 :                                 cnk->flags |= DP_F_MINUS;
     298                 :                                 ch = *format++;
     299                 :                                 break;
     300                 :                         case '+':
     301                 :                                 cnk->flags |= DP_F_PLUS;
     302                 :                                 ch = *format++;
     303                 :                                 break;
     304                 :                         case ' ':
     305                 :                                 cnk->flags |= DP_F_SPACE;
     306                 :                                 ch = *format++;
     307                 :                                 break;
     308                 :                         case '#':
     309                 :                                 cnk->flags |= DP_F_NUM;
     310                 :                                 ch = *format++;
     311                 :                                 break;
     312                 :                         case '0':
     313                 :                                 cnk->flags |= DP_F_ZERO;
     314                 :                                 ch = *format++;
     315                 :                                 break;
     316                 :                         case 'I':
     317                 :                                 /* internationalization not supported yet */
     318                 :                                 ch = *format++;
     319                 :                                 break;
     320                 :                         default:
     321                 :                                 state = DP_S_MIN;
     322                 :                                 break;
     323                 :                         }
     324                 :                         break;
     325                 :                 case DP_S_MIN:
     326                 :                         if (isdigit((unsigned char)ch)) {
     327                 :                                 cnk->min = 10 * cnk->min + char_to_int (ch);
     328                 :                                 ch = *format++;
     329                 :                         } else if (ch == '$') {
     330                 :                                 if (!pfirst && !pflag) {
     331                 :                                         /* parameters must be all positioned or none */
     332                 :                                         goto done;
     333                 :                                 }
     334                 :                                 if (pfirst) {
     335                 :                                         pfirst = 0;
     336                 :                                         pflag = 1;
     337                 :                                 }
     338                 :                                 if (cnk->min == 0) /* what ?? */
     339                 :                                         goto done;
     340                 :                                 cnk->num = cnk->min;
     341                 :                                 cnk->min = 0;
     342                 :                                 ch = *format++;
     343                 :                         } else if (ch == '*') {
     344                 :                                 if (pfirst) pfirst = 0;
     345                 :                                 cnk->min_star = new_chunk();
     346                 :                                 if (!cnk->min_star) /* out of memory :-( */
     347                 :                                         goto done;
     348                 :                                 cnk->min_star->type = CNK_INT;
     349                 :                                 if (pflag) {
     350                 :                                         int num;
     351                 :                                         ch = *format++;
     352                 :                                         if (!isdigit((unsigned char)ch)) {
     353                 :                                                 /* parameters must be all positioned or none */
     354                 :                                                 goto done;
     355                 :                                         }
     356                 :                                         for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
     357                 :                                                 num = 10 * num + char_to_int(ch);
     358                 :                                         }
     359                 :                                         cnk->min_star->num = num;
     360                 :                                         if (ch != '$') /* what ?? */
     361                 :                                                 goto done;
     362                 :                                 } else {
     363                 :                                         cnk->min_star->num = ++pnum;
     364                 :                                 }
     365                 :                                 max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star);
     366                 :                                 if (max_pos == 0) /* out of memory :-( */
     367                 :                                         goto done;
     368                 :                                 ch = *format++;
     369                 :                                 state = DP_S_DOT;
     370                 :                         } else {
     371                 :                                 if (pfirst) pfirst = 0;
     372                 :                                 state = DP_S_DOT;
     373                 :                         }
     374                 :                         break;
     375                 :                 case DP_S_DOT:
     376                 :                         if (ch == '.') {
     377                 :                                 state = DP_S_MAX;
     378                 :                                 ch = *format++;
     379                 :                         } else { 
     380                 :                                 state = DP_S_MOD;
     381                 :                         }
     382                 :                         break;
     383                 :                 case DP_S_MAX:
     384                 :                         if (isdigit((unsigned char)ch)) {
     385                 :                                 if (cnk->max < 0)
     386                 :                                         cnk->max = 0;
     387                 :                                 cnk->max = 10 * cnk->max + char_to_int (ch);
     388                 :                                 ch = *format++;
     389                 :                         } else if (ch == '$') {
     390                 :                                 if (!pfirst && !pflag) {
     391                 :                                         /* parameters must be all positioned or none */
     392                 :                                         goto done;
     393                 :                                 }
     394                 :                                 if (cnk->max <= 0) /* what ?? */
     395                 :                                         goto done;
     396                 :                                 cnk->num = cnk->max;
     397                 :                                 cnk->max = -1;
     398                 :                                 ch = *format++;
     399                 :                         } else if (ch == '*') {
     400                 :                                 cnk->max_star = new_chunk();
     401                 :                                 if (!cnk->max_star) /* out of memory :-( */
     402                 :                                         goto done;
     403                 :                                 cnk->max_star->type = CNK_INT;
     404                 :                                 if (pflag) {
     405                 :                                         int num;
     406                 :                                         ch = *format++;
     407                 :                                         if (!isdigit((unsigned char)ch)) {
     408                 :                                                 /* parameters must be all positioned or none */
     409                 :                                                 goto done;
     410                 :                                         }
     411                 :                                         for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
     412                 :                                                 num = 10 * num + char_to_int(ch);
     413                 :                                         }
     414                 :                                         cnk->max_star->num = num;
     415                 :                                         if (ch != '$') /* what ?? */
     416                 :                                                 goto done;
     417                 :                                 } else {
     418                 :                                         cnk->max_star->num = ++pnum;
     419                 :                                 }
     420                 :                                 max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star);
     421                 :                                 if (max_pos == 0) /* out of memory :-( */
     422                 :                                         goto done;
     423                 : 
     424                 :                                 ch = *format++;
     425                 :                                 state = DP_S_MOD;
     426                 :                         } else {
     427                 :                                 state = DP_S_MOD;
     428                 :                         }
     429                 :                         break;
     430                 :                 case DP_S_MOD:
     431                 :                         switch (ch) {
     432                 :                         case 'h':
     433                 :                                 cnk->cflags = DP_C_SHORT;
     434                 :                                 ch = *format++;
     435                 :                                 if (ch == 'h') {
     436                 :                                         cnk->cflags = DP_C_CHAR;
     437                 :                                         ch = *format++;
     438                 :                                 }
     439                 :                                 break;
     440                 :                         case 'l':
     441                 :                                 cnk->cflags = DP_C_LONG;
     442                 :                                 ch = *format++;
     443                 :                                 if (ch == 'l') {        /* It's a long long */
     444                 :                                         cnk->cflags = DP_C_LLONG;
     445                 :                                         ch = *format++;
     446                 :                                 }
     447                 :                                 break;
     448                 :                         case 'L':
     449                 :                                 cnk->cflags = DP_C_LDOUBLE;
     450                 :                                 ch = *format++;
     451                 :                                 break;
     452                 :                         case 'z':
     453                 :                                 cnk->cflags = DP_C_SIZET;
     454                 :                                 ch = *format++;
     455                 :                                 break;
     456                 :                         default:
     457                 :                                 break;
     458                 :                         }
     459                 :                         state = DP_S_CONV;
     460                 :                         break;
     461                 :                 case DP_S_CONV:
     462                 :                         if (cnk->num == 0) cnk->num = ++pnum;
     463                 :                         max_pos = add_cnk_list_entry(&clist, max_pos, cnk);
     464                 :                         if (max_pos == 0) /* out of memory :-( */
     465                 :                                 goto done;
     466                 :                         
     467                 :                         switch (ch) {
     468                 :                         case 'd':
     469                 :                         case 'i':
     470                 :                                 cnk->type = CNK_INT;
     471                 :                                 break;
     472                 :                         case 'o':
     473                 :                                 cnk->type = CNK_OCTAL;
     474                 :                                 cnk->flags |= DP_F_UNSIGNED;
     475                 :                                 break;
     476                 :                         case 'u':
     477                 :                                 cnk->type = CNK_UINT;
     478                 :                                 cnk->flags |= DP_F_UNSIGNED;
     479                 :                                 break;
     480                 :                         case 'X':
     481                 :                                 cnk->flags |= DP_F_UP;
     482                 :                         case 'x':
     483                 :                                 cnk->type = CNK_HEX;
     484                 :                                 cnk->flags |= DP_F_UNSIGNED;
     485                 :                                 break;
     486                 :                         case 'A':
     487                 :                                 /* hex float not supported yet */
     488                 :                         case 'E':
     489                 :                         case 'G':
     490                 :                         case 'F':
     491                 :                                 cnk->flags |= DP_F_UP;
     492                 :                         case 'a':
     493                 :                                 /* hex float not supported yet */
     494                 :                         case 'e':
     495                 :                         case 'f':
     496                 :                         case 'g':
     497                 :                                 cnk->type = CNK_FLOAT;
     498                 :                                 break;
     499                 :                         case 'c':
     500                 :                                 cnk->type = CNK_CHAR;
     501                 :                                 break;
     502                 :                         case 's':
     503                 :                                 cnk->type = CNK_STRING;
     504                 :                                 break;
     505                 :                         case 'p':
     506                 :                                 cnk->type = CNK_PTR;
     507                 :                                 cnk->flags |= DP_F_UNSIGNED;
     508                 :                                 break;
     509                 :                         case 'n':
     510                 :                                 cnk->type = CNK_NUM;
     511                 :                                 break;
     512                 :                         case '%':
     513                 :                                 cnk->type = CNK_PRCNT;
     514                 :                                 break;
     515                 :                         default:
     516                 :                                 /* Unknown, bail out*/
     517                 :                                 goto done;
     518                 :                         }
     519                 :                         ch = *format++;
     520                 :                         state = DP_S_DEFAULT;
     521                 :                         break;
     522                 :                 case DP_S_DONE:
     523                 :                         break;
     524                 :                 default:
     525                 :                         /* hmm? */
     526                 :                         break; /* some picky compilers need this */
     527                 :                 }
     528                 :         }
     529                 : 
     530                 :         /* retrieve the format arguments */
     531                 :         for (pnum = 0; pnum < max_pos; pnum++) {
     532                 :                 int i;
     533                 : 
     534                 :                 if (clist[pnum].num == 0) {
     535                 :                         /* ignoring a parameter should not be permitted
     536                 :                          * all parameters must be matched at least once
     537                 :                          * BUT seem some system ignore this rule ...
     538                 :                          * at least my glibc based system does --SSS
     539                 :                          */
     540                 : #ifdef DEBUG_SNPRINTF
     541                 :                         printf("parameter at position %d not used\n", pnum+1);
     542                 : #endif
     543                 :                         /* eat the parameter */
     544                 :                         va_arg (args, int);
     545                 :                         continue;
     546                 :                 }
     547                 :                 for (i = 1; i < clist[pnum].num; i++) {
     548                 :                         if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) {
     549                 :                                 /* nooo noo no!
     550                 :                                  * all the references to a parameter
     551                 :                                  * must be of the same type
     552                 :                                  */
     553                 :                                 goto done;
     554                 :                         }
     555                 :                 }
     556                 :                 cnk = clist[pnum].chunks[0];
     557                 :                 switch (cnk->type) {
     558                 :                 case CNK_INT:
     559                 :                         if (cnk->cflags == DP_C_SHORT) 
     560                 :                                 cnk->value = va_arg (args, int);
     561                 :                         else if (cnk->cflags == DP_C_LONG)
     562                 :                                 cnk->value = va_arg (args, long int);
     563                 :                         else if (cnk->cflags == DP_C_LLONG)
     564                 :                                 cnk->value = va_arg (args, LLONG);
     565                 :                         else if (cnk->cflags == DP_C_SIZET)
     566                 :                                 cnk->value = va_arg (args, ssize_t);
     567                 :                         else
     568                 :                                 cnk->value = va_arg (args, int);
     569                 : 
     570                 :                         for (i = 1; i < clist[pnum].num; i++) {
     571                 :                                 clist[pnum].chunks[i]->value = cnk->value;
     572                 :                         }
     573                 :                         break;
     574                 : 
     575                 :                 case CNK_OCTAL:
     576                 :                 case CNK_UINT:
     577                 :                 case CNK_HEX:
     578                 :                         if (cnk->cflags == DP_C_SHORT)
     579                 :                                 cnk->value = va_arg (args, unsigned int);
     580                 :                         else if (cnk->cflags == DP_C_LONG)
     581                 :                                 cnk->value = (unsigned long int)va_arg (args, unsigned long int);
     582                 :                         else if (cnk->cflags == DP_C_LLONG)
     583                 :                                 cnk->value = (LLONG)va_arg (args, unsigned LLONG);
     584                 :                         else if (cnk->cflags == DP_C_SIZET)
     585                 :                                 cnk->value = (size_t)va_arg (args, size_t);
     586                 :                         else
     587                 :                                 cnk->value = (unsigned int)va_arg (args, unsigned int);
     588                 : 
     589                 :                         for (i = 1; i < clist[pnum].num; i++) {
     590                 :                                 clist[pnum].chunks[i]->value = cnk->value;
     591                 :                         }
     592                 :                         break;
     593                 : 
     594                 :                 case CNK_FLOAT:
     595                 :                         if (cnk->cflags == DP_C_LDOUBLE)
     596                 :                                 cnk->fvalue = va_arg (args, LDOUBLE);
     597                 :                         else
     598                 :                                 cnk->fvalue = va_arg (args, double);
     599                 : 
     600                 :                         for (i = 1; i < clist[pnum].num; i++) {
     601                 :                                 clist[pnum].chunks[i]->fvalue = cnk->fvalue;
     602                 :                         }
     603                 :                         break;
     604                 : 
     605                 :                 case CNK_CHAR:
     606                 :                         cnk->value = va_arg (args, int);
     607                 : 
     608                 :                         for (i = 1; i < clist[pnum].num; i++) {
     609                 :                                 clist[pnum].chunks[i]->value = cnk->value;
     610                 :                         }
     611                 :                         break;
     612                 : 
     613                 :                 case CNK_STRING:
     614                 :                         cnk->strvalue = va_arg (args, char *);
     615                 :                         if (!cnk->strvalue) cnk->strvalue = "(NULL)";
     616                 : 
     617                 :                         for (i = 1; i < clist[pnum].num; i++) {
     618                 :                                 clist[pnum].chunks[i]->strvalue = cnk->strvalue;
     619                 :                         }
     620                 :                         break;
     621                 : 
     622                 :                 case CNK_PTR:
     623                 :                         cnk->strvalue = va_arg (args, void *);
     624                 :                         for (i = 1; i < clist[pnum].num; i++) {
     625                 :                                 clist[pnum].chunks[i]->strvalue = cnk->strvalue;
     626                 :                         }
     627                 :                         break;
     628                 : 
     629                 :                 case CNK_NUM:
     630                 :                         if (cnk->cflags == DP_C_CHAR)
     631                 :                                 cnk->pnum = va_arg (args, char *);
     632                 :                         else if (cnk->cflags == DP_C_SHORT)
     633                 :                                 cnk->pnum = va_arg (args, short int *);
     634                 :                         else if (cnk->cflags == DP_C_LONG)
     635                 :                                 cnk->pnum = va_arg (args, long int *);
     636                 :                         else if (cnk->cflags == DP_C_LLONG)
     637                 :                                 cnk->pnum = va_arg (args, LLONG *);
     638                 :                         else if (cnk->cflags == DP_C_SIZET)
     639                 :                                 cnk->pnum = va_arg (args, ssize_t *);
     640                 :                         else
     641                 :                                 cnk->pnum = va_arg (args, int *);
     642                 : 
     643                 :                         for (i = 1; i < clist[pnum].num; i++) {
     644                 :                                 clist[pnum].chunks[i]->pnum = cnk->pnum;
     645                 :                         }
     646                 :                         break;
     647                 : 
     648                 :                 case CNK_PRCNT:
     649                 :                         break;
     650                 : 
     651                 :                 default:
     652                 :                         /* what ?? */
     653                 :                         goto done;
     654                 :                 }
     655                 :         }
     656                 :         /* print out the actual string from chunks */
     657                 :         currlen = 0;
     658                 :         cnk = chunks;
     659                 :         while (cnk) {
     660                 :                 int len, min, max;
     661                 : 
     662                 :                 if (cnk->min_star) min = cnk->min_star->value;
     663                 :                 else min = cnk->min;
     664                 :                 if (cnk->max_star) max = cnk->max_star->value;
     665                 :                 else max = cnk->max;
     666                 : 
     667                 :                 switch (cnk->type) {
     668                 : 
     669                 :                 case CNK_FMT_STR:
     670                 :                         if (maxlen != 0 && maxlen > currlen) {
     671                 :                                 if (maxlen > (currlen + cnk->len)) len = cnk->len;
     672                 :                                 else len = maxlen - currlen;
     673                 : 
     674                 :                                 memcpy(&(buffer[currlen]), &(base[cnk->start]), len);
     675                 :                         }
     676                 :                         currlen += cnk->len;
     677                 :                                 
     678                 :                         break;
     679                 : 
     680                 :                 case CNK_INT:
     681                 :                 case CNK_UINT:
     682                 :                         fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags);
     683                 :                         break;
     684                 : 
     685                 :                 case CNK_OCTAL:
     686                 :                         fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags);
     687                 :                         break;
     688                 : 
     689                 :                 case CNK_HEX:
     690                 :                         fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags);
     691                 :                         break;
     692                 : 
     693                 :                 case CNK_FLOAT:
     694                 :                         fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags);
     695                 :                         break;
     696                 : 
     697                 :                 case CNK_CHAR:
     698                 :                         dopr_outch (buffer, &currlen, maxlen, cnk->value);
     699                 :                         break;
     700                 : 
     701                 :                 case CNK_STRING:
     702                 :                         if (max == -1) {
     703                 :                                 max = strlen(cnk->strvalue);
     704                 :                         }
     705                 :                         fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max);
     706                 :                         break;
     707                 : 
     708                 :                 case CNK_PTR:
     709                 :                         fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags);
     710                 :                         break;
     711                 : 
     712                 :                 case CNK_NUM:
     713                 :                         if (cnk->cflags == DP_C_CHAR)
     714                 :                                 *((char *)(cnk->pnum)) = (char)currlen;
     715                 :                         else if (cnk->cflags == DP_C_SHORT)
     716                 :                                 *((short int *)(cnk->pnum)) = (short int)currlen;
     717                 :                         else if (cnk->cflags == DP_C_LONG)
     718                 :                                 *((long int *)(cnk->pnum)) = (long int)currlen;
     719                 :                         else if (cnk->cflags == DP_C_LLONG)
     720                 :                                 *((LLONG *)(cnk->pnum)) = (LLONG)currlen;
     721                 :                         else if (cnk->cflags == DP_C_SIZET)
     722                 :                                 *((ssize_t *)(cnk->pnum)) = (ssize_t)currlen;
     723                 :                         else
     724                 :                                 *((int *)(cnk->pnum)) = (int)currlen;
     725                 :                         break;
     726                 : 
     727                 :                 case CNK_PRCNT:
     728                 :                         dopr_outch (buffer, &currlen, maxlen, '%');
     729                 :                         break;
     730                 : 
     731                 :                 default:
     732                 :                         /* what ?? */
     733                 :                         goto done;
     734                 :                 }
     735                 :                 cnk = cnk->next;
     736                 :         }
     737                 :         if (maxlen != 0) {
     738                 :                 if (currlen < maxlen - 1) 
     739                 :                         buffer[currlen] = '\0';
     740                 :                 else if (maxlen > 0) 
     741                 :                         buffer[maxlen - 1] = '\0';
     742                 :         }
     743                 :         ret = currlen;
     744                 : 
     745                 : done:
     746                 :         va_end(args);
     747                 : 
     748                 :         while (chunks) {
     749                 :                 cnk = chunks->next;
     750                 :                 free(chunks);
     751                 :                 chunks = cnk;
     752                 :         }
     753                 :         if (clist) {
     754                 :                 for (pnum = 0; pnum < max_pos; pnum++) {
     755                 :                         if (clist[pnum].chunks) free(clist[pnum].chunks);
     756                 :                 }
     757                 :                 free(clist);
     758                 :         }
     759                 :         return ret;
     760                 : }
     761                 : 
     762                 : static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
     763                 :                     char *value, int flags, int min, int max)
     764                 : {
     765                 :         int padlen, strln;     /* amount to pad */
     766                 :         int cnt = 0;
     767                 : 
     768                 : #ifdef DEBUG_SNPRINTF
     769                 :         printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
     770                 : #endif
     771                 :         if (value == 0) {
     772                 :                 value = "<NULL>";
     773                 :         }
     774                 : 
     775                 :         for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
     776                 :         padlen = min - strln;
     777                 :         if (padlen < 0) 
     778                 :                 padlen = 0;
     779                 :         if (flags & DP_F_MINUS) 
     780                 :                 padlen = -padlen; /* Left Justify */
     781                 :         
     782                 :         while (padlen > 0) {
     783                 :                 dopr_outch (buffer, currlen, maxlen, ' ');
     784                 :                 --padlen;
     785                 :         }
     786                 :         while (*value && (cnt < max)) {
     787                 :                 dopr_outch (buffer, currlen, maxlen, *value++);
     788                 :                 ++cnt;
     789                 :         }
     790                 :         while (padlen < 0) {
     791                 :                 dopr_outch (buffer, currlen, maxlen, ' ');
     792                 :                 ++padlen;
     793                 :         }
     794                 : }
     795                 : 
     796                 : /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
     797                 : 
     798                 : static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
     799                 :                     LLONG value, int base, int min, int max, int flags)
     800                 : {
     801                 :         int signvalue = 0;
     802                 :         unsigned LLONG uvalue;
     803                 :         char convert[20];
     804                 :         int place = 0;
     805                 :         int spadlen = 0; /* amount to space pad */
     806                 :         int zpadlen = 0; /* amount to zero pad */
     807                 :         int caps = 0;
     808                 :         
     809                 :         if (max < 0)
     810                 :                 max = 0;
     811                 :         
     812                 :         uvalue = value;
     813                 :         
     814                 :         if(!(flags & DP_F_UNSIGNED)) {
     815                 :                 if( value < 0 ) {
     816                 :                         signvalue = '-';
     817                 :                         uvalue = -value;
     818                 :                 } else {
     819                 :                         if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
     820                 :                                 signvalue = '+';
     821                 :                         else if (flags & DP_F_SPACE)
     822                 :                                 signvalue = ' ';
     823                 :                 }
     824                 :         }
     825                 :   
     826                 :         if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
     827                 : 
     828                 :         do {
     829                 :                 convert[place++] =
     830                 :                         (caps? "0123456789ABCDEF":"0123456789abcdef")
     831                 :                         [uvalue % (unsigned)base  ];
     832                 :                 uvalue = (uvalue / (unsigned)base );
     833                 :         } while(uvalue && (place < 20));
     834                 :         if (place == 20) place--;
     835                 :         convert[place] = 0;
     836                 : 
     837                 :         zpadlen = max - place;
     838                 :         spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
     839                 :         if (zpadlen < 0) zpadlen = 0;
     840                 :         if (spadlen < 0) spadlen = 0;
     841                 :         if (flags & DP_F_ZERO) {
     842                 :                 zpadlen = MAX(zpadlen, spadlen);
     843                 :                 spadlen = 0;
     844                 :         }
     845                 :         if (flags & DP_F_MINUS) 
     846                 :                 spadlen = -spadlen; /* Left Justifty */
     847                 : 
     848                 : #ifdef DEBUG_SNPRINTF
     849                 :         printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
     850                 :                zpadlen, spadlen, min, max, place);
     851                 : #endif
     852                 : 
     853                 :         /* Spaces */
     854                 :         while (spadlen > 0) {
     855                 :                 dopr_outch (buffer, currlen, maxlen, ' ');
     856                 :                 --spadlen;
     857                 :         }
     858                 : 
     859                 :         /* Sign */
     860                 :         if (signvalue) 
     861                 :                 dopr_outch (buffer, currlen, maxlen, signvalue);
     862                 : 
     863                 :         /* Zeros */
     864                 :         if (zpadlen > 0) {
     865                 :                 while (zpadlen > 0) {
     866                 :                         dopr_outch (buffer, currlen, maxlen, '0');
     867                 :                         --zpadlen;
     868                 :                 }
     869                 :         }
     870                 : 
     871                 :         /* Digits */
     872                 :         while (place > 0) 
     873                 :                 dopr_outch (buffer, currlen, maxlen, convert[--place]);
     874                 :   
     875                 :         /* Left Justified spaces */
     876                 :         while (spadlen < 0) {
     877                 :                 dopr_outch (buffer, currlen, maxlen, ' ');
     878                 :                 ++spadlen;
     879                 :         }
     880                 : }
     881                 : 
     882                 : static LDOUBLE abs_val(LDOUBLE value)
     883                 : {
     884                 :         LDOUBLE result = value;
     885                 : 
     886                 :         if (value < 0)
     887                 :                 result = -value;
     888                 :         
     889                 :         return result;
     890                 : }
     891                 : 
     892                 : static LDOUBLE POW10(int exp)
     893                 : {
     894                 :         LDOUBLE result = 1;
     895                 :         
     896                 :         while (exp) {
     897                 :                 result *= 10;
     898                 :                 exp--;
     899                 :         }
     900                 :   
     901                 :         return result;
     902                 : }
     903                 : 
     904                 : static LLONG ROUND(LDOUBLE value)
     905                 : {
     906                 :         LLONG intpart;
     907                 : 
     908                 :         intpart = (LLONG)value;
     909                 :         value = value - intpart;
     910                 :         if (value >= 0.5) intpart++;
     911                 :         
     912                 :         return intpart;
     913                 : }
     914                 : 
     915                 : /* a replacement for modf that doesn't need the math library. Should
     916                 :    be portable, but slow */
     917                 : static double my_modf(double x0, double *iptr)
     918                 : {
     919                 :         int i;
     920                 :         LLONG l=0;
     921                 :         double x = x0;
     922                 :         double f = 1.0;
     923                 : 
     924                 :         for (i=0;i<100;i++) {
     925                 :                 l = (long)x;
     926                 :                 if (l <= (x+1) && l >= (x-1)) break;
     927                 :                 x *= 0.1;
     928                 :                 f *= 10.0;
     929                 :         }
     930                 : 
     931                 :         if (i == 100) {
     932                 :                 /* yikes! the number is beyond what we can handle. What do we do? */
     933                 :                 (*iptr) = 0;
     934                 :                 return 0;
     935                 :         }
     936                 : 
     937                 :         if (i != 0) {
     938                 :                 double i2;
     939                 :                 double ret;
     940                 : 
     941                 :                 ret = my_modf(x0-l*f, &i2);
     942                 :                 (*iptr) = l*f + i2;
     943                 :                 return ret;
     944                 :         } 
     945                 : 
     946                 :         (*iptr) = l;
     947                 :         return x - (*iptr);
     948                 : }
     949                 : 
     950                 : 
     951                 : static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
     952                 :                    LDOUBLE fvalue, int min, int max, int flags)
     953                 : {
     954                 :         int signvalue = 0;
     955                 :         double ufvalue;
     956                 :         char iconvert[311];
     957                 :         char fconvert[311];
     958                 :         int iplace = 0;
     959                 :         int fplace = 0;
     960                 :         int padlen = 0; /* amount to pad */
     961                 :         int zpadlen = 0; 
     962                 :         int caps = 0;
     963                 :         int idx;
     964                 :         double intpart;
     965                 :         double fracpart;
     966                 :         double temp;
     967                 :   
     968                 :         /* 
     969                 :          * AIX manpage says the default is 0, but Solaris says the default
     970                 :          * is 6, and sprintf on AIX defaults to 6
     971                 :          */
     972                 :         if (max < 0)
     973                 :                 max = 6;
     974                 : 
     975                 :         ufvalue = abs_val (fvalue);
     976                 : 
     977                 :         if (fvalue < 0) {
     978                 :                 signvalue = '-';
     979                 :         } else {
     980                 :                 if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
     981                 :                         signvalue = '+';
     982                 :                 } else {
     983                 :                         if (flags & DP_F_SPACE)
     984                 :                                 signvalue = ' ';
     985                 :                 }
     986                 :         }
     987                 : 
     988                 : #if 0
     989                 :         if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
     990                 : #endif
     991                 : 
     992                 : #if 0
     993                 :          if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
     994                 : #endif
     995                 : 
     996                 :         /* 
     997                 :          * Sorry, we only support 9 digits past the decimal because of our 
     998                 :          * conversion method
     999                 :          */
    1000                 :         if (max > 9)
    1001                 :                 max = 9;
    1002                 : 
    1003                 :         /* We "cheat" by converting the fractional part to integer by
    1004                 :          * multiplying by a factor of 10
    1005                 :          */
    1006                 : 
    1007                 :         temp = ufvalue;
    1008                 :         my_modf(temp, &intpart);
    1009                 : 
    1010                 :         fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
    1011                 :         
    1012                 :         if (fracpart >= POW10(max)) {
    1013                 :                 intpart++;
    1014                 :                 fracpart -= POW10(max);
    1015                 :         }
    1016                 : 
    1017                 : 
    1018                 :         /* Convert integer part */
    1019                 :         do {
    1020                 :                 temp = intpart*0.1;
    1021                 :                 my_modf(temp, &intpart);
    1022                 :                 idx = (int) ((temp -intpart +0.05)* 10.0);
    1023                 :                 /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
    1024                 :                 /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
    1025                 :                 iconvert[iplace++] =
    1026                 :                         (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
    1027                 :         } while (intpart && (iplace < 311));
    1028                 :         if (iplace == 311) iplace--;
    1029                 :         iconvert[iplace] = 0;
    1030                 : 
    1031                 :         /* Convert fractional part */
    1032                 :         if (fracpart)
    1033                 :         {
    1034                 :                 do {
    1035                 :                         temp = fracpart*0.1;
    1036                 :                         my_modf(temp, &fracpart);
    1037                 :                         idx = (int) ((temp -fracpart +0.05)* 10.0);
    1038                 :                         /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
    1039                 :                         /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
    1040                 :                         fconvert[fplace++] =
    1041                 :                         (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
    1042                 :                 } while(fracpart && (fplace < 311));
    1043                 :                 if (fplace == 311) fplace--;
    1044                 :         }
    1045                 :         fconvert[fplace] = 0;
    1046                 :   
    1047                 :         /* -1 for decimal point, another -1 if we are printing a sign */
    1048                 :         padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
    1049                 :         zpadlen = max - fplace;
    1050                 :         if (zpadlen < 0) zpadlen = 0;
    1051                 :         if (padlen < 0) 
    1052                 :                 padlen = 0;
    1053                 :         if (flags & DP_F_MINUS) 
    1054                 :                 padlen = -padlen; /* Left Justifty */
    1055                 :         
    1056                 :         if ((flags & DP_F_ZERO) && (padlen > 0)) {
    1057                 :                 if (signvalue) {
    1058                 :                         dopr_outch (buffer, currlen, maxlen, signvalue);
    1059                 :                         --padlen;
    1060                 :                         signvalue = 0;
    1061                 :                 }
    1062                 :                 while (padlen > 0) {
    1063                 :                         dopr_outch (buffer, currlen, maxlen, '0');
    1064                 :                         --padlen;
    1065                 :                 }
    1066                 :         }
    1067                 :         while (padlen > 0) {
    1068                 :                 dopr_outch (buffer, currlen, maxlen, ' ');
    1069                 :                 --padlen;
    1070                 :         }
    1071                 :         if (signvalue) 
    1072                 :                 dopr_outch (buffer, currlen, maxlen, signvalue);
    1073                 :         
    1074                 :         while (iplace > 0) 
    1075                 :                 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
    1076                 : 
    1077                 : #ifdef DEBUG_SNPRINTF
    1078                 :         printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
    1079                 : #endif
    1080                 : 
    1081                 :         /*
    1082                 :          * Decimal point.  This should probably use locale to find the correct
    1083                 :          * char to print out.
    1084                 :          */
    1085                 :         if (max > 0) {
    1086                 :                 dopr_outch (buffer, currlen, maxlen, '.');
    1087                 :                 
    1088                 :                 while (zpadlen > 0) {
    1089                 :                         dopr_outch (buffer, currlen, maxlen, '0');
    1090                 :                         --zpadlen;
    1091                 :                 }
    1092                 : 
    1093                 :                 while (fplace > 0) 
    1094                 :                         dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
    1095                 :         }
    1096                 : 
    1097                 :         while (padlen < 0) {
    1098                 :                 dopr_outch (buffer, currlen, maxlen, ' ');
    1099                 :                 ++padlen;
    1100                 :         }
    1101                 : }
    1102                 : 
    1103                 : static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
    1104                 : {
    1105                 :         if (*currlen < maxlen) {
    1106                 :                 buffer[(*currlen)] = c;
    1107                 :         }
    1108                 :         (*currlen)++;
    1109                 : }
    1110                 : 
    1111                 : static struct pr_chunk *new_chunk(void) {
    1112                 :         struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk));
    1113                 : 
    1114                 :         if (!new_c)
    1115                 :                 return NULL;
    1116                 : 
    1117                 :         new_c->type = 0;
    1118                 :         new_c->num = 0;
    1119                 :         new_c->min = 0;
    1120                 :         new_c->min_star = NULL;
    1121                 :         new_c->max = -1;
    1122                 :         new_c->max_star = NULL;
    1123                 :         new_c->flags = 0;
    1124                 :         new_c->cflags = 0;
    1125                 :         new_c->start = 0;
    1126                 :         new_c->len = 0;
    1127                 :         new_c->value = 0;
    1128                 :         new_c->fvalue = 0;
    1129                 :         new_c->strvalue = NULL;
    1130                 :         new_c->pnum = NULL;
    1131                 :         new_c->next = NULL;
    1132                 : 
    1133                 :         return new_c;
    1134                 : }
    1135                 : 
    1136                 : static int add_cnk_list_entry(struct pr_chunk_x **list,
    1137                 :                                 int max_num, struct pr_chunk *chunk) {
    1138                 :         struct pr_chunk_x *l;
    1139                 :         struct pr_chunk **c;
    1140                 :         int max;
    1141                 :         int cnum;
    1142                 :         int i, pos;
    1143                 : 
    1144                 :         if (chunk->num > max_num) {
    1145                 :                 max = chunk->num;
    1146                 :         
    1147                 :                 if (*list == NULL) {
    1148                 :                         l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max);
    1149                 :                         pos = 0;
    1150                 :                 } else {
    1151                 :                         l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max);
    1152                 :                         pos = max_num;
    1153                 :                 }
    1154                 :                 if (l == NULL) {
    1155                 :                         for (i = 0; i < max; i++) {
    1156                 :                                 if ((*list)[i].chunks) free((*list)[i].chunks);
    1157                 :                         }
    1158                 :                         return 0;
    1159                 :                 }
    1160                 :                 for (i = pos; i < max; i++) {
    1161                 :                         l[i].chunks = NULL;
    1162                 :                         l[i].num = 0;
    1163                 :                 }
    1164                 :         } else {
    1165                 :                 l = *list;
    1166                 :                 max = max_num;
    1167                 :         }
    1168                 : 
    1169                 :         i = chunk->num - 1;
    1170                 :         cnum = l[i].num + 1;
    1171                 :         if (l[i].chunks == NULL) {
    1172                 :                 c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum); 
    1173                 :         } else {
    1174                 :                 c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum);
    1175                 :         }
    1176                 :         if (c == NULL) {
    1177                 :                 for (i = 0; i < max; i++) {
    1178                 :                         if (l[i].chunks) free(l[i].chunks);
    1179                 :                 }
    1180                 :                 return 0;
    1181                 :         }
    1182                 :         c[l[i].num] = chunk;
    1183                 :         l[i].chunks = c;
    1184                 :         l[i].num = cnum;
    1185                 : 
    1186                 :         *list = l;
    1187                 :         return max;
    1188                 : }
    1189                 : 
    1190                 :  int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
    1191                 : {
    1192                 :         return dopr(str, count, fmt, args);
    1193                 : }
    1194                 : #endif
    1195                 : 
    1196                 : /* yes this really must be a ||. Don't muck with this (tridge)
    1197                 :  *
    1198                 :  * The logic for these two is that we need our own definition if the
    1199                 :  * OS *either* has no definition of *sprintf, or if it does have one
    1200                 :  * that doesn't work properly according to the autoconf test.
    1201                 :  */
    1202                 : #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
    1203                 :  int snprintf(char *str,size_t count,const char *fmt,...)
    1204                 : {
    1205                 :         size_t ret;
    1206                 :         va_list ap;
    1207                 :     
    1208                 :         va_start(ap, fmt);
    1209                 :         ret = vsnprintf(str, count, fmt, ap);
    1210                 :         va_end(ap);
    1211                 :         return ret;
    1212                 : }
    1213                 : #endif
    1214                 : 
    1215                 : #ifndef HAVE_C99_VSNPRINTF
    1216                 :  int printf(const char *fmt, ...)
    1217                 : {
    1218                 :         va_list ap;
    1219                 :         int ret;
    1220                 :         char *s;
    1221                 : 
    1222                 :         s = NULL;
    1223                 :         va_start(ap, fmt);
    1224                 :         ret = vasprintf(&s, fmt, ap);
    1225                 :         va_end(ap);
    1226                 : 
    1227                 :         if (s) {
    1228                 :                 fwrite(s, 1, strlen(s), stdout);
    1229                 :         }
    1230                 :         free(s);
    1231                 : 
    1232                 :         return ret;
    1233                 : }
    1234                 : #endif
    1235                 : 
    1236                 : #ifndef HAVE_C99_VSNPRINTF
    1237                 :  int fprintf(FILE *stream, const char *fmt, ...)
    1238                 : {
    1239                 :         va_list ap;
    1240                 :         int ret;
    1241                 :         char *s;
    1242                 : 
    1243                 :         s = NULL;
    1244                 :         va_start(ap, fmt);
    1245                 :         ret = vasprintf(&s, fmt, ap);
    1246                 :         va_end(ap);
    1247                 : 
    1248                 :         if (s) {
    1249                 :                 fwrite(s, 1, strlen(s), stream);
    1250                 :         }
    1251                 :         free(s);
    1252                 : 
    1253                 :         return ret;
    1254                 : }
    1255                 : #endif
    1256                 : 
    1257                 : #endif 
    1258                 : 
    1259                 : #ifndef HAVE_VASPRINTF
    1260                 :  int vasprintf(char **ptr, const char *format, va_list ap)
    1261                 : {
    1262                 :         int ret;
    1263                 :         va_list ap2;
    1264                 : 
    1265                 :         VA_COPY(ap2, ap);
    1266                 :         ret = vsnprintf(NULL, 0, format, ap2);
    1267                 :         va_end(ap2);
    1268                 :         if (ret < 0) return ret;
    1269                 : 
    1270                 :         (*ptr) = (char *)malloc(ret+1);
    1271                 :         if (!*ptr) return -1;
    1272                 : 
    1273                 :         VA_COPY(ap2, ap);
    1274                 :         ret = vsnprintf(*ptr, ret+1, format, ap2);
    1275                 :         va_end(ap2);
    1276                 : 
    1277                 :         return ret;
    1278                 : }
    1279                 : #endif
    1280                 : 
    1281                 : 
    1282                 : #ifndef HAVE_ASPRINTF
    1283                 :  int asprintf(char **ptr, const char *format, ...)
    1284                 : {
    1285                 :         va_list ap;
    1286                 :         int ret;
    1287                 :         
    1288                 :         *ptr = NULL;
    1289                 :         va_start(ap, format);
    1290                 :         ret = vasprintf(ptr, format, ap);
    1291                 :         va_end(ap);
    1292                 : 
    1293                 :         return ret;
    1294                 : }
    1295                 : #endif
    1296                 : 
    1297                 : #ifdef TEST_SNPRINTF
    1298                 : 
    1299                 :  int sprintf(char *str,const char *fmt,...);
    1300                 :  int printf(const char *fmt,...);
    1301                 : 
    1302                 :  int main (void)
    1303                 : {
    1304                 :         char buf1[1024];
    1305                 :         char buf2[1024];
    1306                 :         char *buf3;
    1307                 :         char *fp_fmt[] = {
    1308                 :                 "%1.1f",
    1309                 :                 "%-1.5f",
    1310                 :                 "%1.5f",
    1311                 :                 "%123.9f",
    1312                 :                 "%10.5f",
    1313                 :                 "% 10.5f",
    1314                 :                 "%+22.9f",
    1315                 :                 "%+4.9f",
    1316                 :                 "%01.3f",
    1317                 :                 "%4f",
    1318                 :                 "%3.1f",
    1319                 :                 "%3.2f",
    1320                 :                 "%.0f",
    1321                 :                 "%f",
    1322                 :                 "%-8.8f",
    1323                 :                 "%-9.9f",
    1324                 :                 NULL
    1325                 :         };
    1326                 :         double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, 
    1327                 :                              0.9996, 1.996, 4.136, 5.030201, 0.00205,
    1328                 :                              /* END LIST */ 0};
    1329                 :         char *int_fmt[] = {
    1330                 :                 "%-1.5d",
    1331                 :                 "%1.5d",
    1332                 :                 "%123.9d",
    1333                 :                 "%5.5d",
    1334                 :                 "%10.5d",
    1335                 :                 "% 10.5d",
    1336                 :                 "%+22.33d",
    1337                 :                 "%01.3d",
    1338                 :                 "%4d",
    1339                 :                 "%d",
    1340                 :                 NULL
    1341                 :         };
    1342                 :         long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0};
    1343                 :         char *str_fmt[] = {
    1344                 :                 "%10.5s",
    1345                 :                 "%-10.5s",
    1346                 :                 "%5.10s",
    1347                 :                 "%-5.10s",
    1348                 :                 "%10.1s",
    1349                 :                 "%0.10s",
    1350                 :                 "%10.0s",
    1351                 :                 "%1.10s",
    1352                 :                 "%s",
    1353                 :                 "%.1s",
    1354                 :                 "%.10s",
    1355                 :                 "%10s",
    1356                 :                 NULL
    1357                 :         };
    1358                 :         char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
    1359                 : #ifdef HAVE_LONG_LONG
    1360                 :         char *ll_fmt[] = {
    1361                 :                 "%llu",
    1362                 :                 NULL
    1363                 :         };
    1364                 :         LLONG ll_nums[] = { 134, 91340, 341, 0203, 1234567890, 128006186140000000LL, 0};
    1365                 : #endif
    1366                 :         int x, y;
    1367                 :         int fail = 0;
    1368                 :         int num = 0;
    1369                 :         int l1, l2;
    1370                 :         char *ss_fmt[] = {
    1371                 :                 "%zd",
    1372                 :                 "%zu",
    1373                 :                 NULL
    1374                 :         };
    1375                 :         size_t ss_nums[] = {134, 91340, 123456789, 0203, 1234567890, 0};
    1376                 : 
    1377                 :         printf ("Testing snprintf format codes against system sprintf...\n");
    1378                 : 
    1379                 :         for (x = 0; fp_fmt[x] ; x++) {
    1380                 :                 for (y = 0; fp_nums[y] != 0 ; y++) {
    1381                 :                         buf1[0] = buf2[0] = '\0';
    1382                 :                         l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
    1383                 :                         l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]);
    1384                 :                         buf1[1023] = buf2[1023] = '\0';
    1385                 :                         if (strcmp (buf1, buf2) || (l1 != l2)) {
    1386                 :                                 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
    1387                 :                                        fp_fmt[x], l1, buf1, l2, buf2);
    1388                 :                                 fail++;
    1389                 :                         }
    1390                 :                         num++;
    1391                 :                 }
    1392                 :         }
    1393                 : 
    1394                 :         for (x = 0; int_fmt[x] ; x++) {
    1395                 :                 for (y = 0; int_nums[y] != 0 ; y++) {
    1396                 :                         buf1[0] = buf2[0] = '\0';
    1397                 :                         l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
    1398                 :                         l2 = sprintf (buf2, int_fmt[x], int_nums[y]);
    1399                 :                         buf1[1023] = buf2[1023] = '\0';
    1400                 :                         if (strcmp (buf1, buf2) || (l1 != l2)) {
    1401                 :                                 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
    1402                 :                                        int_fmt[x], l1, buf1, l2, buf2);
    1403                 :                                 fail++;
    1404                 :                         }
    1405                 :                         num++;
    1406                 :                 }
    1407                 :         }
    1408                 : 
    1409                 :         for (x = 0; str_fmt[x] ; x++) {
    1410                 :                 for (y = 0; str_vals[y] != 0 ; y++) {
    1411                 :                         buf1[0] = buf2[0] = '\0';
    1412                 :                         l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
    1413                 :                         l2 = sprintf (buf2, str_fmt[x], str_vals[y]);
    1414                 :                         buf1[1023] = buf2[1023] = '\0';
    1415                 :                         if (strcmp (buf1, buf2) || (l1 != l2)) {
    1416                 :                                 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
    1417                 :                                        str_fmt[x], l1, buf1, l2, buf2);
    1418                 :                                 fail++;
    1419                 :                         }
    1420                 :                         num++;
    1421                 :                 }
    1422                 :         }
    1423                 : 
    1424                 : #ifdef HAVE_LONG_LONG
    1425                 :         for (x = 0; ll_fmt[x] ; x++) {
    1426                 :                 for (y = 0; ll_nums[y] != 0 ; y++) {
    1427                 :                         buf1[0] = buf2[0] = '\0';
    1428                 :                         l1 = snprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
    1429                 :                         l2 = sprintf (buf2, ll_fmt[x], ll_nums[y]);
    1430                 :                         buf1[1023] = buf2[1023] = '\0';
    1431                 :                         if (strcmp (buf1, buf2) || (l1 != l2)) {
    1432                 :                                 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
    1433                 :                                        ll_fmt[x], l1, buf1, l2, buf2);
    1434                 :                                 fail++;
    1435                 :                         }
    1436                 :                         num++;
    1437                 :                 }
    1438                 :         }
    1439                 : #endif
    1440                 : 
    1441                 : #define BUFSZ 2048
    1442                 : 
    1443                 :         buf1[0] = buf2[0] = '\0';
    1444                 :         if ((buf3 = malloc(BUFSZ)) == NULL) {
    1445                 :                 fail++;
    1446                 :         } else {
    1447                 :                 num++;
    1448                 :                 memset(buf3, 'a', BUFSZ);
    1449                 :                 snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3);
    1450                 :                 buf1[1023] = '\0';
    1451                 :                 if (strcmp(buf1, "a") != 0) {
    1452                 :                         printf("length limit buf1 '%s' expected 'a'\n", buf1);
    1453                 :                         fail++;
    1454                 :                 }
    1455                 :         }
    1456                 : 
    1457                 :         buf1[0] = buf2[0] = '\0';
    1458                 :         l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
    1459                 :         l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
    1460                 :         buf1[1023] = buf2[1023] = '\0';
    1461                 :         if (strcmp(buf1, buf2) || (l1 != l2)) {
    1462                 :                 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
    1463                 :                                 "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
    1464                 :                 fail++;
    1465                 :         }
    1466                 : 
    1467                 :         buf1[0] = buf2[0] = '\0';
    1468                 :         l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
    1469                 :         l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
    1470                 :         buf1[1023] = buf2[1023] = '\0';
    1471                 :         if (strcmp(buf1, buf2)) {
    1472                 :                 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
    1473                 :                                 "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
    1474                 :                 fail++;
    1475                 :         }
    1476                 : 
    1477                 :         for (x = 0; ss_fmt[x] ; x++) {
    1478                 :                 for (y = 0; ss_nums[y] != 0 ; y++) {
    1479                 :                         buf1[0] = buf2[0] = '\0';
    1480                 :                         l1 = snprintf(buf1, sizeof(buf1), ss_fmt[x], ss_nums[y]);
    1481                 :                         l2 = sprintf (buf2, ss_fmt[x], ss_nums[y]);
    1482                 :                         buf1[1023] = buf2[1023] = '\0';
    1483                 :                         if (strcmp (buf1, buf2) || (l1 != l2)) {
    1484                 :                                 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
    1485                 :                                        ss_fmt[x], l1, buf1, l2, buf2);
    1486                 :                                 fail++;
    1487                 :                         }
    1488                 :                         num++;
    1489                 :                 }
    1490                 :         }
    1491                 : #if 0
    1492                 :         buf1[0] = buf2[0] = '\0';
    1493                 :         l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890);
    1494                 :         l2 = sprintf(buf2, "%lld", (LLONG)1234567890);
    1495                 :         buf1[1023] = buf2[1023] = '\0';
    1496                 :         if (strcmp(buf1, buf2)) {
    1497                 :                 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
    1498                 :                                 "%lld", l1, buf1, l2, buf2);
    1499                 :                 fail++;
    1500                 :         }
    1501                 : 
    1502                 :         buf1[0] = buf2[0] = '\0';
    1503                 :         l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123);
    1504                 :         l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123);
    1505                 :         buf1[1023] = buf2[1023] = '\0';
    1506                 :         if (strcmp(buf1, buf2)) {
    1507                 :                 printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
    1508                 :                                 "%Lf", l1, buf1, l2, buf2);
    1509                 :                 fail++;
    1510                 :         }
    1511                 : #endif
    1512                 :         printf ("%d tests failed out of %d.\n", fail, num);
    1513                 : 
    1514                 :         printf("seeing how many digits we support\n");
    1515                 :         {
    1516                 :                 double v0 = 0.12345678901234567890123456789012345678901;
    1517                 :                 for (x=0; x<100; x++) {
    1518                 :                         double p = pow(10, x); 
    1519                 :                         double r = v0*p;
    1520                 :                         snprintf(buf1, sizeof(buf1), "%1.1f", r);
    1521                 :                         sprintf(buf2,                "%1.1f", r);
    1522                 :                         if (strcmp(buf1, buf2)) {
    1523                 :                                 printf("we seem to support %d digits\n", x-1);
    1524                 :                                 break;
    1525                 :                         }
    1526                 :                 }
    1527                 :         }
    1528                 : 
    1529                 :         return 0;
    1530                 : }
    1531                 : #endif /* TEST_SNPRINTF */

Generated by: LTP GCOV extension version 1.6