|
version 1.1, 2012/02/17 15:09:30
|
version 1.1.1.2, 2013/10/14 07:51:14
|
|
Line 37
|
Line 37
|
| * which showed it, so that's been fixed. Also, formated the code |
* which showed it, so that's been fixed. Also, formated the code |
| * to mutt conventions, and removed dead code left over from the |
* to mutt conventions, and removed dead code left over from the |
| * original. Also, there is now a builtin-test, just compile with: |
* original. Also, there is now a builtin-test, just compile with: |
| * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm | * gcc -I.. -DTEST_SNPRINTF -o snprintf snprintf.c -lm |
| * and run snprintf for results. |
* and run snprintf for results. |
| * |
* |
| * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i |
* Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i |
|
Line 89
|
Line 89
|
| * |
* |
| * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even |
* Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even |
| * if the C library has some snprintf functions already. |
* if the C library has some snprintf functions already. |
| |
* |
| |
* Darren Tucker (dtucker@zip.com.au) 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 (idra@samba.org) Jan 2006 |
| |
* |
| |
* Add support for position independent parameters |
| |
* fix fmtstr now it conforms to sprintf wrt min.max |
| |
* |
| **************************************************************/ |
**************************************************************/ |
| |
|
| #ifndef NO_CONFIG_H |
|
| #include "config.h" |
#include "config.h" |
| #else |
|
| #define NULL 0 |
|
| #endif |
|
| |
|
| #ifdef TEST_SNPRINTF /* need math library headers for testing */ |
#ifdef TEST_SNPRINTF /* need math library headers for testing */ |
| |
|
|
Line 133
|
Line 141
|
| void dummy_snprintf(void) {} |
void dummy_snprintf(void) {} |
| #endif /* HAVE_SNPRINTF, etc */ |
#endif /* HAVE_SNPRINTF, etc */ |
| |
|
| |
#ifdef STDC_HEADERS |
| |
#include <stddef.h> |
| |
#endif |
| |
|
| #ifdef HAVE_LONG_DOUBLE |
#ifdef HAVE_LONG_DOUBLE |
| #define LDOUBLE long double |
#define LDOUBLE long double |
| #else |
#else |
| #define LDOUBLE double |
#define LDOUBLE double |
| #endif |
#endif |
| |
|
| #if SIZEOF_LONG_LONG | #if !defined HAVE_LONG_LONG && SIZEOF_LONG_LONG |
| | #define HAVE_LONG_LONG 1 |
| | #endif |
| | #ifdef HAVE_LONG_LONG |
| #define LLONG long long |
#define LLONG long long |
| #else |
#else |
| #define LLONG long |
#define LLONG long |
|
Line 155
|
Line 170
|
| #define VA_COPY(dest, src) (dest) = (src) |
#define VA_COPY(dest, src) (dest) = (src) |
| #endif |
#endif |
| #endif |
#endif |
| |
#endif |
| |
|
| |
/* yes this really must be a ||. Don't muck with this (tridge) */ |
| |
#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) |
| |
|
| /* |
/* |
| * dopr(): poor man's version of doprintf |
* dopr(): poor man's version of doprintf |
| */ |
*/ |
|
Line 180
|
Line 199
|
| #define DP_F_UNSIGNED (1 << 6) |
#define DP_F_UNSIGNED (1 << 6) |
| |
|
| /* Conversion Flags */ |
/* Conversion Flags */ |
| #define DP_C_SHORT 1 | #define DP_C_CHAR 1 |
| #define DP_C_LONG 2 | #define DP_C_SHORT 2 |
| #define DP_C_LDOUBLE 3 | #define DP_C_LONG 3 |
| #define DP_C_LLONG 4 | #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') |
#define char_to_int(p) ((p)- '0') |
| #ifndef MAX |
#ifndef MAX |
| #define MAX(p,q) (((p) >= (q)) ? (p) : (q)) |
#define MAX(p,q) (((p) >= (q)) ? (p) : (q)) |
| #endif |
#endif |
| |
|
| /* yes this really must be a ||. Don't muck with this (tridge) */ | struct pr_chunk { |
| #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) | int type; /* chunk type */ |
| | int num; /* parameter number */ |
| | int min; |
| | int max; |
| | 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; |
| | }; |
| |
|
| static size_t dopr(char *buffer, size_t maxlen, const char *format, | 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); |
va_list args_in); |
| static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, |
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, |
| char *value, int flags, int min, int max); |
char *value, int flags, int min, int max); |
| static void fmtint(char *buffer, size_t *currlen, size_t maxlen, |
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); |
| static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, |
static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, |
| LDOUBLE fvalue, int min, int max, int flags); |
LDOUBLE fvalue, int min, int max, int flags); |
| static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); |
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 size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) | static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) |
| { |
{ |
| char ch; |
char ch; |
| LLONG value; |
|
| LDOUBLE fvalue; |
|
| char *strvalue; |
|
| int min; |
|
| int max; |
|
| int state; |
int state; |
| int flags; | int pflag; |
| int cflags; | int pnum; |
| | int pfirst; |
| size_t currlen; |
size_t currlen; |
| va_list args; |
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); |
VA_COPY(args, args_in); |
| | |
| state = DP_S_DEFAULT; |
state = DP_S_DEFAULT; |
| currlen = flags = cflags = min = 0; | pfirst = 1; |
| max = -1; | pflag = 0; |
| | pnum = 0; |
| | |
| | max_pos = 0; |
| | base = format; |
| ch = *format++; |
ch = *format++; |
| |
|
| |
/* retrieve the string structure as chunks */ |
| while (state != DP_S_DONE) { |
while (state != DP_S_DONE) { |
| if (ch == '\0') |
if (ch == '\0') |
| state = DP_S_DONE; |
state = DP_S_DONE; |
| |
|
| switch(state) { |
switch(state) { |
| case DP_S_DEFAULT: |
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; |
state = DP_S_FLAGS; |
| else | ch = *format++; |
| dopr_outch (buffer, &currlen, maxlen, ch); | } else { |
| ch = *format++; | cnk->type = CNK_FMT_STR; |
| | cnk->start = format - base -1; |
| | while ((ch != '\0') && (ch != '%')) ch = *format++; |
| | cnk->len = format - base - cnk->start -1; |
| | } |
| break; |
break; |
| case DP_S_FLAGS: |
case DP_S_FLAGS: |
| switch (ch) { |
switch (ch) { |
| case '-': |
case '-': |
| flags |= DP_F_MINUS; | cnk->flags |= DP_F_MINUS; |
| ch = *format++; |
ch = *format++; |
| break; |
break; |
| case '+': |
case '+': |
| flags |= DP_F_PLUS; | cnk->flags |= DP_F_PLUS; |
| ch = *format++; |
ch = *format++; |
| break; |
break; |
| case ' ': |
case ' ': |
| flags |= DP_F_SPACE; | cnk->flags |= DP_F_SPACE; |
| ch = *format++; |
ch = *format++; |
| break; |
break; |
| case '#': |
case '#': |
| flags |= DP_F_NUM; | cnk->flags |= DP_F_NUM; |
| ch = *format++; |
ch = *format++; |
| break; |
break; |
| case '0': |
case '0': |
| flags |= DP_F_ZERO; | cnk->flags |= DP_F_ZERO; |
| ch = *format++; |
ch = *format++; |
| break; |
break; |
| |
case 'I': |
| |
/* internationalization not supported yet */ |
| |
ch = *format++; |
| |
break; |
| default: |
default: |
| state = DP_S_MIN; |
state = DP_S_MIN; |
| break; |
break; |
|
Line 265 static size_t dopr(char *buffer, size_t maxlen, const
|
Line 347 static size_t dopr(char *buffer, size_t maxlen, const
|
| break; |
break; |
| case DP_S_MIN: |
case DP_S_MIN: |
| if (isdigit((unsigned char)ch)) { |
if (isdigit((unsigned char)ch)) { |
| min = 10*min + char_to_int (ch); | cnk->min = 10 * cnk->min + char_to_int (ch); |
| ch = *format++; |
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 == '*') { |
} 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++; |
ch = *format++; |
| state = DP_S_DOT; |
state = DP_S_DOT; |
| } else { |
} else { |
| |
if (pfirst) pfirst = 0; |
| state = DP_S_DOT; |
state = DP_S_DOT; |
| } |
} |
| break; |
break; |
|
Line 285 static size_t dopr(char *buffer, size_t maxlen, const
|
Line 405 static size_t dopr(char *buffer, size_t maxlen, const
|
| break; |
break; |
| case DP_S_MAX: |
case DP_S_MAX: |
| if (isdigit((unsigned char)ch)) { |
if (isdigit((unsigned char)ch)) { |
| if (max < 0) | if (cnk->max < 0) |
| max = 0; | cnk->max = 0; |
| max = 10*max + char_to_int (ch); | cnk->max = 10 * cnk->max + char_to_int (ch); |
| ch = *format++; |
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 == '*') { |
} 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++; |
ch = *format++; |
| state = DP_S_MOD; |
state = DP_S_MOD; |
| } else { |
} else { |
|
Line 300 static size_t dopr(char *buffer, size_t maxlen, const
|
Line 453 static size_t dopr(char *buffer, size_t maxlen, const
|
| case DP_S_MOD: |
case DP_S_MOD: |
| switch (ch) { |
switch (ch) { |
| case 'h': |
case 'h': |
| cflags = DP_C_SHORT; | cnk->cflags = DP_C_SHORT; |
| ch = *format++; |
ch = *format++; |
| |
if (ch == 'h') { |
| |
cnk->cflags = DP_C_CHAR; |
| |
ch = *format++; |
| |
} |
| break; |
break; |
| case 'l': |
case 'l': |
| cflags = DP_C_LONG; | cnk->cflags = DP_C_LONG; |
| ch = *format++; |
ch = *format++; |
| if (ch == 'l') { /* It's a long long */ |
if (ch == 'l') { /* It's a long long */ |
| cflags = DP_C_LLONG; | cnk->cflags = DP_C_LLONG; |
| ch = *format++; |
ch = *format++; |
| } |
} |
| break; |
break; |
| case 'L': |
case 'L': |
| cflags = DP_C_LDOUBLE; | cnk->cflags = DP_C_LDOUBLE; |
| ch = *format++; |
ch = *format++; |
| break; |
break; |
| |
case 'z': |
| |
cnk->cflags = DP_C_SIZET; |
| |
ch = *format++; |
| |
break; |
| default: |
default: |
| break; |
break; |
| } |
} |
| state = DP_S_CONV; |
state = DP_S_CONV; |
| break; |
break; |
| case DP_S_CONV: |
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) { |
switch (ch) { |
| case 'd': |
case 'd': |
| case 'i': |
case 'i': |
| if (cflags == DP_C_SHORT) | cnk->type = CNK_INT; |
| 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); | |
| break; |
break; |
| case 'o': |
case 'o': |
| flags |= DP_F_UNSIGNED; | cnk->type = CNK_OCTAL; |
| if (cflags == DP_C_SHORT) | cnk->flags |= DP_F_UNSIGNED; |
| 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); | |
| break; |
break; |
| case 'u': |
case 'u': |
| flags |= DP_F_UNSIGNED; | cnk->type = CNK_UINT; |
| if (cflags == DP_C_SHORT) | cnk->flags |= DP_F_UNSIGNED; |
| 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); | |
| break; |
break; |
| case 'X': |
case 'X': |
| flags |= DP_F_UP; | cnk->flags |= DP_F_UP; |
| case 'x': |
case 'x': |
| flags |= DP_F_UNSIGNED; | cnk->type = CNK_HEX; |
| if (cflags == DP_C_SHORT) | cnk->flags |= DP_F_UNSIGNED; |
| 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; |
break; |
| case 'f': | case 'A': |
| if (cflags == DP_C_LDOUBLE) | /* hex float not supported yet */ |
| fvalue = va_arg (args, LDOUBLE); | |
| else | |
| fvalue = va_arg (args, double); | |
| /* um, floating point? */ | |
| fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); | |
| break; | |
| case 'E': |
case 'E': |
| flags |= DP_F_UP; |
|
| case 'e': |
|
| if (cflags == DP_C_LDOUBLE) |
|
| fvalue = va_arg (args, LDOUBLE); |
|
| else |
|
| fvalue = va_arg (args, double); |
|
| fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); |
|
| break; |
|
| case 'G': |
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': |
case 'g': |
| if (cflags == DP_C_LDOUBLE) | cnk->type = CNK_FLOAT; |
| fvalue = va_arg (args, LDOUBLE); | |
| else | |
| fvalue = va_arg (args, double); | |
| fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); | |
| break; |
break; |
| case 'c': |
case 'c': |
| dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); | cnk->type = CNK_CHAR; |
| break; |
break; |
| case 's': |
case 's': |
| strvalue = va_arg (args, char *); | cnk->type = CNK_STRING; |
| 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); | |
| break; |
break; |
| case 'p': |
case 'p': |
| strvalue = va_arg (args, void *); | cnk->type = CNK_PTR; |
| fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); | cnk->flags |= DP_F_UNSIGNED; |
| break; |
break; |
| case 'n': |
case 'n': |
| if (cflags == DP_C_SHORT) { | cnk->type = CNK_NUM; |
| 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; | |
| } | |
| break; |
break; |
| case '%': |
case '%': |
| dopr_outch (buffer, &currlen, maxlen, ch); | cnk->type = CNK_PRCNT; |
| break; |
break; |
| case 'w': |
|
| /* not supported yet, treat as next char */ |
|
| ch = *format++; |
|
| break; |
|
| default: |
default: |
| /* Unknown, skip */ | /* Unknown, bail out*/ |
| break; | goto done; |
| } |
} |
| ch = *format++; |
ch = *format++; |
| state = DP_S_DEFAULT; |
state = DP_S_DEFAULT; |
| flags = cflags = min = 0; |
|
| max = -1; |
|
| break; |
break; |
| case DP_S_DONE: |
case DP_S_DONE: |
| break; |
break; |
|
Line 456 static size_t dopr(char *buffer, size_t maxlen, const
|
Line 549 static size_t dopr(char *buffer, size_t maxlen, const
|
| break; /* some picky compilers need this */ |
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 (maxlen != 0) { |
| if (currlen < maxlen - 1) |
if (currlen < maxlen - 1) |
| buffer[currlen] = '\0'; |
buffer[currlen] = '\0'; |
| else if (maxlen > 0) |
else if (maxlen > 0) |
| buffer[maxlen - 1] = '\0'; |
buffer[maxlen - 1] = '\0'; |
| } |
} |
| | ret = currlen; |
| return 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, |
static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, |
|
Line 479 static void fmtstr(char *buffer, size_t *currlen, size
|
Line 795 static void fmtstr(char *buffer, size_t *currlen, size
|
| value = "<NULL>"; |
value = "<NULL>"; |
| } |
} |
| |
|
| for (strln = 0; value[strln]; ++strln); /* strlen */ | for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */ |
| padlen = min - strln; |
padlen = min - strln; |
| if (padlen < 0) |
if (padlen < 0) |
| padlen = 0; |
padlen = 0; |
| if (flags & DP_F_MINUS) |
if (flags & DP_F_MINUS) |
| padlen = -padlen; /* Left Justify */ |
padlen = -padlen; /* Left Justify */ |
| |
|
| while ((padlen > 0) && (cnt < max)) { | while (padlen > 0) { |
| dopr_outch (buffer, currlen, maxlen, ' '); |
dopr_outch (buffer, currlen, maxlen, ' '); |
| --padlen; |
--padlen; |
| ++cnt; |
|
| } |
} |
| while (*value && (cnt < max)) { |
while (*value && (cnt < max)) { |
| dopr_outch (buffer, currlen, maxlen, *value++); |
dopr_outch (buffer, currlen, maxlen, *value++); |
| ++cnt; |
++cnt; |
| } |
} |
| while ((padlen < 0) && (cnt < max)) { | while (padlen < 0) { |
| dopr_outch (buffer, currlen, maxlen, ' '); |
dopr_outch (buffer, currlen, maxlen, ' '); |
| ++padlen; |
++padlen; |
| ++cnt; |
|
| } |
} |
| } |
} |
| |
|
| /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ |
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ |
| |
|
| static void fmtint(char *buffer, size_t *currlen, size_t maxlen, |
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; |
int signvalue = 0; |
| unsigned long uvalue; | unsigned LLONG uvalue; |
| char convert[20]; |
char convert[20]; |
| int place = 0; |
int place = 0; |
| int spadlen = 0; /* amount to space pad */ |
int spadlen = 0; /* amount to space pad */ |
|
Line 626 static LLONG ROUND(LDOUBLE value)
|
Line 940 static LLONG ROUND(LDOUBLE value)
|
| static double my_modf(double x0, double *iptr) |
static double my_modf(double x0, double *iptr) |
| { |
{ |
| int i; |
int i; |
| long l; | LLONG l=0; |
| double x = x0; |
double x = x0; |
| double f = 1.0; |
double f = 1.0; |
| |
|
| for (i=0;i<100;i++) { |
for (i=0;i<100;i++) { |
| l = (long)x; |
l = (long)x; |
| if (l <= (x+1) && l >= (x-1)) { | if (l <= (x+1) && l >= (x-1)) break; |
| if (i != 0) { | |
| double i2; | |
| double ret; | |
| |
| ret = my_modf(x0-l*f, &i2); | |
| (*iptr) = l*f + i2; | |
| return ret; | |
| } | |
| |
| (*iptr) = l; | |
| return x - (*iptr); | |
| } | |
| x *= 0.1; |
x *= 0.1; |
| f *= 10.0; |
f *= 10.0; |
| } |
} |
| |
|
| /* yikes! the number is beyond what we can handle. What do we do? */ | if (i == 100) { |
| (*iptr) = 0; | /* yikes! the number is beyond what we can handle. What do we do? */ |
| return 0; | (*iptr) = 0; |
| | return 0; |
| | } |
| | |
| | if (i != 0) { |
| | double i2; |
| | double ret; |
| | |
| | ret = my_modf(x0-l*f, &i2); |
| | (*iptr) = l*f + i2; |
| | return ret; |
| | } |
| | |
| | (*iptr) = l; |
| | return x - (*iptr); |
| } |
} |
| |
|
| |
|
|
Line 701 static void fmtfp (char *buffer, size_t *currlen, size
|
Line 1017 static void fmtfp (char *buffer, size_t *currlen, size
|
| #endif |
#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 |
* conversion method |
| */ |
*/ |
| if (max > 16) | if (max > 9) |
| max = 16; | max = 9; |
| |
|
| /* We "cheat" by converting the fractional part to integer by |
/* We "cheat" by converting the fractional part to integer by |
| * multiplying by a factor of 10 |
* multiplying by a factor of 10 |
|
Line 815 static void dopr_outch(char *buffer, size_t *currlen,
|
Line 1131 static void dopr_outch(char *buffer, size_t *currlen,
|
| (*currlen)++; |
(*currlen)++; |
| } |
} |
| |
|
| |
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 rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args) |
int rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args) |
| { |
{ |
| return dopr(str, count, fmt, args); |
return dopr(str, count, fmt, args); |
|
Line 842 int rsync_snprintf(char *str,size_t count,const char *
|
Line 1237 int rsync_snprintf(char *str,size_t count,const char *
|
| #define snprintf rsync_snprintf |
#define snprintf rsync_snprintf |
| #endif |
#endif |
| |
|
| #endif |
|
| |
|
| #ifndef HAVE_VASPRINTF |
#ifndef HAVE_VASPRINTF |
| int vasprintf(char **ptr, const char *format, va_list ap) |
int vasprintf(char **ptr, const char *format, va_list ap) |
| { |
{ |
|
Line 851 int rsync_snprintf(char *str,size_t count,const char *
|
Line 1244 int rsync_snprintf(char *str,size_t count,const char *
|
| va_list ap2; |
va_list ap2; |
| |
|
| VA_COPY(ap2, ap); |
VA_COPY(ap2, ap); |
| |
|
| ret = vsnprintf(NULL, 0, format, ap2); |
ret = vsnprintf(NULL, 0, format, ap2); |
| if (ret <= 0) return ret; | va_end(ap2); |
| | if (ret < 0) return ret; |
| |
|
| (*ptr) = (char *)malloc(ret+1); |
(*ptr) = (char *)malloc(ret+1); |
| if (!*ptr) return -1; |
if (!*ptr) return -1; |
| |
|
| VA_COPY(ap2, ap); |
VA_COPY(ap2, ap); |
| |
|
| ret = vsnprintf(*ptr, ret+1, format, ap2); |
ret = vsnprintf(*ptr, ret+1, format, ap2); |
| |
va_end(ap2); |
| |
|
| return ret; |
return ret; |
| } |
} |
|
Line 885 int rsync_snprintf(char *str,size_t count,const char *
|
Line 1278 int rsync_snprintf(char *str,size_t count,const char *
|
| #ifdef TEST_SNPRINTF |
#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 buf1[1024]; |
| char buf2[1024]; |
char buf2[1024]; |
| |
char *buf3; |
| char *fp_fmt[] = { |
char *fp_fmt[] = { |
| "%1.1f", |
"%1.1f", |
| "%-1.5f", |
"%-1.5f", |
|
Line 905 int rsync_snprintf(char *str,size_t count,const char *
|
Line 1300 int rsync_snprintf(char *str,size_t count,const char *
|
| "%3.2f", |
"%3.2f", |
| "%.0f", |
"%.0f", |
| "%f", |
"%f", |
| "-16.16f", | "%-8.8f", |
| | "%-9.9f", |
| NULL |
NULL |
| }; |
}; |
| double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, |
double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, |
|
Line 924 int rsync_snprintf(char *str,size_t count,const char *
|
Line 1320 int rsync_snprintf(char *str,size_t count,const char *
|
| "%d", |
"%d", |
| NULL |
NULL |
| }; |
}; |
| long int_nums[] = { -1, 134, 91340, 341, 0203, 0}; | long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0}; |
| char *str_fmt[] = { |
char *str_fmt[] = { |
| "10.5s", | "%10.5s", |
| "5.10s", | "%-10.5s", |
| "10.1s", | "%5.10s", |
| "0.10s", | "%-5.10s", |
| "10.0s", | "%10.1s", |
| "1.10s", | "%0.10s", |
| | "%10.0s", |
| | "%1.10s", |
| "%s", |
"%s", |
| "%.1s", |
"%.1s", |
| "%.10s", |
"%.10s", |
|
Line 939 int rsync_snprintf(char *str,size_t count,const char *
|
Line 1337 int rsync_snprintf(char *str,size_t count,const char *
|
| NULL |
NULL |
| }; |
}; |
| char *str_vals[] = {"hello", "a", "", "a longer string", 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 x, y; |
| int fail = 0; |
int fail = 0; |
| int num = 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"); |
printf ("Testing snprintf format codes against system sprintf...\n"); |
| |
|
| for (x = 0; fp_fmt[x] ; x++) { |
for (x = 0; fp_fmt[x] ; x++) { |
| for (y = 0; fp_nums[y] != 0 ; y++) { |
for (y = 0; fp_nums[y] != 0 ; y++) { |
| int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]); | buf1[0] = buf2[0] = '\0'; |
| int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); | l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); |
| sprintf (buf2, fp_fmt[x], fp_nums[y]); | l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]); |
| if (strcmp (buf1, buf2)) { | buf1[1023] = buf2[1023] = '\0'; |
| printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", | if (strcmp (buf1, buf2) || (l1 != l2)) { |
| fp_fmt[x], buf1, buf2); | 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++; |
fail++; |
| } |
} |
| if (l1 != l2) { |
|
| printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]); |
|
| fail++; |
|
| } |
|
| num++; |
num++; |
| } |
} |
| } |
} |
| |
|
| for (x = 0; int_fmt[x] ; x++) { |
for (x = 0; int_fmt[x] ; x++) { |
| for (y = 0; int_nums[y] != 0 ; y++) { |
for (y = 0; int_nums[y] != 0 ; y++) { |
| int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]); | buf1[0] = buf2[0] = '\0'; |
| int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); | l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); |
| sprintf (buf2, int_fmt[x], int_nums[y]); | l2 = sprintf (buf2, int_fmt[x], int_nums[y]); |
| if (strcmp (buf1, buf2)) { | buf1[1023] = buf2[1023] = '\0'; |
| printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", | if (strcmp (buf1, buf2) || (l1 != l2)) { |
| int_fmt[x], buf1, buf2); | 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++; |
fail++; |
| } |
} |
| if (l1 != l2) { |
|
| printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]); |
|
| fail++; |
|
| } |
|
| num++; |
num++; |
| } |
} |
| } |
} |
| |
|
| for (x = 0; str_fmt[x] ; x++) { |
for (x = 0; str_fmt[x] ; x++) { |
| for (y = 0; str_vals[y] != 0 ; y++) { |
for (y = 0; str_vals[y] != 0 ; y++) { |
| int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]); | buf1[0] = buf2[0] = '\0'; |
| int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]); | l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]); |
| sprintf (buf2, str_fmt[x], str_vals[y]); | l2 = sprintf (buf2, str_fmt[x], str_vals[y]); |
| if (strcmp (buf1, buf2)) { | buf1[1023] = buf2[1023] = '\0'; |
| printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", | if (strcmp (buf1, buf2) || (l1 != l2)) { |
| str_fmt[x], buf1, buf2); | 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++; |
fail++; |
| } |
} |
| if (l1 != l2) { | num++; |
| printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]); | } |
| | } |
| | |
| | #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++; |
fail++; |
| } |
} |
| num++; |
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 ("%d tests failed out of %d.\n", fail, num); |
| |
|
| printf("seeing how many digits we support\n"); |
printf("seeing how many digits we support\n"); |