Commit 888271ed authored by Bruce Momjian's avatar Bruce Momjian

Fix snprintf to handle %$ properly by storing and reordering the

arguments.

Nicolai Tufar
parent 83e87e6f
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
* causing nasty effects. * causing nasty effects.
**************************************************************/ **************************************************************/
/*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.19 2005/03/12 04:00:56 momjian Exp $";*/ /*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.20 2005/03/16 06:00:58 momjian Exp $";*/
int pg_snprintf(char *str, size_t count, const char *fmt,...); int pg_snprintf(char *str, size_t count, const char *fmt,...);
int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args); int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args);
...@@ -151,20 +151,20 @@ static void dopr_outch(int c, char *end, char **output); ...@@ -151,20 +151,20 @@ static void dopr_outch(int c, char *end, char **output);
#define FMTSTR 1 #define FMTSTR 1
#define FMTNUM 2 #define FMTNUM 2
#define FMTFLOAT 3 #define FMTNUM_U 3
#define FMTCHAR 4 #define FMTFLOAT 4
#define FMTCHAR 5
#define FMTWIDTH 6
#define FMTLEN 7
static void static void
dopr(char *buffer, const char *format, va_list args, char *end) dopr(char *buffer, const char *format, va_list args, char *end)
{ {
int ch; int ch;
int64 value;
double fvalue;
int longlongflag = 0; int longlongflag = 0;
int longflag = 0; int longflag = 0;
int pointflag = 0; int pointflag = 0;
int maxwidth = 0; int maxwidth = 0;
char *strvalue;
int ljust; int ljust;
int len; int len;
int zpad; int zpad;
...@@ -173,6 +173,7 @@ dopr(char *buffer, const char *format, va_list args, char *end) ...@@ -173,6 +173,7 @@ dopr(char *buffer, const char *format, va_list args, char *end)
const char* fmtbegin; const char* fmtbegin;
int fmtpos = 1; int fmtpos = 1;
int realpos = 0; int realpos = 0;
int precision;
int position; int position;
char *output; char *output;
int percents = 1; int percents = 1;
...@@ -195,6 +196,8 @@ dopr(char *buffer, const char *format, va_list args, char *end) ...@@ -195,6 +196,8 @@ dopr(char *buffer, const char *format, va_list args, char *end)
int pointflag; int pointflag;
char func; char func;
int realpos; int realpos;
int longflag;
int longlongflag;
} *fmtpar, **fmtparptr; } *fmtpar, **fmtparptr;
/* Create enough structures to hold all arguments */ /* Create enough structures to hold all arguments */
...@@ -229,12 +232,12 @@ dopr(char *buffer, const char *format, va_list args, char *end) ...@@ -229,12 +232,12 @@ dopr(char *buffer, const char *format, va_list args, char *end)
longflag = longlongflag = pointflag = 0; longflag = longlongflag = pointflag = 0;
fmtbegin = format - 1; fmtbegin = format - 1;
realpos = 0; realpos = 0;
position = 0; position = precision = 0;
nextch: nextch:
ch = *format++; ch = *format++;
switch (ch) switch (ch)
{ {
case 0: case '\0':
goto performpr; goto performpr;
case '-': case '-':
ljust = 1; ljust = 1;
...@@ -251,24 +254,29 @@ dopr(char *buffer, const char *format, va_list args, char *end) ...@@ -251,24 +254,29 @@ dopr(char *buffer, const char *format, va_list args, char *end)
case '7': case '7':
case '8': case '8':
case '9': case '9':
if (pointflag) if (!pointflag)
/* could also be precision */
maxwidth = maxwidth * 10 + ch - '0';
else
{ {
len = len * 10 + ch - '0'; len = len * 10 + ch - '0';
position = position * 10 + ch - '0'; position = position * 10 + ch - '0';
} }
else
{
maxwidth = maxwidth * 10 + ch - '0';
precision = precision * 10 + ch - '0';
}
goto nextch; goto nextch;
case '$': case '$':
realpos = position; realpos = position;
len = 0; len = 0;
goto nextch; goto nextch;
case '*': case '*':
if (pointflag) MemSet(&fmtpar[fmtpos], 0, sizeof(fmtpar[fmtpos]));
maxwidth = va_arg(args, int); if (!pointflag)
fmtpar[fmtpos].func = FMTLEN;
else else
len = va_arg(args, int); fmtpar[fmtpos].func = FMTWIDTH;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
goto nextch; goto nextch;
case '.': case '.':
pointflag = 1; pointflag = 1;
...@@ -301,68 +309,40 @@ dopr(char *buffer, const char *format, va_list args, char *end) ...@@ -301,68 +309,40 @@ dopr(char *buffer, const char *format, va_list args, char *end)
#endif #endif
case 'u': case 'u':
case 'U': case 'U':
/* fmtnum(value,base,dosign,ljust,len,zpad,&output) */ fmtpar[fmtpos].longflag = longflag;
if (longflag) fmtpar[fmtpos].longlongflag = longlongflag;
{
if (longlongflag)
value = va_arg(args, uint64);
else
value = va_arg(args, unsigned long);
}
else
value = va_arg(args, unsigned int);
fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
fmtpar[fmtpos].base = 10; fmtpar[fmtpos].base = 10;
fmtpar[fmtpos].dosign = 0; fmtpar[fmtpos].dosign = 0;
fmtpar[fmtpos].ljust = ljust; fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len; fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].zpad = zpad;
fmtpar[fmtpos].func = FMTNUM; fmtpar[fmtpos].func = FMTNUM_U;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos; fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++; fmtpos++;
break; break;
case 'o': case 'o':
case 'O': case 'O':
/* fmtnum(value,base,dosign,ljust,len,zpad,&output) */ fmtpar[fmtpos].longflag = longflag;
if (longflag) fmtpar[fmtpos].longlongflag = longlongflag;
{
if (longlongflag)
value = va_arg(args, uint64);
else
value = va_arg(args, unsigned long);
}
else
value = va_arg(args, unsigned int);
fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
fmtpar[fmtpos].base = 8; fmtpar[fmtpos].base = 8;
fmtpar[fmtpos].dosign = 0; fmtpar[fmtpos].dosign = 0;
fmtpar[fmtpos].ljust = ljust; fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len; fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].zpad = zpad;
fmtpar[fmtpos].func = FMTNUM; fmtpar[fmtpos].func = FMTNUM_U;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos; fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++; fmtpos++;
break; break;
case 'd': case 'd':
case 'D': case 'D':
if (longflag) fmtpar[fmtpos].longflag = longflag;
{ fmtpar[fmtpos].longlongflag = longlongflag;
if (longlongflag)
{
value = va_arg(args, int64);
}
else
value = va_arg(args, long);
}
else
value = va_arg(args, int);
fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
fmtpar[fmtpos].base = 10; fmtpar[fmtpos].base = 10;
fmtpar[fmtpos].dosign = 1; fmtpar[fmtpos].dosign = 1;
fmtpar[fmtpos].ljust = ljust; fmtpar[fmtpos].ljust = ljust;
...@@ -373,72 +353,47 @@ dopr(char *buffer, const char *format, va_list args, char *end) ...@@ -373,72 +353,47 @@ dopr(char *buffer, const char *format, va_list args, char *end)
fmtpos++; fmtpos++;
break; break;
case 'x': case 'x':
if (longflag) fmtpar[fmtpos].longflag = longflag;
{ fmtpar[fmtpos].longlongflag = longlongflag;
if (longlongflag)
value = va_arg(args, uint64);
else
value = va_arg(args, unsigned long);
}
else
value = va_arg(args, unsigned int);
fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
fmtpar[fmtpos].base = 16; fmtpar[fmtpos].base = 16;
fmtpar[fmtpos].dosign = 0; fmtpar[fmtpos].dosign = 0;
fmtpar[fmtpos].ljust = ljust; fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len; fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].zpad = zpad;
fmtpar[fmtpos].func = FMTNUM; fmtpar[fmtpos].func = FMTNUM_U;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos; fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++; fmtpos++;
break; break;
case 'X': case 'X':
if (longflag) fmtpar[fmtpos].longflag = longflag;
{ fmtpar[fmtpos].longlongflag = longlongflag;
if (longlongflag)
value = va_arg(args, uint64);
else
value = va_arg(args, unsigned long);
}
else
value = va_arg(args, unsigned int);
fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
fmtpar[fmtpos].base = -16; fmtpar[fmtpos].base = -16;
fmtpar[fmtpos].dosign = 1; fmtpar[fmtpos].dosign = 1;
fmtpar[fmtpos].ljust = ljust; fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len; fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].zpad = zpad;
fmtpar[fmtpos].func = FMTNUM; fmtpar[fmtpos].func = FMTNUM_U;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos; fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++; fmtpos++;
break; break;
case 's': case 's':
strvalue = va_arg(args, char *); fmtpar[fmtpos].fmtbegin = fmtbegin;
if (maxwidth > 0 || !pointflag) fmtpar[fmtpos].fmtend = format;
{ fmtpar[fmtpos].ljust = ljust;
if (pointflag && len > maxwidth) fmtpar[fmtpos].len = len;
len = maxwidth; /* Adjust padding */ fmtpar[fmtpos].zpad = zpad;
fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].maxwidth = maxwidth;
fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].func = FMTSTR;
fmtpar[fmtpos].value = strvalue; fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpar[fmtpos].ljust = ljust; fmtpos++;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
fmtpar[fmtpos].maxwidth = maxwidth;
fmtpar[fmtpos].func = FMTSTR;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
}
break; break;
case 'c': case 'c':
ch = va_arg(args, int);
fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].charvalue = ch;
fmtpar[fmtpos].func = FMTCHAR; fmtpar[fmtpos].func = FMTCHAR;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos; fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++; fmtpos++;
...@@ -448,15 +403,13 @@ dopr(char *buffer, const char *format, va_list args, char *end) ...@@ -448,15 +403,13 @@ dopr(char *buffer, const char *format, va_list args, char *end)
case 'f': case 'f':
case 'g': case 'g':
case 'G': case 'G':
fvalue = va_arg(args, double);
fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].fvalue = fvalue;
fmtpar[fmtpos].type = ch; fmtpar[fmtpos].type = ch;
fmtpar[fmtpos].ljust = ljust; fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len; fmtpar[fmtpos].len = len;
fmtpar[fmtpos].maxwidth = maxwidth; fmtpar[fmtpos].maxwidth = maxwidth;
fmtpar[fmtpos].precision = position; fmtpar[fmtpos].precision = precision;
fmtpar[fmtpos].pointflag = pointflag; fmtpar[fmtpos].pointflag = pointflag;
fmtpar[fmtpos].func = FMTFLOAT; fmtpar[fmtpos].func = FMTFLOAT;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos; fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
...@@ -473,22 +426,74 @@ dopr(char *buffer, const char *format, va_list args, char *end) ...@@ -473,22 +426,74 @@ dopr(char *buffer, const char *format, va_list args, char *end)
break; break;
} }
} }
performpr: performpr:
/* shuffle pointers */ /* reorder pointers */
for(i = 1; i < fmtpos; i++) for(i = 1; i < fmtpos; i++)
fmtparptr[i] = &fmtpar[fmtpar[i].realpos]; fmtparptr[i] = &fmtpar[fmtpar[i].realpos];
/* assign values */
for(i = 1; i < fmtpos; i++){
switch(fmtparptr[i]->func){
case FMTSTR:
fmtparptr[i]->value = va_arg(args, char *);
break;
case FMTNUM:
if (fmtparptr[i]->longflag)
{
if (fmtparptr[i]->longlongflag)
fmtparptr[i]->numvalue = va_arg(args, int64);
else
fmtparptr[i]->numvalue = va_arg(args, long);
}
else
fmtparptr[i]->numvalue = va_arg(args, int);
break;
case FMTNUM_U:
if (fmtparptr[i]->longflag)
{
if (fmtparptr[i]->longlongflag)
fmtparptr[i]->numvalue = va_arg(args, uint64);
else
fmtparptr[i]->numvalue = va_arg(args, unsigned long);
}
else
fmtparptr[i]->numvalue = va_arg(args, unsigned int);
break;
case FMTFLOAT:
fmtparptr[i]->fvalue = va_arg(args, double);
break;
case FMTCHAR:
fmtparptr[i]->charvalue = va_arg(args, int);
break;
case FMTLEN:
if (i + 1 < fmtpos && fmtpar[i + 1].func != FMTWIDTH)
fmtpar[i + 1].len = va_arg(args, int);
/* For "%*.*f", use the second arg */
if (i + 2 < fmtpos && fmtpar[i + 1].func == FMTWIDTH)
fmtpar[i + 2].len = va_arg(args, int);
break;
case FMTWIDTH:
if (i + 1 < fmtpos)
fmtpar[i + 1].maxwidth = fmtpar[i + 1].precision =
va_arg(args, int);
break;
}
}
/* do the output */
output = buffer; output = buffer;
format = format_save; format = format_save;
while ((ch = *format++)) while ((ch = *format++))
{ {
for(i = 1; i < fmtpos; i++) for(i = 1; i < fmtpos; i++)
{ {
if(ch == '%' && *format == '%') if (ch == '%' && *format == '%')
{ {
format++; format++;
continue; continue;
} }
if(fmtpar[i].fmtbegin == format - 1) if (fmtpar[i].fmtbegin == format - 1)
{ {
switch(fmtparptr[i]->func){ switch(fmtparptr[i]->func){
case FMTSTR: case FMTSTR:
...@@ -497,6 +502,7 @@ performpr: ...@@ -497,6 +502,7 @@ performpr:
fmtparptr[i]->maxwidth, end, &output); fmtparptr[i]->maxwidth, end, &output);
break; break;
case FMTNUM: case FMTNUM:
case FMTNUM_U:
fmtnum(fmtparptr[i]->numvalue, fmtparptr[i]->base, fmtnum(fmtparptr[i]->numvalue, fmtparptr[i]->base,
fmtparptr[i]->dosign, fmtparptr[i]->ljust, fmtparptr[i]->dosign, fmtparptr[i]->ljust,
fmtparptr[i]->len, fmtparptr[i]->zpad, end, &output); fmtparptr[i]->len, fmtparptr[i]->zpad, end, &output);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment