Back to index

nagios-nrpe  2.13
snprintf.c
Go to the documentation of this file.
00001 /*
00002  * NOTE: If you change this file, please merge it into rsync, samba, etc.
00003  */
00004 
00005 /*
00006  * Copyright Patrick Powell 1995
00007  * This code is based on code written by Patrick Powell (papowell@astart.com)
00008  * It may be used for any purpose as long as this notice remains intact
00009  * on all source code distributions
00010  */
00011 
00012 /**************************************************************
00013  * Original:
00014  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
00015  * A bombproof version of doprnt (dopr) included.
00016  * Sigh.  This sort of thing is always nasty do deal with.  Note that
00017  * the version here does not include floating point...
00018  *
00019  * snprintf() is used instead of sprintf() as it does limit checks
00020  * for string length.  This covers a nasty loophole.
00021  *
00022  * The other functions are there to prevent NULL pointers from
00023  * causing nast effects.
00024  *
00025  * More Recently:
00026  *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
00027  *  This was ugly.  It is still ugly.  I opted out of floating point
00028  *  numbers, but the formatter understands just about everything
00029  *  from the normal C string format, at least as far as I can tell from
00030  *  the Solaris 2.5 printf(3S) man page.
00031  *
00032  *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
00033  *    Ok, added some minimal floating point support, which means this
00034  *    probably requires libm on most operating systems.  Don't yet
00035  *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
00036  *    was pretty badly broken, it just wasn't being exercised in ways
00037  *    which showed it, so that's been fixed.  Also, formated the code
00038  *    to mutt conventions, and removed dead code left over from the
00039  *    original.  Also, there is now a builtin-test, just compile with:
00040  *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
00041  *    and run snprintf for results.
00042  * 
00043  *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
00044  *    The PGP code was using unsigned hexadecimal formats. 
00045  *    Unfortunately, unsigned formats simply didn't work.
00046  *
00047  *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
00048  *    The original code assumed that both snprintf() and vsnprintf() were
00049  *    missing.  Some systems only have snprintf() but not vsnprintf(), so
00050  *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
00051  *
00052  *  Andrew Tridgell (tridge@samba.org) Oct 1998
00053  *    fixed handling of %.0f
00054  *    added test for HAVE_LONG_DOUBLE
00055  *
00056  * tridge@samba.org, idra@samba.org, April 2001
00057  *    got rid of fcvt code (twas buggy and made testing harder)
00058  *    added C99 semantics
00059  *
00060  * date: 2002/12/19 19:56:31;  author: herb;  state: Exp;  lines: +2 -0
00061  * actually print args for %g and %e
00062  * 
00063  * date: 2002/06/03 13:37:52;  author: jmcd;  state: Exp;  lines: +8 -0
00064  * Since includes.h isn't included here, VA_COPY has to be defined here.  I don't
00065  * see any include file that is guaranteed to be here, so I'm defining it
00066  * locally.  Fixes AIX and Solaris builds.
00067  * 
00068  * date: 2002/06/03 03:07:24;  author: tridge;  state: Exp;  lines: +5 -13
00069  * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
00070  * functions
00071  * 
00072  * date: 2002/05/17 14:51:22;  author: jmcd;  state: Exp;  lines: +21 -4
00073  * Fix usage of va_list passed as an arg.  Use __va_copy before using it
00074  * when it exists.
00075  * 
00076  * date: 2002/04/16 22:38:04;  author: idra;  state: Exp;  lines: +20 -14
00077  * Fix incorrect zpadlen handling in fmtfp.
00078  * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
00079  * few mods to make it easier to compile the tests.
00080  * addedd the "Ollie" test to the floating point ones.
00081  *
00082  * Martin Pool (mbp@samba.org) April 2003
00083  *    Remove NO_CONFIG_H so that the test case can be built within a source
00084  *    tree with less trouble.
00085  *    Remove unnecessary SAFE_FREE() definition.
00086  *
00087  * Martin Pool (mbp@samba.org) May 2003
00088  *    Put in a prototype for dummy_snprintf() to quiet compiler warnings.
00089  *
00090  *    Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
00091  *    if the C library has some snprintf functions already.
00092  *
00093  * Darren Tucker (dtucker@zip.com.au) 2005
00094  *    Fix bug allowing read overruns of the source string with "%.*s"
00095  *    Usually harmless unless the read runs outside the process' allocation
00096  *    (eg if your malloc does guard pages) in which case it will segfault.
00097  *    From OpenSSH.  Also added test for same.
00098  *
00099  * Simo Sorce (idra@samba.org) Jan 2006
00100  * 
00101  *    Add support for position independent parameters 
00102  *    fix fmtstr now it conforms to sprintf wrt min.max
00103  *
00104  **************************************************************/
00105 
00106 #ifndef NO_CONFIG_H
00107 /* 08/13/2007 EG changed path to config.h to match NRPE distro */
00108 #include "../include/config.h"
00109 #else
00110 #define NULL 0
00111 #endif 
00112 
00113 #ifdef TEST_SNPRINTF /* need math library headers for testing */
00114 
00115 /* In test mode, we pretend that this system doesn't have any snprintf
00116  * functions, regardless of what config.h says. */
00117 #  undef HAVE_SNPRINTF
00118 #  undef HAVE_VSNPRINTF
00119 #  undef HAVE_C99_VSNPRINTF
00120 #  undef HAVE_ASPRINTF
00121 #  undef HAVE_VASPRINTF
00122 #  include <math.h>
00123 #endif /* TEST_SNPRINTF */
00124 
00125 #ifdef HAVE_STRING_H
00126 #include <string.h>
00127 #endif
00128 
00129 #ifdef HAVE_STRINGS_H
00130 #include <strings.h>
00131 #endif
00132 #ifdef HAVE_CTYPE_H
00133 #include <ctype.h>
00134 #endif
00135 #include <sys/types.h>
00136 #include <stdarg.h>
00137 #ifdef HAVE_STDLIB_H
00138 #include <stdlib.h>
00139 #endif
00140 
00141 #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
00142 /* only include stdio.h if we are not re-defining snprintf or vsnprintf */
00143 #include <stdio.h>
00144  /* make the compiler happy with an empty file */
00145  void dummy_snprintf(void);
00146  void dummy_snprintf(void) {} 
00147 #endif /* HAVE_SNPRINTF, etc */
00148 
00149 #ifdef HAVE_LONG_DOUBLE
00150 #define LDOUBLE long double
00151 #else
00152 #define LDOUBLE double
00153 #endif
00154 
00155 #ifdef HAVE_LONG_LONG
00156 #define LLONG long long
00157 #else
00158 #define LLONG long
00159 #endif
00160 
00161 #ifndef VA_COPY
00162 #ifdef HAVE_VA_COPY
00163 #define VA_COPY(dest, src) va_copy(dest, src)
00164 #else
00165 #ifdef HAVE___VA_COPY
00166 #define VA_COPY(dest, src) __va_copy(dest, src)
00167 #else
00168 #define VA_COPY(dest, src) (dest) = (src)
00169 #endif
00170 #endif
00171 
00172 /*
00173  * dopr(): poor man's version of doprintf
00174  */
00175 
00176 /* format read states */
00177 #define DP_S_DEFAULT 0
00178 #define DP_S_FLAGS   1
00179 #define DP_S_MIN     2
00180 #define DP_S_DOT     3
00181 #define DP_S_MAX     4
00182 #define DP_S_MOD     5
00183 #define DP_S_CONV    6
00184 #define DP_S_DONE    7
00185 
00186 /* format flags - Bits */
00187 #define DP_F_MINUS   (1 << 0)
00188 #define DP_F_PLUS    (1 << 1)
00189 #define DP_F_SPACE   (1 << 2)
00190 #define DP_F_NUM     (1 << 3)
00191 #define DP_F_ZERO    (1 << 4)
00192 #define DP_F_UP      (1 << 5)
00193 #define DP_F_UNSIGNED       (1 << 6)
00194 
00195 /* Conversion Flags */
00196 #define DP_C_CHAR    1
00197 #define DP_C_SHORT   2
00198 #define DP_C_LONG    3
00199 #define DP_C_LDOUBLE 4
00200 #define DP_C_LLONG   5
00201 
00202 /* Chunk types */
00203 #define CNK_FMT_STR 0
00204 #define CNK_INT     1
00205 #define CNK_OCTAL   2
00206 #define CNK_UINT    3
00207 #define CNK_HEX     4
00208 #define CNK_FLOAT   5
00209 #define CNK_CHAR    6
00210 #define CNK_STRING  7
00211 #define CNK_PTR     8
00212 #define CNK_NUM     9
00213 #define CNK_PRCNT   10
00214 
00215 #define char_to_int(p) ((p)- '0')
00216 #ifndef MAX
00217 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
00218 #endif
00219 
00220 /* yes this really must be a ||. Don't muck with this (tridge) */
00221 #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
00222 
00223 struct pr_chunk {
00224        int type; /* chunk type */
00225        int num; /* parameter number */
00226        int min; 
00227        int max;
00228        int flags;
00229        int cflags;
00230        int start;
00231        int len;
00232        LLONG value;
00233        LDOUBLE fvalue;
00234        char *strvalue;
00235        void *pnum;
00236        struct pr_chunk *min_star;
00237        struct pr_chunk *max_star;
00238        struct pr_chunk *next;
00239 };
00240 
00241 struct pr_chunk_x {
00242        struct pr_chunk **chunks;
00243        int num;
00244 };
00245 
00246 static size_t dopr(char *buffer, size_t maxlen, const char *format, 
00247                  va_list args_in);
00248 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
00249                   char *value, int flags, int min, int max);
00250 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
00251                   long value, int base, int min, int max, int flags);
00252 static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
00253                  LDOUBLE fvalue, int min, int max, int flags);
00254 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
00255 static struct pr_chunk *new_chunk(void);
00256 static int add_cnk_list_entry(struct pr_chunk_x **list,
00257                             int max_num, struct pr_chunk *chunk);
00258 
00259 static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
00260 {
00261        char ch;
00262        int state;
00263        int pflag;
00264        int pnum;
00265        int pfirst;
00266        size_t currlen;
00267        va_list args;
00268        const char *base;
00269        struct pr_chunk *chunks = NULL;
00270        struct pr_chunk *cnk = NULL;
00271        struct pr_chunk_x *clist = NULL;
00272        int max_pos;
00273        size_t ret = -1;
00274 
00275        VA_COPY(args, args_in);
00276 
00277        state = DP_S_DEFAULT;
00278        pfirst = 1;
00279        pflag = 0;
00280        pnum = 0;
00281 
00282        max_pos = 0;
00283        base = format;
00284        ch = *format++;
00285        
00286        /* retrieve the string structure as chunks */
00287        while (state != DP_S_DONE) {
00288               if (ch == '\0') 
00289                      state = DP_S_DONE;
00290 
00291               switch(state) {
00292               case DP_S_DEFAULT:
00293                      
00294                      if (cnk) {
00295                             cnk->next = new_chunk();
00296                             cnk = cnk->next;
00297                      } else {
00298                             cnk = new_chunk();
00299                      }
00300                      if (!cnk) goto done;
00301                      if (!chunks) chunks = cnk;
00302                      
00303                      if (ch == '%') {
00304                             state = DP_S_FLAGS;
00305                             ch = *format++;
00306                      } else {
00307                             cnk->type = CNK_FMT_STR;
00308                             cnk->start = format - base -1;
00309                             while ((ch != '\0') && (ch != '%')) ch = *format++;
00310                             cnk->len = format - base - cnk->start -1;
00311                      }
00312                      break;
00313               case DP_S_FLAGS:
00314                      switch (ch) {
00315                      case '-':
00316                             cnk->flags |= DP_F_MINUS;
00317                             ch = *format++;
00318                             break;
00319                      case '+':
00320                             cnk->flags |= DP_F_PLUS;
00321                             ch = *format++;
00322                             break;
00323                      case ' ':
00324                             cnk->flags |= DP_F_SPACE;
00325                             ch = *format++;
00326                             break;
00327                      case '#':
00328                             cnk->flags |= DP_F_NUM;
00329                             ch = *format++;
00330                             break;
00331                      case '0':
00332                             cnk->flags |= DP_F_ZERO;
00333                             ch = *format++;
00334                             break;
00335                      case 'I':
00336                             /* internationalization not supported yet */
00337                             ch = *format++;
00338                             break;
00339                      default:
00340                             state = DP_S_MIN;
00341                             break;
00342                      }
00343                      break;
00344               case DP_S_MIN:
00345                      if (isdigit((unsigned char)ch)) {
00346                             cnk->min = 10 * cnk->min + char_to_int (ch);
00347                             ch = *format++;
00348                      } else if (ch == '$') {
00349                             if (!pfirst && !pflag) {
00350                                    /* parameters must be all positioned or none */
00351                                    goto done;
00352                             }
00353                             if (pfirst) {
00354                                    pfirst = 0;
00355                                    pflag = 1;
00356                             }
00357                             if (cnk->min == 0) /* what ?? */
00358                                    goto done;
00359                             cnk->num = cnk->min;
00360                             cnk->min = 0;
00361                             ch = *format++;
00362                      } else if (ch == '*') {
00363                             if (pfirst) pfirst = 0;
00364                             cnk->min_star = new_chunk();
00365                             if (!cnk->min_star) /* out of memory :-( */
00366                                    goto done;
00367                             cnk->min_star->type = CNK_INT;
00368                             if (pflag) {
00369                                    int num;
00370                                    ch = *format++;
00371                                    if (!isdigit((unsigned char)ch)) {
00372                                           /* parameters must be all positioned or none */
00373                                           goto done;
00374                                    }
00375                                    for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
00376                                           num = 10 * num + char_to_int(ch);
00377                                    }
00378                                    cnk->min_star->num = num;
00379                                    if (ch != '$') /* what ?? */
00380                                           goto done;
00381                             } else {
00382                                    cnk->min_star->num = ++pnum;
00383                             }
00384                             max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star);
00385                             if (max_pos == 0) /* out of memory :-( */
00386                                    goto done;
00387                             ch = *format++;
00388                             state = DP_S_DOT;
00389                      } else {
00390                             if (pfirst) pfirst = 0;
00391                             state = DP_S_DOT;
00392                      }
00393                      break;
00394               case DP_S_DOT:
00395                      if (ch == '.') {
00396                             state = DP_S_MAX;
00397                             ch = *format++;
00398                      } else { 
00399                             state = DP_S_MOD;
00400                      }
00401                      break;
00402               case DP_S_MAX:
00403                      if (isdigit((unsigned char)ch)) {
00404                             if (cnk->max < 0)
00405                                    cnk->max = 0;
00406                             cnk->max = 10 * cnk->max + char_to_int (ch);
00407                             ch = *format++;
00408                      } else if (ch == '$') {
00409                             if (!pfirst && !pflag) {
00410                                    /* parameters must be all positioned or none */
00411                                    goto done;
00412                             }
00413                             if (cnk->max <= 0) /* what ?? */
00414                                    goto done;
00415                             cnk->num = cnk->max;
00416                             cnk->max = -1;
00417                             ch = *format++;
00418                      } else if (ch == '*') {
00419                             cnk->max_star = new_chunk();
00420                             if (!cnk->max_star) /* out of memory :-( */
00421                                    goto done;
00422                             cnk->max_star->type = CNK_INT;
00423                             if (pflag) {
00424                                    int num;
00425                                    ch = *format++;
00426                                    if (!isdigit((unsigned char)ch)) {
00427                                           /* parameters must be all positioned or none */
00428                                           goto done;
00429                                    }
00430                                    for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
00431                                           num = 10 * num + char_to_int(ch);
00432                                    }
00433                                    cnk->max_star->num = num;
00434                                    if (ch != '$') /* what ?? */
00435                                           goto done;
00436                             } else {
00437                                    cnk->max_star->num = ++pnum;
00438                             }
00439                             max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star);
00440                             if (max_pos == 0) /* out of memory :-( */
00441                                    goto done;
00442 
00443                             ch = *format++;
00444                             state = DP_S_MOD;
00445                      } else {
00446                             state = DP_S_MOD;
00447                      }
00448                      break;
00449               case DP_S_MOD:
00450                      switch (ch) {
00451                      case 'h':
00452                             cnk->cflags = DP_C_SHORT;
00453                             ch = *format++;
00454                             if (ch == 'h') {
00455                                    cnk->cflags = DP_C_CHAR;
00456                                    ch = *format++;
00457                             }
00458                             break;
00459                      case 'l':
00460                             cnk->cflags = DP_C_LONG;
00461                             ch = *format++;
00462                             if (ch == 'l') {     /* It's a long long */
00463                                    cnk->cflags = DP_C_LLONG;
00464                                    ch = *format++;
00465                             }
00466                             break;
00467                      case 'L':
00468                             cnk->cflags = DP_C_LDOUBLE;
00469                             ch = *format++;
00470                             break;
00471                      default:
00472                             break;
00473                      }
00474                      state = DP_S_CONV;
00475                      break;
00476               case DP_S_CONV:
00477                      if (cnk->num == 0) cnk->num = ++pnum;
00478                      max_pos = add_cnk_list_entry(&clist, max_pos, cnk);
00479                      if (max_pos == 0) /* out of memory :-( */
00480                             goto done;
00481                      
00482                      switch (ch) {
00483                      case 'd':
00484                      case 'i':
00485                             cnk->type = CNK_INT;
00486                             break;
00487                      case 'o':
00488                             cnk->type = CNK_OCTAL;
00489                             cnk->flags |= DP_F_UNSIGNED;
00490                             break;
00491                      case 'u':
00492                             cnk->type = CNK_UINT;
00493                             cnk->flags |= DP_F_UNSIGNED;
00494                             break;
00495                      case 'X':
00496                             cnk->flags |= DP_F_UP;
00497                      case 'x':
00498                             cnk->type = CNK_HEX;
00499                             cnk->flags |= DP_F_UNSIGNED;
00500                             break;
00501                      case 'A':
00502                             /* hex float not supported yet */
00503                      case 'E':
00504                      case 'G':
00505                      case 'F':
00506                             cnk->flags |= DP_F_UP;
00507                      case 'a':
00508                             /* hex float not supported yet */
00509                      case 'e':
00510                      case 'f':
00511                      case 'g':
00512                             cnk->type = CNK_FLOAT;
00513                             break;
00514                      case 'c':
00515                             cnk->type = CNK_CHAR;
00516                             break;
00517                      case 's':
00518                             cnk->type = CNK_STRING;
00519                             break;
00520                      case 'p':
00521                             cnk->type = CNK_PTR;
00522                             break;
00523                      case 'n':
00524                             cnk->type = CNK_NUM;
00525                             break;
00526                      case '%':
00527                             cnk->type = CNK_PRCNT;
00528                             break;
00529                      default:
00530                             /* Unknown, bail out*/
00531                             goto done;
00532                      }
00533                      ch = *format++;
00534                      state = DP_S_DEFAULT;
00535                      break;
00536               case DP_S_DONE:
00537                      break;
00538               default:
00539                      /* hmm? */
00540                      break; /* some picky compilers need this */
00541               }
00542        }
00543 
00544        /* retieve the format arguments */
00545        for (pnum = 0; pnum < max_pos; pnum++) {
00546               int i;
00547 
00548               if (clist[pnum].num == 0) {
00549                      /* ignoring a parameter should not be permitted
00550                       * all parameters must be matched at least once
00551                       * BUT seem some system ignore this rule ...
00552                       * at least my glibc based system does --SSS
00553                       */
00554 #ifdef DEBUG_SNPRINTF
00555                      printf("parameter at position %d not used\n", pnum+1);
00556 #endif
00557                      /* eat the parameter */
00558                      va_arg (args, int);
00559                      continue;
00560               }
00561               for (i = 1; i < clist[pnum].num; i++) {
00562                      if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) {
00563                             /* nooo noo no!
00564                              * all the references to a parameter
00565                              * must be of the same type
00566                              */
00567                             goto done;
00568                      }
00569               }
00570               cnk = clist[pnum].chunks[0];
00571               switch (cnk->type) {
00572               case CNK_INT:
00573                      if (cnk->cflags == DP_C_SHORT) 
00574                             cnk->value = va_arg (args, int);
00575                      else if (cnk->cflags == DP_C_LONG)
00576                             cnk->value = va_arg (args, long int);
00577                      else if (cnk->cflags == DP_C_LLONG)
00578                             cnk->value = va_arg (args, LLONG);
00579                      else
00580                             cnk->value = va_arg (args, int);
00581 
00582                      for (i = 1; i < clist[pnum].num; i++) {
00583                             clist[pnum].chunks[i]->value = cnk->value;
00584                      }
00585                      break;
00586 
00587               case CNK_OCTAL:
00588               case CNK_UINT:
00589               case CNK_HEX:
00590                      if (cnk->cflags == DP_C_SHORT)
00591                             cnk->value = va_arg (args, unsigned int);
00592                      else if (cnk->cflags == DP_C_LONG)
00593                             cnk->value = (long)va_arg (args, unsigned long int);
00594                      else if (cnk->cflags == DP_C_LLONG)
00595                             cnk->value = (LLONG)va_arg (args, unsigned LLONG);
00596                      else
00597                             cnk->value = (long)va_arg (args, unsigned int);
00598 
00599                      for (i = 1; i < clist[pnum].num; i++) {
00600                             clist[pnum].chunks[i]->value = cnk->value;
00601                      }
00602                      break;
00603 
00604               case CNK_FLOAT:
00605                      if (cnk->cflags == DP_C_LDOUBLE)
00606                             cnk->fvalue = va_arg (args, LDOUBLE);
00607                      else
00608                             cnk->fvalue = va_arg (args, double);
00609 
00610                      for (i = 1; i < clist[pnum].num; i++) {
00611                             clist[pnum].chunks[i]->fvalue = cnk->fvalue;
00612                      }
00613                      break;
00614 
00615               case CNK_CHAR:
00616                      cnk->value = va_arg (args, int);
00617 
00618                      for (i = 1; i < clist[pnum].num; i++) {
00619                             clist[pnum].chunks[i]->value = cnk->value;
00620                      }
00621                      break;
00622 
00623               case CNK_STRING:
00624                      cnk->strvalue = va_arg (args, char *);
00625                      if (!cnk->strvalue) cnk->strvalue = "(NULL)";
00626 
00627                      for (i = 1; i < clist[pnum].num; i++) {
00628                             clist[pnum].chunks[i]->strvalue = cnk->strvalue;
00629                      }
00630                      break;
00631 
00632               case CNK_PTR:
00633                      cnk->strvalue = va_arg (args, void *);
00634                      for (i = 1; i < clist[pnum].num; i++) {
00635                             clist[pnum].chunks[i]->strvalue = cnk->strvalue;
00636                      }
00637                      break;
00638 
00639               case CNK_NUM:
00640                      if (cnk->cflags == DP_C_CHAR)
00641                             cnk->pnum = va_arg (args, char *);
00642                      else if (cnk->cflags == DP_C_SHORT)
00643                             cnk->pnum = va_arg (args, short int *);
00644                      else if (cnk->cflags == DP_C_LONG)
00645                             cnk->pnum = va_arg (args, long int *);
00646                      else if (cnk->cflags == DP_C_LLONG)
00647                             cnk->pnum = va_arg (args, LLONG *);
00648                      else
00649                             cnk->pnum = va_arg (args, int *);
00650 
00651                      for (i = 1; i < clist[pnum].num; i++) {
00652                             clist[pnum].chunks[i]->pnum = cnk->pnum;
00653                      }
00654                      break;
00655 
00656               case CNK_PRCNT:
00657                      break;
00658 
00659               default:
00660                      /* what ?? */
00661                      goto done;
00662               }
00663        }
00664        /* print out the actual string from chunks */
00665        currlen = 0;
00666        cnk = chunks;
00667        while (cnk) {
00668               int len, min, max;
00669 
00670               if (cnk->min_star) min = cnk->min_star->value;
00671               else min = cnk->min;
00672               if (cnk->max_star) max = cnk->max_star->value;
00673               else max = cnk->max;
00674 
00675               switch (cnk->type) {
00676 
00677               case CNK_FMT_STR:
00678                      if (maxlen != 0 && maxlen > currlen) {
00679                             if (maxlen > (currlen + cnk->len)) len = cnk->len;
00680                             else len = maxlen - currlen;
00681 
00682                             memcpy(&(buffer[currlen]), &(base[cnk->start]), len);
00683                      }
00684                      currlen += cnk->len;
00685                             
00686                      break;
00687 
00688               case CNK_INT:
00689               case CNK_UINT:
00690                      fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags);
00691                      break;
00692 
00693               case CNK_OCTAL:
00694                      fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags);
00695                      break;
00696 
00697               case CNK_HEX:
00698                      fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags);
00699                      break;
00700 
00701               case CNK_FLOAT:
00702                      fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags);
00703                      break;
00704 
00705               case CNK_CHAR:
00706                      dopr_outch (buffer, &currlen, maxlen, cnk->value);
00707                      break;
00708 
00709               case CNK_STRING:
00710                      if (max == -1) {
00711                             max = strlen(cnk->strvalue);
00712                      }
00713                      fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max);
00714                      break;
00715 
00716               case CNK_PTR:
00717                      fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags);
00718                      break;
00719 
00720               case CNK_NUM:
00721                      if (cnk->cflags == DP_C_CHAR)
00722                             *((char *)(cnk->pnum)) = (char)currlen;
00723                      else if (cnk->cflags == DP_C_SHORT)
00724                             *((short int *)(cnk->pnum)) = (short int)currlen;
00725                      else if (cnk->cflags == DP_C_LONG)
00726                             *((long int *)(cnk->pnum)) = (long int)currlen;
00727                      else if (cnk->cflags == DP_C_LLONG)
00728                             *((LLONG *)(cnk->pnum)) = (LLONG)currlen;
00729                      else
00730                             *((int *)(cnk->pnum)) = (int)currlen;
00731                      break;
00732 
00733               case CNK_PRCNT:
00734                      dopr_outch (buffer, &currlen, maxlen, '%');
00735                      break;
00736 
00737               default:
00738                      /* what ?? */
00739                      goto done;
00740               }
00741               cnk = cnk->next;
00742        }
00743        if (maxlen != 0) {
00744               if (currlen < maxlen - 1) 
00745                      buffer[currlen] = '\0';
00746               else if (maxlen > 0) 
00747                      buffer[maxlen - 1] = '\0';
00748        }
00749        ret = currlen;
00750 
00751 done:
00752        while (chunks) {
00753               cnk = chunks->next;
00754               free(chunks);
00755               chunks = cnk;
00756        }
00757        if (clist) {
00758               for (pnum = 0; pnum < max_pos; pnum++) {
00759                      if (clist[pnum].chunks) free(clist[pnum].chunks);
00760               }
00761               free(clist);
00762        }
00763        return ret;
00764 }
00765 
00766 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
00767                   char *value, int flags, int min, int max)
00768 {
00769        int padlen, strln;     /* amount to pad */
00770        int cnt = 0;
00771 
00772 #ifdef DEBUG_SNPRINTF
00773        printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
00774 #endif
00775        if (value == 0) {
00776               value = "<NULL>";
00777        }
00778 
00779        for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
00780        padlen = min - strln;
00781        if (padlen < 0) 
00782               padlen = 0;
00783        if (flags & DP_F_MINUS) 
00784               padlen = -padlen; /* Left Justify */
00785        
00786        while (padlen > 0) {
00787               dopr_outch (buffer, currlen, maxlen, ' ');
00788               --padlen;
00789        }
00790        while (*value && (cnt < max)) {
00791               dopr_outch (buffer, currlen, maxlen, *value++);
00792               ++cnt;
00793        }
00794        while (padlen < 0) {
00795               dopr_outch (buffer, currlen, maxlen, ' ');
00796               ++padlen;
00797        }
00798 }
00799 
00800 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
00801 
00802 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
00803                   long value, int base, int min, int max, int flags)
00804 {
00805        int signvalue = 0;
00806        unsigned long uvalue;
00807        char convert[20];
00808        int place = 0;
00809        int spadlen = 0; /* amount to space pad */
00810        int zpadlen = 0; /* amount to zero pad */
00811        int caps = 0;
00812        
00813        if (max < 0)
00814               max = 0;
00815        
00816        uvalue = value;
00817        
00818        if(!(flags & DP_F_UNSIGNED)) {
00819               if( value < 0 ) {
00820                      signvalue = '-';
00821                      uvalue = -value;
00822               } else {
00823                      if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
00824                             signvalue = '+';
00825                      else if (flags & DP_F_SPACE)
00826                             signvalue = ' ';
00827               }
00828        }
00829   
00830        if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
00831 
00832        do {
00833               convert[place++] =
00834                      (caps? "0123456789ABCDEF":"0123456789abcdef")
00835                      [uvalue % (unsigned)base  ];
00836               uvalue = (uvalue / (unsigned)base );
00837        } while(uvalue && (place < 20));
00838        if (place == 20) place--;
00839        convert[place] = 0;
00840 
00841        zpadlen = max - place;
00842        spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
00843        if (zpadlen < 0) zpadlen = 0;
00844        if (spadlen < 0) spadlen = 0;
00845        if (flags & DP_F_ZERO) {
00846               zpadlen = MAX(zpadlen, spadlen);
00847               spadlen = 0;
00848        }
00849        if (flags & DP_F_MINUS) 
00850               spadlen = -spadlen; /* Left Justifty */
00851 
00852 #ifdef DEBUG_SNPRINTF
00853        printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
00854               zpadlen, spadlen, min, max, place);
00855 #endif
00856 
00857        /* Spaces */
00858        while (spadlen > 0) {
00859               dopr_outch (buffer, currlen, maxlen, ' ');
00860               --spadlen;
00861        }
00862 
00863        /* Sign */
00864        if (signvalue) 
00865               dopr_outch (buffer, currlen, maxlen, signvalue);
00866 
00867        /* Zeros */
00868        if (zpadlen > 0) {
00869               while (zpadlen > 0) {
00870                      dopr_outch (buffer, currlen, maxlen, '0');
00871                      --zpadlen;
00872               }
00873        }
00874 
00875        /* Digits */
00876        while (place > 0) 
00877               dopr_outch (buffer, currlen, maxlen, convert[--place]);
00878   
00879        /* Left Justified spaces */
00880        while (spadlen < 0) {
00881               dopr_outch (buffer, currlen, maxlen, ' ');
00882               ++spadlen;
00883        }
00884 }
00885 
00886 static LDOUBLE abs_val(LDOUBLE value)
00887 {
00888        LDOUBLE result = value;
00889 
00890        if (value < 0)
00891               result = -value;
00892        
00893        return result;
00894 }
00895 
00896 static LDOUBLE POW10(int exp)
00897 {
00898        LDOUBLE result = 1;
00899        
00900        while (exp) {
00901               result *= 10;
00902               exp--;
00903        }
00904   
00905        return result;
00906 }
00907 
00908 static LLONG ROUND(LDOUBLE value)
00909 {
00910        LLONG intpart;
00911 
00912        intpart = (LLONG)value;
00913        value = value - intpart;
00914        if (value >= 0.5) intpart++;
00915        
00916        return intpart;
00917 }
00918 
00919 /* a replacement for modf that doesn't need the math library. Should
00920    be portable, but slow */
00921 static double my_modf(double x0, double *iptr)
00922 {
00923        int i;
00924        long l;
00925        double x = x0;
00926        double f = 1.0;
00927 
00928        for (i=0;i<100;i++) {
00929               l = (long)x;
00930               if (l <= (x+1) && l >= (x-1)) break;
00931               x *= 0.1;
00932               f *= 10.0;
00933        }
00934 
00935        if (i == 100) {
00936               /* yikes! the number is beyond what we can handle. What do we do? */
00937               (*iptr) = 0;
00938               return 0;
00939        }
00940 
00941        if (i != 0) {
00942               double i2;
00943               double ret;
00944 
00945               ret = my_modf(x0-l*f, &i2);
00946               (*iptr) = l*f + i2;
00947               return ret;
00948        } 
00949 
00950        (*iptr) = l;
00951        return x - (*iptr);
00952 }
00953 
00954 
00955 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
00956                  LDOUBLE fvalue, int min, int max, int flags)
00957 {
00958        int signvalue = 0;
00959        double ufvalue;
00960        char iconvert[311];
00961        char fconvert[311];
00962        int iplace = 0;
00963        int fplace = 0;
00964        int padlen = 0; /* amount to pad */
00965        int zpadlen = 0; 
00966        int caps = 0;
00967        int idx;
00968        double intpart;
00969        double fracpart;
00970        double temp;
00971   
00972        /* 
00973         * AIX manpage says the default is 0, but Solaris says the default
00974         * is 6, and sprintf on AIX defaults to 6
00975         */
00976        if (max < 0)
00977               max = 6;
00978 
00979        ufvalue = abs_val (fvalue);
00980 
00981        if (fvalue < 0) {
00982               signvalue = '-';
00983        } else {
00984               if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
00985                      signvalue = '+';
00986               } else {
00987                      if (flags & DP_F_SPACE)
00988                             signvalue = ' ';
00989               }
00990        }
00991 
00992 #if 0
00993        if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
00994 #endif
00995 
00996 #if 0
00997         if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
00998 #endif
00999 
01000        /* 
01001         * Sorry, we only support 9 digits past the decimal because of our 
01002         * conversion method
01003         */
01004        if (max > 9)
01005               max = 9;
01006 
01007        /* We "cheat" by converting the fractional part to integer by
01008         * multiplying by a factor of 10
01009         */
01010 
01011        temp = ufvalue;
01012        my_modf(temp, &intpart);
01013 
01014        fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
01015        
01016        if (fracpart >= POW10(max)) {
01017               intpart++;
01018               fracpart -= POW10(max);
01019        }
01020 
01021 
01022        /* Convert integer part */
01023        do {
01024               temp = intpart*0.1;
01025               my_modf(temp, &intpart);
01026               idx = (int) ((temp -intpart +0.05)* 10.0);
01027               /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
01028               /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
01029               iconvert[iplace++] =
01030                      (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
01031        } while (intpart && (iplace < 311));
01032        if (iplace == 311) iplace--;
01033        iconvert[iplace] = 0;
01034 
01035        /* Convert fractional part */
01036        if (fracpart)
01037        {
01038               do {
01039                      temp = fracpart*0.1;
01040                      my_modf(temp, &fracpart);
01041                      idx = (int) ((temp -fracpart +0.05)* 10.0);
01042                      /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
01043                      /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
01044                      fconvert[fplace++] =
01045                      (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
01046               } while(fracpart && (fplace < 311));
01047               if (fplace == 311) fplace--;
01048        }
01049        fconvert[fplace] = 0;
01050   
01051        /* -1 for decimal point, another -1 if we are printing a sign */
01052        padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
01053        zpadlen = max - fplace;
01054        if (zpadlen < 0) zpadlen = 0;
01055        if (padlen < 0) 
01056               padlen = 0;
01057        if (flags & DP_F_MINUS) 
01058               padlen = -padlen; /* Left Justifty */
01059        
01060        if ((flags & DP_F_ZERO) && (padlen > 0)) {
01061               if (signvalue) {
01062                      dopr_outch (buffer, currlen, maxlen, signvalue);
01063                      --padlen;
01064                      signvalue = 0;
01065               }
01066               while (padlen > 0) {
01067                      dopr_outch (buffer, currlen, maxlen, '0');
01068                      --padlen;
01069               }
01070        }
01071        while (padlen > 0) {
01072               dopr_outch (buffer, currlen, maxlen, ' ');
01073               --padlen;
01074        }
01075        if (signvalue) 
01076               dopr_outch (buffer, currlen, maxlen, signvalue);
01077        
01078        while (iplace > 0) 
01079               dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
01080 
01081 #ifdef DEBUG_SNPRINTF
01082        printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
01083 #endif
01084 
01085        /*
01086         * Decimal point.  This should probably use locale to find the correct
01087         * char to print out.
01088         */
01089        if (max > 0) {
01090               dopr_outch (buffer, currlen, maxlen, '.');
01091               
01092               while (zpadlen > 0) {
01093                      dopr_outch (buffer, currlen, maxlen, '0');
01094                      --zpadlen;
01095               }
01096 
01097               while (fplace > 0) 
01098                      dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
01099        }
01100 
01101        while (padlen < 0) {
01102               dopr_outch (buffer, currlen, maxlen, ' ');
01103               ++padlen;
01104        }
01105 }
01106 
01107 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
01108 {
01109        if (*currlen < maxlen) {
01110               buffer[(*currlen)] = c;
01111        }
01112        (*currlen)++;
01113 }
01114 
01115 static struct pr_chunk *new_chunk(void) {
01116        struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk));
01117 
01118        if ( !new_c ) 
01119               return NULL;
01120 
01121        new_c->type = 0;
01122        new_c->num = 0;
01123        new_c->min = 0;
01124        new_c->min_star = NULL;
01125        new_c->max = -1;
01126        new_c->max_star = NULL;
01127        new_c->flags = 0;
01128        new_c->cflags = 0;
01129        new_c->start = 0;
01130        new_c->len = 0;
01131        new_c->value = 0;
01132        new_c->fvalue = 0;
01133        new_c->strvalue = NULL;
01134        new_c->pnum = NULL;
01135        new_c->next = NULL;
01136 
01137        return new_c;
01138 }
01139 
01140 static int add_cnk_list_entry(struct pr_chunk_x **list,
01141                             int max_num, struct pr_chunk *chunk) {
01142        struct pr_chunk_x *l;
01143        struct pr_chunk **c;
01144        int max;
01145        int cnum;
01146        int i, pos;
01147 
01148        if (chunk->num > max_num) {
01149               max = chunk->num;
01150        
01151               if (*list == NULL) {
01152                      l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max);
01153                      pos = 0;
01154               } else {
01155                      l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max);
01156                      pos = max_num;
01157               }
01158               if (l == NULL) {
01159                      for (i = 0; i < max; i++) {
01160                             if ((*list)[i].chunks) free((*list)[i].chunks);
01161                      }
01162                      return 0;
01163               }
01164               for (i = pos; i < max; i++) {
01165                      l[i].chunks = NULL;
01166                      l[i].num = 0;
01167               }
01168        } else {
01169               l = *list;
01170               max = max_num;
01171        }
01172 
01173        i = chunk->num - 1;
01174        cnum = l[i].num + 1;
01175        if (l[i].chunks == NULL) {
01176               c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum); 
01177        } else {
01178               c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum);
01179        }
01180        if (c == NULL) {
01181               for (i = 0; i < max; i++) {
01182                      if (l[i].chunks) free(l[i].chunks);
01183               }
01184               return 0;
01185        }
01186        c[l[i].num] = chunk;
01187        l[i].chunks = c;
01188        l[i].num = cnum;
01189 
01190        *list = l;
01191        return max;
01192 }
01193 
01194  int smb_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
01195 {
01196        return dopr(str, count, fmt, args);
01197 }
01198 #define vsnprintf smb_vsnprintf
01199 #endif
01200 
01201 /* yes this really must be a ||. Don't muck with this (tridge)
01202  *
01203  * The logic for these two is that we need our own definition if the
01204  * OS *either* has no definition of *sprintf, or if it does have one
01205  * that doesn't work properly according to the autoconf test.
01206  */
01207 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
01208 int smb_snprintf(char *str,size_t count,const char *fmt,...)
01209 {
01210        size_t ret;
01211        va_list ap;
01212     
01213        va_start(ap, fmt);
01214        ret = vsnprintf(str, count, fmt, ap);
01215        va_end(ap);
01216        return ret;
01217 }
01218 #define snprintf smb_snprintf
01219 #endif
01220 
01221 #endif 
01222 
01223 #ifndef HAVE_VASPRINTF
01224  int vasprintf(char **ptr, const char *format, va_list ap)
01225 {
01226        int ret;
01227        va_list ap2;
01228 
01229        VA_COPY(ap2, ap);
01230        
01231        ret = vsnprintf(NULL, 0, format, ap2);
01232        if (ret <= 0) return ret;
01233 
01234        (*ptr) = (char *)malloc(ret+1);
01235        if (!*ptr) return -1;
01236 
01237        VA_COPY(ap2, ap);
01238 
01239        ret = vsnprintf(*ptr, ret+1, format, ap2);
01240 
01241        return ret;
01242 }
01243 #endif
01244 
01245 
01246 #ifndef HAVE_ASPRINTF
01247  int asprintf(char **ptr, const char *format, ...)
01248 {
01249        va_list ap;
01250        int ret;
01251        
01252        *ptr = NULL;
01253        va_start(ap, format);
01254        ret = vasprintf(ptr, format, ap);
01255        va_end(ap);
01256 
01257        return ret;
01258 }
01259 #endif
01260 
01261 #ifdef TEST_SNPRINTF
01262 
01263  int sprintf(char *str,const char *fmt,...);
01264 
01265  int main (void)
01266 {
01267        char buf1[1024];
01268        char buf2[1024];
01269        char *buf3;
01270        char *fp_fmt[] = {
01271               "%1.1f",
01272               "%-1.5f",
01273               "%1.5f",
01274               "%123.9f",
01275               "%10.5f",
01276               "% 10.5f",
01277               "%+22.9f",
01278               "%+4.9f",
01279               "%01.3f",
01280               "%4f",
01281               "%3.1f",
01282               "%3.2f",
01283               "%.0f",
01284               "%f",
01285               "%-8.8f",
01286               "%-9.9f",
01287               NULL
01288        };
01289        double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, 
01290                           0.9996, 1.996, 4.136, 5.030201, 0.00205,
01291                           /* END LIST */ 0};
01292        char *int_fmt[] = {
01293               "%-1.5d",
01294               "%1.5d",
01295               "%123.9d",
01296               "%5.5d",
01297               "%10.5d",
01298               "% 10.5d",
01299               "%+22.33d",
01300               "%01.3d",
01301               "%4d",
01302               "%d",
01303               NULL
01304        };
01305        long int_nums[] = { -1, 134, 91340, 341, 0203, 0, 1234567890};
01306        char *str_fmt[] = {
01307               "%10.5s",
01308               "%-10.5s",
01309               "%5.10s",
01310               "%-5.10s",
01311               "%10.1s",
01312               "%0.10s",
01313               "%10.0s",
01314               "%1.10s",
01315               "%s",
01316               "%.1s",
01317               "%.10s",
01318               "%10s",
01319               NULL
01320        };
01321        char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
01322        int x, y;
01323        int fail = 0;
01324        int num = 0;
01325        int l1, l2;
01326 
01327        printf ("Testing snprintf format codes against system sprintf...\n");
01328 
01329        for (x = 0; fp_fmt[x] ; x++) {
01330               for (y = 0; fp_nums[y] != 0 ; y++) {
01331                      buf1[0] = buf2[0] = '\0';
01332                      l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
01333                      l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
01334                      sprintf (buf2, fp_fmt[x], fp_nums[y]);
01335                      buf1[1023] = buf1[1023] = '\0';
01336                      if (strcmp (buf1, buf2) || (l1 != l2)) {
01337                             printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
01338                                    fp_fmt[x], l1, buf1, l2, buf2);
01339                             fail++;
01340                      }
01341                      num++;
01342               }
01343        }
01344 
01345        for (x = 0; int_fmt[x] ; x++) {
01346               for (y = 0; int_nums[y] != 0 ; y++) {
01347                      buf1[0] = buf2[0] = '\0';
01348                      l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
01349                      l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
01350                      sprintf (buf2, int_fmt[x], int_nums[y]);
01351                      buf1[1023] = buf1[1023] = '\0';
01352                      if (strcmp (buf1, buf2) || (l1 != l2)) {
01353                             printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
01354                                    int_fmt[x], l1, buf1, l2, buf2);
01355                             fail++;
01356                      }
01357                      num++;
01358               }
01359        }
01360 
01361        for (x = 0; str_fmt[x] ; x++) {
01362               for (y = 0; str_vals[y] != 0 ; y++) {
01363                      buf1[0] = buf2[0] = '\0';
01364                      l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
01365                      l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
01366                      sprintf (buf2, str_fmt[x], str_vals[y]);
01367                      buf1[1023] = buf1[1023] = '\0';
01368                      if (strcmp (buf1, buf2) || (l1 != l2)) {
01369                             printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
01370                                    str_fmt[x], l1, buf1, l2, buf2);
01371                             fail++;
01372                      }
01373                      num++;
01374               }
01375        }
01376 
01377 #define BUFSZ 2048
01378 
01379        buf1[0] = buf2[0] = '\0';
01380        if ((buf3 = malloc(BUFSZ)) == NULL) {
01381               fail++;
01382        } else {
01383               num++;
01384               memset(buf3, 'a', BUFSZ);
01385               snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3);
01386               buf1[1023] = '\0';
01387               if (strcmp(buf1, "a") != 0) {
01388                      printf("length limit buf1 '%s' expected 'a'\n", buf1);
01389                      fail++;
01390               }
01391         }
01392 
01393        buf1[0] = buf2[0] = '\0';
01394        l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
01395        l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
01396        buf1[1023] = buf1[1023] = '\0';
01397        if (strcmp(buf1, buf2) || (l1 != l2)) {
01398               printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01399                             "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
01400               fail++;
01401        }
01402 
01403        buf1[0] = buf2[0] = '\0';
01404        l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
01405        l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
01406        buf1[1023] = buf1[1023] = '\0';
01407        if (strcmp(buf1, buf2)) {
01408               printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01409                             "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
01410               fail++;
01411        }
01412 #if 0
01413        buf1[0] = buf2[0] = '\0';
01414        l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890);
01415        l2 = sprintf(buf2, "%lld", (LLONG)1234567890);
01416        buf1[1023] = buf1[1023] = '\0';
01417        if (strcmp(buf1, buf2)) {
01418               printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01419                             "%lld", l1, buf1, l2, buf2);
01420               fail++;
01421        }
01422 
01423        buf1[0] = buf2[0] = '\0';
01424        l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123);
01425        l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123);
01426        buf1[1023] = buf1[1023] = '\0';
01427        if (strcmp(buf1, buf2)) {
01428               printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
01429                             "%Lf", l1, buf1, l2, buf2);
01430               fail++;
01431        }
01432 #endif
01433        printf ("%d tests failed out of %d.\n", fail, num);
01434 
01435        printf("seeing how many digits we support\n");
01436        {
01437               double v0 = 0.12345678901234567890123456789012345678901;
01438               for (x=0; x<100; x++) {
01439                      double p = pow(10, x); 
01440                      double r = v0*p;
01441                      snprintf(buf1, sizeof(buf1), "%1.1f", r);
01442                      sprintf(buf2,                "%1.1f", r);
01443                      if (strcmp(buf1, buf2)) {
01444                             printf("we seem to support %d digits\n", x-1);
01445                             break;
01446                      }
01447               }
01448        }
01449 
01450        return 0;
01451 }
01452 #endif /* TEST_SNPRINTF */