[PATCH v3] Update snprintf.c
Ladislav Michl <[email protected]> Fri, 11 Jan 2019 21:26:21 +0100
| Newsgroups | gmane.linux.drivers.gnokii |
|---|---|
| Message-ID | <20190111202621.GA24314@lenoch> |
From: Fabrizio Gennari <[email protected]> Update to the latest (7a5b65c88d3b) version from Samba's repository. --- CHANGES: -v2: none -v3: update to the latest version with fixed whitespaces ChangeLog | 3 + common/snprintf.c | 1170 +++++++++++++++++++++++++++++++++------------ 2 files changed, 863 insertions(+), 310 deletions(-) diff --git a/ChangeLog b/ChangeLog index ed6d42ff..ad462734 100644 --- a/ChangeLog +++ b/ChangeLog @@ -121,6 +121,9 @@ o since Linux filesystems are case-sensitive, and MinGW-W64 provides lower case names for Win32 header files, use lower case names in #include directives + o update snprintf.c (replacement of snprintf for systems where + it is not C99-compatible, such as Win32) to the latest + version from Samba's repository 0.6.31 ====== diff --git a/common/snprintf.c b/common/snprintf.c index b1222806..7cbef94f 100644 --- a/common/snprintf.c +++ b/common/snprintf.c @@ -1,3 +1,7 @@ +/* + * NOTE: If you change this file, please merge it into rsync, samba, etc. + */ + /* * Copyright Patrick Powell 1995 * This code is based on code written by Patrick Powell ([email protected]) @@ -30,7 +34,7 @@ * probably requires libm on most operating systems. Don't yet * support the exponent (e,E) and sigfig (g,G). Also, fmtint() * was pretty badly broken, it just wasn't being exercised in ways - * which showed it, so that's been fixed. Also, formated the code + * which showed it, so that's been fixed. Also, formatted the code * to mutt conventions, and removed dead code left over from the * original. Also, there is now a builtin-test, just compile with: * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm @@ -53,47 +57,76 @@ * got rid of fcvt code (twas buggy and made testing harder) * added C99 semantics * + * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0 + * actually print args for %g and %e + * + * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0 + * Since includes.h isn't included here, VA_COPY has to be defined here. I don't + * see any include file that is guaranteed to be here, so I'm defining it + * locally. Fixes AIX and Solaris builds. + * + * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13 + * put the ifdef for HAVE_VA_COPY in one place rather than in lots of + * functions + * + * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4 + * Fix usage of va_list passed as an arg. Use __va_copy before using it + * when it exists. + * + * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14 + * Fix incorrect zpadlen handling in fmtfp. + * Thanks to Ollie Oldham <[email protected]> for spotting it. + * few mods to make it easier to compile the tests. + * addedd the "Ollie" test to the floating point ones. + * + * Martin Pool ([email protected]) April 2003 + * Remove NO_CONFIG_H so that the test case can be built within a source + * tree with less trouble. + * Remove unnecessary SAFE_FREE() definition. + * + * Martin Pool ([email protected]) May 2003 + * Put in a prototype for dummy_snprintf() to quiet compiler warnings. + * + * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even + * if the C library has some snprintf functions already. + * + * Darren Tucker ([email protected]) 2005 + * Fix bug allowing read overruns of the source string with "%.*s" + * Usually harmless unless the read runs outside the process' allocation + * (eg if your malloc does guard pages) in which case it will segfault. + * From OpenSSH. Also added test for same. + * + * Simo Sorce ([email protected]) Jan 2006 + * + * Add support for position independent parameters + * fix fmtstr now it conforms to sprintf wrt min.max + * **************************************************************/ -#ifndef NO_CONFIG_H /* for some tests */ -# include "config.h" -#endif - #include "compat.h" -#define snprintf __dummy_snprintf - -#if defined(WIN32) && !defined(CYGWIN) -# include <stdio.h> -# include <stddef.h> -#endif +#ifdef TEST_SNPRINTF /* need math library headers for testing */ -#ifdef HAVE_STRING_H -# include <string.h> -#endif - -#ifdef HAVE_STRINGS_H -# include <strings.h> -#endif -#ifdef HAVE_CTYPE_H -# include <ctype.h> -#endif -#include <sys/types.h> -#ifdef HAVE_STDARG_H -# include <stdarg.h> -#endif -#ifdef HAVE_STDLIB_H -# include <stdlib.h> -#endif - -#undef snprintf +/* In test mode, we pretend that this system doesn't have any snprintf + * functions, regardless of what config.h says. */ +# undef HAVE_SNPRINTF +# undef HAVE_VSNPRINTF +# undef HAVE_C99_VSNPRINTF +# undef HAVE_ASPRINTF +# undef HAVE_VASPRINTF +# include <math.h> +#endif /* TEST_SNPRINTF */ #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF) /* only include stdio.h if we are not re-defining snprintf or vsnprintf */ -# include <stdio.h> -/* make the compiler happy with an empty file */ -void dummy_snprintf(void) {} -#else +#include <stdio.h> + /* make the compiler happy with an empty file */ + void dummy_snprintf(void); + void dummy_snprintf(void) {} +#endif /* HAVE_SNPRINTF, etc */ + +/* yes this really must be a ||. Don't muck with this (tridge) */ +#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) #ifdef HAVE_LONG_DOUBLE #define LDOUBLE long double @@ -101,26 +134,22 @@ void dummy_snprintf(void) {} #define LDOUBLE double #endif -#ifdef HAVE_LONG_LONG_INT +#ifdef HAVE_LONG_LONG #define LLONG long long #else #define LLONG long #endif -/* free memory if the pointer is valid and zero the pointer */ -#ifndef SAFE_FREE -#define SAFE_FREE(x) do { if ((x) != NULL) {free((x)); (x)=NULL;} } while(0) +#ifndef VA_COPY +#ifdef HAVE_VA_COPY +#define VA_COPY(dest, src) va_copy(dest, src) +#else +#ifdef HAVE___VA_COPY +#define VA_COPY(dest, src) __va_copy(dest, src) +#else +#define VA_COPY(dest, src) (dest) = (src) +#endif #endif - -static size_t dopr(char *buffer, size_t maxlen, const char *format, - va_list args); -static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, - char *value, int flags, int min, int max); -static void fmtint(char *buffer, size_t *currlen, size_t maxlen, - long value, int base, int min, int max, int flags); -static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, - LDOUBLE fvalue, int min, int max, int flags); -static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); /* * dopr(): poor man's version of doprintf @@ -137,75 +166,154 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); #define DP_S_DONE 7 /* format flags - Bits */ -#define DP_F_MINUS (1 << 0) -#define DP_F_PLUS (1 << 1) -#define DP_F_SPACE (1 << 2) -#define DP_F_NUM (1 << 3) -#define DP_F_ZERO (1 << 4) -#define DP_F_UP (1 << 5) -#define DP_F_UNSIGNED (1 << 6) +#define DP_F_MINUS (1 << 0) +#define DP_F_PLUS (1 << 1) +#define DP_F_SPACE (1 << 2) +#define DP_F_NUM (1 << 3) +#define DP_F_ZERO (1 << 4) +#define DP_F_UP (1 << 5) +#define DP_F_UNSIGNED (1 << 6) /* Conversion Flags */ -#define DP_C_SHORT 1 -#define DP_C_LONG 2 -#define DP_C_LDOUBLE 3 -#define DP_C_LLONG 4 +#define DP_C_CHAR 1 +#define DP_C_SHORT 2 +#define DP_C_LONG 3 +#define DP_C_LDOUBLE 4 +#define DP_C_LLONG 5 +#define DP_C_SIZET 6 + +/* Chunk types */ +#define CNK_FMT_STR 0 +#define CNK_INT 1 +#define CNK_OCTAL 2 +#define CNK_UINT 3 +#define CNK_HEX 4 +#define CNK_FLOAT 5 +#define CNK_CHAR 6 +#define CNK_STRING 7 +#define CNK_PTR 8 +#define CNK_NUM 9 +#define CNK_PRCNT 10 #define char_to_int(p) ((p)- '0') #ifndef MAX #define MAX(p,q) (((p) >= (q)) ? (p) : (q)) #endif -static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args) -{ - char ch; - LLONG value; - LDOUBLE fvalue; - char *strvalue; +struct pr_chunk { + int type; /* chunk type */ + int num; /* parameter number */ int min; int max; - int state; int flags; int cflags; + int start; + int len; + LLONG value; + LDOUBLE fvalue; + char *strvalue; + void *pnum; + struct pr_chunk *min_star; + struct pr_chunk *max_star; + struct pr_chunk *next; +}; + +struct pr_chunk_x { + struct pr_chunk **chunks; + int num; +}; + +static int dopr(char *buffer, size_t maxlen, const char *format, + va_list args_in); +static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max); +static void fmtint(char *buffer, size_t *currlen, size_t maxlen, + LLONG value, int base, int min, int max, int flags); +static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, + LDOUBLE fvalue, int min, int max, int flags); +static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); +static struct pr_chunk *new_chunk(void); +static int add_cnk_list_entry(struct pr_chunk_x **list, + int max_num, struct pr_chunk *chunk); + +static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) +{ + char ch; + int state; + int pflag; + int pnum; + int pfirst; size_t currlen; - + va_list args; + const char *base; + struct pr_chunk *chunks = NULL; + struct pr_chunk *cnk = NULL; + struct pr_chunk_x *clist = NULL; + int max_pos; + int ret = -1; + + VA_COPY(args, args_in); + state = DP_S_DEFAULT; - currlen = flags = cflags = min = 0; - max = -1; + pfirst = 1; + pflag = 0; + pnum = 0; + + max_pos = 0; + base = format; ch = *format++; - + + /* retrieve the string structure as chunks */ while (state != DP_S_DONE) { if (ch == '\0') state = DP_S_DONE; switch(state) { case DP_S_DEFAULT: - if (ch == '%') + + if (cnk) { + cnk->next = new_chunk(); + cnk = cnk->next; + } else { + cnk = new_chunk(); + } + if (!cnk) goto done; + if (!chunks) chunks = cnk; + + if (ch == '%') { state = DP_S_FLAGS; - else - dopr_outch (buffer, &currlen, maxlen, ch); - ch = *format++; + ch = *format++; + } else { + cnk->type = CNK_FMT_STR; + cnk->start = format - base -1; + while ((ch != '\0') && (ch != '%')) ch = *format++; + cnk->len = format - base - cnk->start -1; + } break; case DP_S_FLAGS: switch (ch) { case '-': - flags |= DP_F_MINUS; + cnk->flags |= DP_F_MINUS; ch = *format++; break; case '+': - flags |= DP_F_PLUS; + cnk->flags |= DP_F_PLUS; ch = *format++; break; case ' ': - flags |= DP_F_SPACE; + cnk->flags |= DP_F_SPACE; ch = *format++; break; case '#': - flags |= DP_F_NUM; + cnk->flags |= DP_F_NUM; ch = *format++; break; case '0': - flags |= DP_F_ZERO; + cnk->flags |= DP_F_ZERO; + ch = *format++; + break; + case 'I': + /* internationalization not supported yet */ ch = *format++; break; default: @@ -215,13 +323,51 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args break; case DP_S_MIN: if (isdigit((unsigned char)ch)) { - min = 10*min + char_to_int (ch); + cnk->min = 10 * cnk->min + char_to_int (ch); + ch = *format++; + } else if (ch == '$') { + if (!pfirst && !pflag) { + /* parameters must be all positioned or none */ + goto done; + } + if (pfirst) { + pfirst = 0; + pflag = 1; + } + if (cnk->min == 0) /* what ?? */ + goto done; + cnk->num = cnk->min; + cnk->min = 0; ch = *format++; } else if (ch == '*') { - min = va_arg (args, int); + if (pfirst) pfirst = 0; + cnk->min_star = new_chunk(); + if (!cnk->min_star) /* out of memory :-( */ + goto done; + cnk->min_star->type = CNK_INT; + if (pflag) { + int num; + ch = *format++; + if (!isdigit((unsigned char)ch)) { + /* parameters must be all positioned or none */ + goto done; + } + for (num = 0; isdigit((unsigned char)ch); ch = *format++) { + num = 10 * num + char_to_int(ch); + } + cnk->min_star->num = num; + if (ch != '$') /* what ?? */ + goto done; + } else { + cnk->min_star->num = ++pnum; + } + max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star); + if (max_pos == 0) /* out of memory :-( */ + goto done; ch = *format++; state = DP_S_DOT; } else { + if (pfirst) pfirst = 0; state = DP_S_DOT; } break; @@ -235,12 +381,45 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args break; case DP_S_MAX: if (isdigit((unsigned char)ch)) { - if (max < 0) - max = 0; - max = 10*max + char_to_int (ch); + if (cnk->max < 0) + cnk->max = 0; + cnk->max = 10 * cnk->max + char_to_int (ch); + ch = *format++; + } else if (ch == '$') { + if (!pfirst && !pflag) { + /* parameters must be all positioned or none */ + goto done; + } + if (cnk->max <= 0) /* what ?? */ + goto done; + cnk->num = cnk->max; + cnk->max = -1; ch = *format++; } else if (ch == '*') { - max = va_arg (args, int); + cnk->max_star = new_chunk(); + if (!cnk->max_star) /* out of memory :-( */ + goto done; + cnk->max_star->type = CNK_INT; + if (pflag) { + int num; + ch = *format++; + if (!isdigit((unsigned char)ch)) { + /* parameters must be all positioned or none */ + goto done; + } + for (num = 0; isdigit((unsigned char)ch); ch = *format++) { + num = 10 * num + char_to_int(ch); + } + cnk->max_star->num = num; + if (ch != '$') /* what ?? */ + goto done; + } else { + cnk->max_star->num = ++pnum; + } + max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star); + if (max_pos == 0) /* out of memory :-( */ + goto done; + ch = *format++; state = DP_S_MOD; } else { @@ -250,19 +429,31 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args case DP_S_MOD: switch (ch) { case 'h': - cflags = DP_C_SHORT; + cnk->cflags = DP_C_SHORT; ch = *format++; + if (ch == 'h') { + cnk->cflags = DP_C_CHAR; + ch = *format++; + } break; case 'l': - cflags = DP_C_LONG; + cnk->cflags = DP_C_LONG; ch = *format++; if (ch == 'l') { /* It's a long long */ - cflags = DP_C_LLONG; + cnk->cflags = DP_C_LLONG; ch = *format++; } break; + case 'j': + cnk->cflags = DP_C_LLONG; + ch = *format++; + break; case 'L': - cflags = DP_C_LDOUBLE; + cnk->cflags = DP_C_LDOUBLE; + ch = *format++; + break; + case 'z': + cnk->cflags = DP_C_SIZET; ch = *format++; break; default: @@ -271,131 +462,65 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args state = DP_S_CONV; break; case DP_S_CONV: + if (cnk->num == 0) cnk->num = ++pnum; + max_pos = add_cnk_list_entry(&clist, max_pos, cnk); + if (max_pos == 0) /* out of memory :-( */ + goto done; + switch (ch) { case 'd': case 'i': - if (cflags == DP_C_SHORT) - value = va_arg (args, int); - else if (cflags == DP_C_LONG) - value = va_arg (args, long int); - else if (cflags == DP_C_LLONG) - value = va_arg (args, LLONG); - else - value = va_arg (args, int); - fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + cnk->type = CNK_INT; break; case 'o': - flags |= DP_F_UNSIGNED; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int); - else if (cflags == DP_C_LONG) - value = (long)va_arg (args, unsigned long int); - else if (cflags == DP_C_LLONG) - value = (long)va_arg (args, unsigned LLONG); - else - value = (long)va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); + cnk->type = CNK_OCTAL; + cnk->flags |= DP_F_UNSIGNED; break; case 'u': - flags |= DP_F_UNSIGNED; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int); - else if (cflags == DP_C_LONG) - value = (long)va_arg (args, unsigned long int); - else if (cflags == DP_C_LLONG) - value = (LLONG)va_arg (args, unsigned LLONG); - else - value = (long)va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + cnk->type = CNK_UINT; + cnk->flags |= DP_F_UNSIGNED; break; case 'X': - flags |= DP_F_UP; + cnk->flags |= DP_F_UP; case 'x': - flags |= DP_F_UNSIGNED; - if (cflags == DP_C_SHORT) - value = va_arg (args, unsigned int); - else if (cflags == DP_C_LONG) - value = (long)va_arg (args, unsigned long int); - else if (cflags == DP_C_LLONG) - value = (LLONG)va_arg (args, unsigned LLONG); - else - value = (long)va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); - break; - case 'f': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, LDOUBLE); - else - fvalue = va_arg (args, double); - /* um, floating point? */ - fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + cnk->type = CNK_HEX; + cnk->flags |= DP_F_UNSIGNED; break; + case 'A': + /* hex float not supported yet */ case 'E': - flags |= DP_F_UP; - case 'e': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, LDOUBLE); - else - fvalue = va_arg (args, double); - break; case 'G': - flags |= DP_F_UP; + case 'F': + cnk->flags |= DP_F_UP; + case 'a': + /* hex float not supported yet */ + case 'e': + case 'f': case 'g': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg (args, LDOUBLE); - else - fvalue = va_arg (args, double); + cnk->type = CNK_FLOAT; break; case 'c': - dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); + cnk->type = CNK_CHAR; break; case 's': - strvalue = va_arg (args, char *); - if (!strvalue) strvalue = "(NULL)"; - if (max == -1) { - max = strlen(strvalue); - } - if (min > 0 && max >= 0 && min > max) max = min; - fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); + cnk->type = CNK_STRING; break; case 'p': - strvalue = va_arg (args, void *); - fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); + cnk->type = CNK_PTR; + cnk->flags |= DP_F_UNSIGNED; break; case 'n': - if (cflags == DP_C_SHORT) { - short int *num; - num = va_arg (args, short int *); - *num = currlen; - } else if (cflags == DP_C_LONG) { - long int *num; - num = va_arg (args, long int *); - *num = (long int)currlen; - } else if (cflags == DP_C_LLONG) { - LLONG *num; - num = va_arg (args, LLONG *); - *num = (LLONG)currlen; - } else { - int *num; - num = va_arg (args, int *); - *num = currlen; - } + cnk->type = CNK_NUM; break; case '%': - dopr_outch (buffer, &currlen, maxlen, ch); - break; - case 'w': - /* not supported yet, treat as next char */ - ch = *format++; + cnk->type = CNK_PRCNT; break; default: - /* Unknown, skip */ - break; + /* Unknown, bail out*/ + goto done; } ch = *format++; state = DP_S_DEFAULT; - flags = cflags = min = 0; - max = -1; break; case DP_S_DONE: break; @@ -404,14 +529,237 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args break; /* some picky compilers need this */ } } + + /* retrieve the format arguments */ + for (pnum = 0; pnum < max_pos; pnum++) { + int i; + + if (clist[pnum].num == 0) { + /* ignoring a parameter should not be permitted + * all parameters must be matched at least once + * BUT seem some system ignore this rule ... + * at least my glibc based system does --SSS + */ +#ifdef DEBUG_SNPRINTF + printf("parameter at position %d not used\n", pnum+1); +#endif + /* eat the parameter */ + va_arg (args, int); + continue; + } + for (i = 1; i < clist[pnum].num; i++) { + if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) { + /* nooo noo no! + * all the references to a parameter + * must be of the same type + */ + goto done; + } + } + cnk = clist[pnum].chunks[0]; + switch (cnk->type) { + case CNK_INT: + if (cnk->cflags == DP_C_SHORT) + cnk->value = va_arg (args, int); + else if (cnk->cflags == DP_C_LONG) + cnk->value = va_arg (args, long int); + else if (cnk->cflags == DP_C_LLONG) + cnk->value = va_arg (args, LLONG); + else if (cnk->cflags == DP_C_SIZET) + cnk->value = va_arg (args, ssize_t); + else + cnk->value = va_arg (args, int); + + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->value = cnk->value; + } + break; + + case CNK_OCTAL: + case CNK_UINT: + case CNK_HEX: + if (cnk->cflags == DP_C_SHORT) + cnk->value = va_arg (args, unsigned int); + else if (cnk->cflags == DP_C_LONG) + cnk->value = (unsigned long int)va_arg (args, unsigned long int); + else if (cnk->cflags == DP_C_LLONG) + cnk->value = (LLONG)va_arg (args, unsigned LLONG); + else if (cnk->cflags == DP_C_SIZET) + cnk->value = (size_t)va_arg (args, size_t); + else + cnk->value = (unsigned int)va_arg (args, unsigned int); + + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->value = cnk->value; + } + break; + + case CNK_FLOAT: + if (cnk->cflags == DP_C_LDOUBLE) + cnk->fvalue = va_arg (args, LDOUBLE); + else + cnk->fvalue = va_arg (args, double); + + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->fvalue = cnk->fvalue; + } + break; + + case CNK_CHAR: + cnk->value = va_arg (args, int); + + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->value = cnk->value; + } + break; + + case CNK_STRING: + cnk->strvalue = va_arg (args, char *); + if (!cnk->strvalue) cnk->strvalue = "(NULL)"; + + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->strvalue = cnk->strvalue; + } + break; + + case CNK_PTR: + cnk->strvalue = va_arg (args, void *); + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->strvalue = cnk->strvalue; + } + break; + + case CNK_NUM: + if (cnk->cflags == DP_C_CHAR) + cnk->pnum = va_arg (args, char *); + else if (cnk->cflags == DP_C_SHORT) + cnk->pnum = va_arg (args, short int *); + else if (cnk->cflags == DP_C_LONG) + cnk->pnum = va_arg (args, long int *); + else if (cnk->cflags == DP_C_LLONG) + cnk->pnum = va_arg (args, LLONG *); + else if (cnk->cflags == DP_C_SIZET) + cnk->pnum = va_arg (args, ssize_t *); + else + cnk->pnum = va_arg (args, int *); + + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->pnum = cnk->pnum; + } + break; + + case CNK_PRCNT: + break; + + default: + /* what ?? */ + goto done; + } + } + /* print out the actual string from chunks */ + currlen = 0; + cnk = chunks; + while (cnk) { + int len, min, max; + + if (cnk->min_star) min = cnk->min_star->value; + else min = cnk->min; + if (cnk->max_star) max = cnk->max_star->value; + else max = cnk->max; + + switch (cnk->type) { + + case CNK_FMT_STR: + if (maxlen != 0 && maxlen > currlen) { + if (maxlen > (currlen + cnk->len)) len = cnk->len; + else len = maxlen - currlen; + + memcpy(&(buffer[currlen]), &(base[cnk->start]), len); + } + currlen += cnk->len; + + break; + + case CNK_INT: + case CNK_UINT: + fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags); + break; + + case CNK_OCTAL: + fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags); + break; + + case CNK_HEX: + fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags); + break; + + case CNK_FLOAT: + fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags); + break; + + case CNK_CHAR: + dopr_outch (buffer, &currlen, maxlen, cnk->value); + break; + + case CNK_STRING: + if (max == -1) { + max = strlen(cnk->strvalue); + } + fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max); + break; + + case CNK_PTR: + fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags); + break; + + case CNK_NUM: + if (cnk->cflags == DP_C_CHAR) + *((char *)(cnk->pnum)) = (char)currlen; + else if (cnk->cflags == DP_C_SHORT) + *((short int *)(cnk->pnum)) = (short int)currlen; + else if (cnk->cflags == DP_C_LONG) + *((long int *)(cnk->pnum)) = (long int)currlen; + else if (cnk->cflags == DP_C_LLONG) + *((LLONG *)(cnk->pnum)) = (LLONG)currlen; + else if (cnk->cflags == DP_C_SIZET) + *((ssize_t *)(cnk->pnum)) = (ssize_t)currlen; + else + *((int *)(cnk->pnum)) = (int)currlen; + break; + + case CNK_PRCNT: + dopr_outch (buffer, &currlen, maxlen, '%'); + break; + + default: + /* what ?? */ + goto done; + } + cnk = cnk->next; + } if (maxlen != 0) { if (currlen < maxlen - 1) buffer[currlen] = '\0'; else if (maxlen > 0) buffer[maxlen - 1] = '\0'; } - - return currlen; + ret = currlen; + +done: + va_end(args); + + while (chunks) { + cnk = chunks->next; + free(chunks); + chunks = cnk; + } + if (clist) { + for (pnum = 0; pnum < max_pos; pnum++) { + if (clist[pnum].chunks) free(clist[pnum].chunks); + } + free(clist); + } + return ret; } static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, @@ -427,47 +775,45 @@ static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, value = "<NULL>"; } - for (strln = 0; value[strln]; ++strln); /* strlen */ + for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */ padlen = min - strln; if (padlen < 0) padlen = 0; if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justify */ - - while ((padlen > 0) && (cnt < max)) { + + while (padlen > 0) { dopr_outch (buffer, currlen, maxlen, ' '); --padlen; - ++cnt; } while (*value && (cnt < max)) { dopr_outch (buffer, currlen, maxlen, *value++); ++cnt; } - while ((padlen < 0) && (cnt < max)) { + while (padlen < 0) { dopr_outch (buffer, currlen, maxlen, ' '); ++padlen; - ++cnt; } } /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ static void fmtint(char *buffer, size_t *currlen, size_t maxlen, - long value, int base, int min, int max, int flags) + LLONG value, int base, int min, int max, int flags) { int signvalue = 0; - unsigned long uvalue; - char convert[20]; + unsigned LLONG uvalue; + char convert[22+1]; /* 64-bit value in octal: 22 digits + \0 */ int place = 0; int spadlen = 0; /* amount to space pad */ int zpadlen = 0; /* amount to zero pad */ int caps = 0; - + if (max < 0) max = 0; - + uvalue = value; - + if(!(flags & DP_F_UNSIGNED)) { if( value < 0 ) { signvalue = '-'; @@ -487,8 +833,8 @@ static void fmtint(char *buffer, size_t *currlen, size_t maxlen, (caps? "0123456789ABCDEF":"0123456789abcdef") [uvalue % (unsigned)base ]; uvalue = (uvalue / (unsigned)base ); - } while(uvalue && (place < 20)); - if (place == 20) place--; + } while(uvalue && (place < sizeof(convert))); + if (place == sizeof(convert)) place--; convert[place] = 0; zpadlen = max - place; @@ -542,14 +888,14 @@ static LDOUBLE abs_val(LDOUBLE value) if (value < 0) result = -value; - + return result; } static LDOUBLE POW10(int exp) { LDOUBLE result = 1; - + while (exp) { result *= 10; exp--; @@ -565,7 +911,7 @@ static LLONG ROUND(LDOUBLE value) intpart = (LLONG)value; value = value - intpart; if (value >= 0.5) intpart++; - + return intpart; } @@ -574,7 +920,7 @@ static LLONG ROUND(LDOUBLE value) static double my_modf(double x0, double *iptr) { int i; - long l; + LLONG l=0; double x = x0; double f = 1.0; @@ -617,7 +963,7 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, int padlen = 0; /* amount to pad */ int zpadlen = 0; int caps = 0; - int index; + int idx; double intpart; double fracpart; double temp; @@ -651,11 +997,11 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, #endif /* - * Sorry, we only support 16 digits past the decimal because of our + * Sorry, we only support 9 digits past the decimal because of our * conversion method */ - if (max > 16) - max = 16; + if (max > 9) + max = 9; /* We "cheat" by converting the fractional part to integer by * multiplying by a factor of 10 @@ -665,7 +1011,7 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, my_modf(temp, &intpart); fracpart = ROUND((POW10(max)) * (ufvalue - intpart)); - + if (fracpart >= POW10(max)) { intpart++; fracpart -= POW10(max); @@ -674,14 +1020,13 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, /* Convert integer part */ do { - temp = intpart; - my_modf(intpart*0.1, &intpart); - temp = temp*0.1; - index = (int) ((temp -intpart +0.05)* 10.0); - /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ - /* printf ("%llf, %f, %x\n", temp, intpart, index); */ + temp = intpart*0.1; + my_modf(temp, &intpart); + idx = (int) ((temp -intpart +0.05)* 10.0); + /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ + /* printf ("%llf, %f, %x\n", temp, intpart, idx); */ iconvert[iplace++] = - (caps? "0123456789ABCDEF":"0123456789abcdef")[index]; + (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; } while (intpart && (iplace < 311)); if (iplace == 311) iplace--; iconvert[iplace] = 0; @@ -690,14 +1035,13 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, if (fracpart) { do { - temp = fracpart; - my_modf(fracpart*0.1, &fracpart); - temp = temp*0.1; - index = (int) ((temp -fracpart +0.05)* 10.0); - /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */ - /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */ + temp = fracpart*0.1; + my_modf(temp, &fracpart); + idx = (int) ((temp -fracpart +0.05)* 10.0); + /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */ + /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */ fconvert[fplace++] = - (caps? "0123456789ABCDEF":"0123456789abcdef")[index]; + (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; } while(fracpart && (fplace < 311)); if (fplace == 311) fplace--; } @@ -711,7 +1055,7 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, padlen = 0; if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justifty */ - + if ((flags & DP_F_ZERO) && (padlen > 0)) { if (signvalue) { dopr_outch (buffer, currlen, maxlen, signvalue); @@ -729,7 +1073,7 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, } if (signvalue) dopr_outch (buffer, currlen, maxlen, signvalue); - + while (iplace > 0) dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); @@ -743,15 +1087,15 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, */ if (max > 0) { dopr_outch (buffer, currlen, maxlen, '.'); - + + while (zpadlen > 0) { + dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; + } + while (fplace > 0) dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); } - - while (zpadlen > 0) { - dopr_outch (buffer, currlen, maxlen, '0'); - --zpadlen; - } while (padlen < 0) { dopr_outch (buffer, currlen, maxlen, ' '); @@ -767,24 +1111,99 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) (*currlen)++; } -/* yes this really must be a ||. Don't muck with this (tridge) */ -#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) -int vsnprintf (char *str, size_t count, const char *fmt, va_list args) +static struct pr_chunk *new_chunk(void) { + struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk)); + + if (!new_c) + return NULL; + + new_c->type = 0; + new_c->num = 0; + new_c->min = 0; + new_c->min_star = NULL; + new_c->max = -1; + new_c->max_star = NULL; + new_c->flags = 0; + new_c->cflags = 0; + new_c->start = 0; + new_c->len = 0; + new_c->value = 0; + new_c->fvalue = 0; + new_c->strvalue = NULL; + new_c->pnum = NULL; + new_c->next = NULL; + + return new_c; +} + +static int add_cnk_list_entry(struct pr_chunk_x **list, + int max_num, struct pr_chunk *chunk) { + struct pr_chunk_x *l; + struct pr_chunk **c; + int max; + int cnum; + int i, pos; + + if (chunk->num > max_num) { + max = chunk->num; + + if (*list == NULL) { + l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max); + pos = 0; + } else { + l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max); + pos = max_num; + } + if (l == NULL) { + for (i = 0; i < max; i++) { + if ((*list)[i].chunks) free((*list)[i].chunks); + } + return 0; + } + for (i = pos; i < max; i++) { + l[i].chunks = NULL; + l[i].num = 0; + } + } else { + l = *list; + max = max_num; + } + + i = chunk->num - 1; + cnum = l[i].num + 1; + if (l[i].chunks == NULL) { + c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum); + } else { + c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum); + } + if (c == NULL) { + for (i = 0; i < max; i++) { + if (l[i].chunks) free(l[i].chunks); + } + return 0; + } + c[l[i].num] = chunk; + l[i].chunks = c; + l[i].num = cnum; + + *list = l; + return max; +} + + int rep_vsnprintf (char *str, size_t count, const char *fmt, va_list args) { return dopr(str, count, fmt, args); } #endif -/* yes this really must be a ||. Don't muck wiith this (tridge) +/* yes this really must be a ||. Don't muck with this (tridge) * * The logic for these two is that we need our own definition if the * OS *either* has no definition of *sprintf, or if it does have one - * that doesn't work properly according to the autoconf test. Perhaps - * these should really be smb_snprintf to avoid conflicts with buggy - * linkers? -- mbp + * that doesn't work properly according to the autoconf test. */ -#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_SNPRINTF) -int snprintf(char *str,size_t count,const char *fmt,...) +#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) + int rep_snprintf(char *str,size_t count,const char *fmt,...) { size_t ret; va_list ap; @@ -792,38 +1211,82 @@ int snprintf(char *str,size_t count,const char *fmt,...) va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap); -#ifdef WIN32 - str[count-1] = 0; /* Windows vsnprintf does NOT truncate str. We do it manually. */ + return ret; +} +#endif + +#ifndef HAVE_C99_VSNPRINTF + int rep_printf(const char *fmt, ...) +{ + va_list ap; + int ret; + char *s; + + s = NULL; + va_start(ap, fmt); + ret = vasprintf(&s, fmt, ap); + va_end(ap); + + if (s) { + fwrite(s, 1, strlen(s), stdout); + } + free(s); + + return ret; +} #endif + +#ifndef HAVE_C99_VSNPRINTF + int rep_fprintf(FILE *stream, const char *fmt, ...) +{ + va_list ap; + int ret; + char *s; + + s = NULL; + va_start(ap, fmt); + ret = vasprintf(&s, fmt, ap); + va_end(ap); + + if (s) { + fwrite(s, 1, strlen(s), stream); + } + free(s); + return ret; } #endif #endif -#ifndef HAVE_VASPRINTF -int vasprintf(char **ptr, const char *format, va_list ap) +#if !defined(HAVE_VASPRINTF) || !defined(HAVE_C99_VSNPRINTF) + int rep_vasprintf(char **ptr, const char *format, va_list ap) { int ret; - - ret = vsnprintf(NULL, 0, format, ap); - if (ret <= 0) return ret; + va_list ap2; + + VA_COPY(ap2, ap); + ret = vsnprintf(NULL, 0, format, ap2); + va_end(ap2); + if (ret < 0) return ret; (*ptr) = (char *)malloc(ret+1); if (!*ptr) return -1; - ret = vsnprintf(*ptr, ret+1, format, ap); + + VA_COPY(ap2, ap); + ret = vsnprintf(*ptr, ret+1, format, ap2); + va_end(ap2); return ret; } #endif - -#ifndef HAVE_ASPRINTF -int asprintf(char **ptr, const char *format, ...) +#if !defined(HAVE_ASPRINTF) || !defined(HAVE_C99_VSNPRINTF) + int rep_asprintf(char **ptr, const char *format, ...) { va_list ap; int ret; - + *ptr = NULL; va_start(ap, format); ret = vasprintf(ptr, format, ap); @@ -833,28 +1296,16 @@ int asprintf(char **ptr, const char *format, ...) } #endif -#ifndef HAVE_VSYSLOG -#ifdef HAVE_SYSLOG -void vsyslog (int facility_priority, char *format, va_list arglist) -{ - char *msg = NULL; - vasprintf(&msg, format, arglist); - if (!msg) - return; - syslog(facility_priority, "%s", msg); - SAFE_FREE(msg); -} -#endif /* HAVE_SYSLOG */ -#endif /* HAVE_VSYSLOG */ - #ifdef TEST_SNPRINTF -int sprintf(char *str,const char *fmt,...); + int sprintf(char *str,const char *fmt,...); + int printf(const char *fmt,...); -int main (void) + int main (void) { char buf1[1024]; char buf2[1024]; + char *buf3; char *fp_fmt[] = { "%1.1f", "%-1.5f", @@ -870,11 +1321,13 @@ int main (void) "%3.2f", "%.0f", "%f", - "-16.16f", + "%-8.8f", + "%-9.9f", NULL }; - double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, - 0.9996, 1.996, 4.136, 0}; + double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, + 0.9996, 1.996, 4.136, 5.030201, 0.00205, + /* END LIST */ 0}; char *int_fmt[] = { "%-1.5d", "%1.5d", @@ -888,14 +1341,16 @@ int main (void) "%d", NULL }; - long int_nums[] = { -1, 134, 91340, 341, 0203, 0}; + long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0}; char *str_fmt[] = { - "10.5s", - "5.10s", - "10.1s", - "0.10s", - "10.0s", - "1.10s", + "%10.5s", + "%-10.5s", + "%5.10s", + "%-5.10s", + "%10.1s", + "%0.10s", + "%10.0s", + "%1.10s", "%s", "%.1s", "%.10s", @@ -903,24 +1358,35 @@ int main (void) NULL }; char *str_vals[] = {"hello", "a", "", "a longer string", NULL}; +#ifdef HAVE_LONG_LONG + char *ll_fmt[] = { + "%llu", + NULL + }; + LLONG ll_nums[] = { 134, 91340, 341, 0203, 1234567890, 128006186140000000LL, 0}; +#endif int x, y; int fail = 0; int num = 0; + int l1, l2; + char *ss_fmt[] = { + "%zd", + "%zu", + NULL + }; + size_t ss_nums[] = {134, 91340, 123456789, 0203, 1234567890, 0}; printf ("Testing snprintf format codes against system sprintf...\n"); for (x = 0; fp_fmt[x] ; x++) { for (y = 0; fp_nums[y] != 0 ; y++) { - int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]); - int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); - sprintf (buf2, fp_fmt[x], fp_nums[y]); - if (strcmp (buf1, buf2)) { - printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", - fp_fmt[x], buf1, buf2); - fail++; - } - if (l1 != l2) { - printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]); + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); + l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp (buf1, buf2) || (l1 != l2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + fp_fmt[x], l1, buf1, l2, buf2); fail++; } num++; @@ -929,16 +1395,13 @@ int main (void) for (x = 0; int_fmt[x] ; x++) { for (y = 0; int_nums[y] != 0 ; y++) { - int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]); - int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); - sprintf (buf2, int_fmt[x], int_nums[y]); - if (strcmp (buf1, buf2)) { - printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", - int_fmt[x], buf1, buf2); - fail++; - } - if (l1 != l2) { - printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]); + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); + l2 = sprintf (buf2, int_fmt[x], int_nums[y]); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp (buf1, buf2) || (l1 != l2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + int_fmt[x], l1, buf1, l2, buf2); fail++; } num++; @@ -947,30 +1410,117 @@ int main (void) for (x = 0; str_fmt[x] ; x++) { for (y = 0; str_vals[y] != 0 ; y++) { - int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]); - int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]); - sprintf (buf2, str_fmt[x], str_vals[y]); - if (strcmp (buf1, buf2)) { - printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", - str_fmt[x], buf1, buf2); + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]); + l2 = sprintf (buf2, str_fmt[x], str_vals[y]); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp (buf1, buf2) || (l1 != l2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + str_fmt[x], l1, buf1, l2, buf2); + fail++; + } + num++; + } + } + +#ifdef HAVE_LONG_LONG + for (x = 0; ll_fmt[x] ; x++) { + for (y = 0; ll_nums[y] != 0 ; y++) { + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]); + l2 = sprintf (buf2, ll_fmt[x], ll_nums[y]); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp (buf1, buf2) || (l1 != l2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + ll_fmt[x], l1, buf1, l2, buf2); fail++; } - if (l1 != l2) { - printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]); + num++; + } + } +#endif + +#define BUFSZ 2048 + + buf1[0] = buf2[0] = '\0'; + if ((buf3 = malloc(BUFSZ)) == NULL) { + fail++; + } else { + num++; + memset(buf3, 'a', BUFSZ); + snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3); + buf1[1023] = '\0'; + if (strcmp(buf1, "a") != 0) { + printf("length limit buf1 '%s' expected 'a'\n", buf1); + fail++; + } + } + + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9); + l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp(buf1, buf2) || (l1 != l2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2); + fail++; + } + + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9); + l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp(buf1, buf2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2); + fail++; + } + + for (x = 0; ss_fmt[x] ; x++) { + for (y = 0; ss_nums[y] != 0 ; y++) { + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), ss_fmt[x], ss_nums[y]); + l2 = sprintf (buf2, ss_fmt[x], ss_nums[y]); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp (buf1, buf2) || (l1 != l2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + ss_fmt[x], l1, buf1, l2, buf2); fail++; } num++; } } +#if 0 + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890); + l2 = sprintf(buf2, "%lld", (LLONG)1234567890); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp(buf1, buf2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + "%lld", l1, buf1, l2, buf2); + fail++; + } + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123); + l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp(buf1, buf2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + "%Lf", l1, buf1, l2, buf2); + fail++; + } +#endif printf ("%d tests failed out of %d.\n", fail, num); printf("seeing how many digits we support\n"); { double v0 = 0.12345678901234567890123456789012345678901; for (x=0; x<100; x++) { - snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x)); - sprintf(buf2, "%1.1f", v0*pow(10, x)); + double p = pow(10, x); + double r = v0*p; + snprintf(buf1, sizeof(buf1), "%1.1f", r); + sprintf(buf2, "%1.1f", r); if (strcmp(buf1, buf2)) { printf("we seem to support %d digits\n", x-1); break; @@ -980,4 +1530,4 @@ int main (void) return 0; } -#endif /* SNPRINTF_TEST */ +#endif /* TEST_SNPRINTF */ -- 2.20.1