summaryrefslogtreecommitdiff
path: root/source3/lib
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2006-02-07 00:50:38 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:06:27 -0500
commit0b09d4b2f650e23f79e93433de4c1795c9382795 (patch)
treef88c94d419d318fe24d3bcfbdd07e0205c3e0776 /source3/lib
parentde0337163fb592fba424bb6e916e539948ef37fd (diff)
downloadsamba-0b09d4b2f650e23f79e93433de4c1795c9382795.tar.gz
samba-0b09d4b2f650e23f79e93433de4c1795c9382795.tar.bz2
samba-0b09d4b2f650e23f79e93433de4c1795c9382795.zip
r13374: new revision of the snprintf replace code
still missing a configure test to make us substitute our snprintf to system one when the system one does not have positional parameters support (This used to be commit e9bcc24b13c0e264d1d4aaf31a56e38cb3fec830)
Diffstat (limited to 'source3/lib')
-rw-r--r--source3/lib/snprintf.c756
1 files changed, 580 insertions, 176 deletions
diff --git a/source3/lib/snprintf.c b/source3/lib/snprintf.c
index a3e4b06d47..379e15cf6d 100644
--- a/source3/lib/snprintf.c
+++ b/source3/lib/snprintf.c
@@ -90,11 +90,17 @@
* 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)
+ * 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
@@ -186,10 +192,24 @@
#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
@@ -199,6 +219,29 @@
/* 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;
+ 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,
@@ -208,60 +251,88 @@ static void fmtint(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);
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;
- LLONG value;
- LDOUBLE fvalue;
- char *strvalue;
- int min;
- int max;
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:
@@ -271,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;
@@ -291,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 {
@@ -306,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:
@@ -327,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;
@@ -462,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,
@@ -492,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;
}
}
@@ -709,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
@@ -823,6 +1111,82 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
(*currlen)++;
}
+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);
@@ -914,7 +1278,8 @@ int smb_snprintf(char *str,size_t count,const char *fmt,...)
"%3.2f",
"%.0f",
"%f",
- "-16.16f",
+ "%-8.8f",
+ "%-9.9f",
NULL
};
double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996,
@@ -933,14 +1298,16 @@ int smb_snprintf(char *str,size_t count,const char *fmt,...)
"%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",
@@ -951,21 +1318,20 @@ int smb_snprintf(char *str,size_t count,const char *fmt,...)
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++;
@@ -974,16 +1340,14 @@ int smb_snprintf(char *str,size_t count,const char *fmt,...)
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++;
@@ -992,16 +1356,14 @@ int smb_snprintf(char *str,size_t count,const char *fmt,...)
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++;
@@ -1010,18 +1372,60 @@ int smb_snprintf(char *str,size_t count,const char *fmt,...)
#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");