![]() |
Icinga-core 1.4.0
next gen monitoring
|
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 */