Icinga-core 1.4.0
next gen monitoring
common/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 /* 02/28/2006 EG changed path to config.h to match Icinga 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 */
 All Data Structures Files Functions Variables Typedefs Defines