summaryrefslogtreecommitdiff
path: root/source4/lib/replace
diff options
context:
space:
mode:
Diffstat (limited to 'source4/lib/replace')
-rw-r--r--source4/lib/replace/snprintf.c898
1 files changed, 672 insertions, 226 deletions
diff --git a/source4/lib/replace/snprintf.c b/source4/lib/replace/snprintf.c
index 67b00b3d84..379e15cf6d 100644
--- a/source4/lib/replace/snprintf.c
+++ b/source4/lib/replace/snprintf.c
@@ -1,4 +1,8 @@
/*
+ * 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 (papowell@astart.com)
* It may be used for any purpose as long as this notice remains intact
@@ -53,23 +57,69 @@
* got rid of fcvt code (twas buggy and made testing harder)
* added C99 semantics
*
- * Darren Tucker (dtucker@zip.com.au)
+ * 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 <ollie.oldham@metro-optix.com> for spotting it.
+ * few mods to make it easier to compile the tests.
+ * addedd the "Ollie" test to the floating point ones.
+ *
+ * Martin Pool (mbp@samba.org) 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 (mbp@samba.org) 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 (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 /* for some tests */
+#ifndef NO_CONFIG_H
#include "config.h"
#else
#define NULL 0
-#endif
+#endif
#ifdef TEST_SNPRINTF /* need math library headers for testing */
-#include <math.h>
-#endif
+
+/* 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 */
#ifdef HAVE_STRING_H
#include <string.h>
@@ -87,23 +137,13 @@
#include <stdlib.h>
#endif
-#ifndef VA_COPY
-#ifdef HAVE_VA_COPY
-#define VA_COPY(dest, src) va_copy(dest, src)
-#elif defined(HAVE___VA_COPY)
-#define VA_COPY(dest, src) __va_copy(dest, src)
-#else
-#define VA_COPY(dest, src) (dest) = (src)
-#endif
-#endif
-
-
#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);
void dummy_snprintf(void) {}
-#else
+#endif /* HAVE_SNPRINTF, etc */
#ifdef HAVE_LONG_DOUBLE
#define LDOUBLE long double
@@ -117,20 +157,16 @@
#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_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,
- 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
@@ -156,69 +192,147 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
#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
+
+/* 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_in)
-{
- char ch;
+/* yes this really must be a ||. Don't muck with this (tridge) */
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+
+struct pr_chunk {
+ 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;
- int min;
- int max;
+ 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 size_t 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,
+ 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);
+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)
+{
+ char ch;
int state;
- int flags;
- int cflags;
+ 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;
+ size_t 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:
@@ -228,13 +342,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;
@@ -248,12 +400,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 {
@@ -263,19 +448,23 @@ 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 'L':
- cflags = DP_C_LDOUBLE;
+ cnk->cflags = DP_C_LDOUBLE;
ch = *format++;
break;
default:
@@ -284,133 +473,64 @@ 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);
- fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
- 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);
- fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+ 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;
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;
@@ -419,14 +539,227 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
break; /* some picky compilers need this */
}
}
+
+ /* retieve 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
+ 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 = (long)va_arg (args, unsigned long int);
+ else if (cnk->cflags == DP_C_LLONG)
+ cnk->value = (LLONG)va_arg (args, unsigned LLONG);
+ else
+ cnk->value = (long)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
+ 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
+ *((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:
+ 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,
@@ -449,19 +782,17 @@ static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
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;
}
}
@@ -632,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;
@@ -666,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
@@ -691,11 +1022,11 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
do {
temp = intpart*0.1;
my_modf(temp, &intpart);
- 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); */
+ 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;
@@ -706,11 +1037,11 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
do {
temp = fracpart*0.1;
my_modf(temp, &fracpart);
- index = (int) ((temp -fracpart +0.05)* 10.0);
- /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
- /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
+ 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--;
}
@@ -780,24 +1111,97 @@ 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 = (struct pr_chunk *)malloc(sizeof(struct pr_chunk));
+
+ if (!new) return NULL;
+
+ new->type = 0;
+ new->num = 0;
+ new->min = 0;
+ new->min_star = NULL;
+ new->max = -1;
+ new->max_star = NULL;
+ new->flags = 0;
+ new->cflags = 0;
+ new->start = 0;
+ new->len = 0;
+ new->value = 0;
+ new->fvalue = 0;
+ new->strvalue = NULL;
+ new->pnum = NULL;
+ new->next = NULL;
+}
+
+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 smb_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
{
return dopr(str, count, fmt, args);
}
+#define vsnprintf smb_vsnprintf
#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 smb_snprintf(char *str,size_t count,const char *fmt,...)
{
size_t ret;
va_list ap;
@@ -807,6 +1211,7 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
va_end(ap);
return ret;
}
+#define snprintf smb_snprintf
#endif
#endif
@@ -873,11 +1278,13 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
"%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, 5.030201, 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",
@@ -891,14 +1298,16 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
"%d",
NULL
};
- long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
+ long int_nums[] = { -1, 134, 91340, 341, 0203, 0, 1234567890};
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",
@@ -909,21 +1318,20 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
int x, y;
int fail = 0;
int num = 0;
+ int l1, l2;
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]);
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
+ 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[1023] = buf1[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++;
@@ -932,16 +1340,14 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
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]);
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
+ 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[1023] = buf1[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++;
@@ -950,16 +1356,14 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
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]);
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
+ 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);
- fail++;
- }
- if (l1 != l2) {
- printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]);
+ buf1[1023] = buf1[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++;
@@ -968,18 +1372,60 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
#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] = buf1[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] = buf1[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++;
+ }
+#if 0
+ buf1[0] = buf2[0] = '\0';
+ l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890);
+ l2 = sprintf(buf2, "%lld", (LLONG)1234567890);
+ buf1[1023] = buf1[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] = buf1[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");
@@ -999,4 +1445,4 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
return 0;
}
-#endif /* SNPRINTF_TEST */
+#endif /* TEST_SNPRINTF */