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"); |