mirror of
https://github.com/postgres/postgres.git
synced 2025-07-12 21:01:52 +03:00
Fix snprintf to handle %$ properly by storing and reordering the
arguments. Nicolai Tufar
This commit is contained in:
@ -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);
|
|||||||
|
|
||||||
#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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
#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)
|
|||||||
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 *);
|
|
||||||
if (maxwidth > 0 || !pointflag)
|
|
||||||
{
|
|
||||||
if (pointflag && len > maxwidth)
|
|
||||||
len = maxwidth; /* Adjust padding */
|
|
||||||
fmtpar[fmtpos].fmtbegin = fmtbegin;
|
|
||||||
fmtpar[fmtpos].fmtend = format;
|
|
||||||
fmtpar[fmtpos].value = strvalue;
|
|
||||||
fmtpar[fmtpos].ljust = ljust;
|
|
||||||
fmtpar[fmtpos].len = len;
|
|
||||||
fmtpar[fmtpos].zpad = zpad;
|
|
||||||
fmtpar[fmtpos].maxwidth = maxwidth;
|
|
||||||
fmtpar[fmtpos].func = FMTSTR;
|
|
||||||
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
|
|
||||||
fmtpos++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
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].ljust = ljust;
|
||||||
|
fmtpar[fmtpos].len = len;
|
||||||
|
fmtpar[fmtpos].zpad = zpad;
|
||||||
|
fmtpar[fmtpos].maxwidth = maxwidth;
|
||||||
|
fmtpar[fmtpos].func = FMTSTR;
|
||||||
|
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
|
||||||
|
fmtpos++;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
fmtpar[fmtpos].fmtbegin = fmtbegin;
|
||||||
|
fmtpar[fmtpos].fmtend = format;
|
||||||
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)
|
|||||||
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)
|
|||||||
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:
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user