Commit b4feafb6 authored by Bruce Momjian's avatar Bruce Momjian

Add support to port/snprintf.c for position parameter specification:

+ # Determine if printf supports %1$ argument selection, e.g. %5$ selects
+ # the fifth argument after the printf print string.
+ # This is not in the C99 standard, but in the Single Unix Specification (SUS).
+ # It is used in our langauge translation strings.

Nicolai Tufar with configure changes by Bruce.
parent 78bb800b
# Macros that test various C library quirks # Macros that test various C library quirks
# $PostgreSQL: pgsql/config/c-library.m4,v 1.29 2004/12/16 17:48:26 momjian Exp $ # $PostgreSQL: pgsql/config/c-library.m4,v 1.30 2005/02/22 03:55:50 momjian Exp $
# PGAC_VAR_INT_TIMEZONE # PGAC_VAR_INT_TIMEZONE
...@@ -266,3 +266,36 @@ case $pgac_cv_snprintf_long_long_int_format in ...@@ -266,3 +266,36 @@ case $pgac_cv_snprintf_long_long_int_format in
LONG_LONG_INT_FORMAT=$pgac_cv_snprintf_long_long_int_format;; LONG_LONG_INT_FORMAT=$pgac_cv_snprintf_long_long_int_format;;
*) AC_MSG_RESULT(none);; *) AC_MSG_RESULT(none);;
esac])# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT esac])# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT
# PGAC_FUNC_PRINTF_ARG_CONTROL
# ---------------------------------------
# Determine if printf supports %1$ argument selection, e.g. %5$ selects
# the fifth argument after the printf print string.
# This is not in the C99 standard, but in the Single Unix Specification (SUS).
# It is used in our langauge translation strings.
#
AC_DEFUN([PGAC_FUNC_PRINTF_ARG_CONTROL],
[AC_MSG_CHECKING([printf supports argument control])
AC_CACHE_VAL(pgac_cv_printf_arg_control,
[AC_TRY_RUN([#include <stdio.h>
int does_printf_have_arg_control()
{
char buf[100];
/* can it swap arguments? */
snprintf(buf, 100, "%2$d|%1$d", 3, 4);
if (strcmp(buf, "4|3") != 0)
return 0;
return 1;
}
main() {
exit(! does_printf_have_arg_control());
}],
[pgac_cv_printf_arg_control=yes],
[pgac_cv_printf_arg_control=no],
[pgac_cv_printf_arg_control=cross])
])dnl AC_CACHE_VAL
AC_MSG_RESULT([$pgac_cv_printf_arg_control])
])# PGAC_FUNC_PRINTF_ARG_CONTROL
...@@ -12162,6 +12162,63 @@ fi ...@@ -12162,6 +12162,63 @@ fi
done done
echo "$as_me:$LINENO: checking printf supports argument control" >&5
echo $ECHO_N "checking printf supports argument control... $ECHO_C" >&6
if test "${pgac_cv_printf_arg_control+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test "$cross_compiling" = yes; then
pgac_cv_printf_arg_control=cross
else
cat >conftest.$ac_ext <<_ACEOF
#line $LINENO "configure"
#include "confdefs.h"
#include <stdio.h>
int does_printf_have_arg_control()
{
char buf[100];
/* can it swap arguments? */
snprintf(buf, 100, "%2$d|%1$d", 3, 4);
if (strcmp(buf, "4|3") != 0)
return 0;
return 1;
}
main() {
exit(! does_printf_have_arg_control());
}
_ACEOF
rm -f conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && { ac_try='./conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
pgac_cv_printf_arg_control=yes
else
echo "$as_me: program exited with status $ac_status" >&5
echo "$as_me: failed program was:" >&5
cat conftest.$ac_ext >&5
( exit $ac_status )
pgac_cv_printf_arg_control=no
fi
rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
fi
echo "$as_me:$LINENO: result: $pgac_cv_printf_arg_control" >&5
echo "${ECHO_T}$pgac_cv_printf_arg_control" >&6
# cross compiler should use our snprintf too
if test $pgac_cv_printf_arg_control != yes ; then
pgac_need_repl_snprintf=yes
fi
# Check whether <stdio.h> declares snprintf() and vsnprintf(); if not, # Check whether <stdio.h> declares snprintf() and vsnprintf(); if not,
# include/c.h will provide declarations. Note this is a separate test # include/c.h will provide declarations. Note this is a separate test
......
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
dnl $PostgreSQL: pgsql/configure.in,v 1.399 2005/01/18 05:23:36 momjian Exp $ dnl $PostgreSQL: pgsql/configure.in,v 1.400 2005/02/22 03:55:12 momjian Exp $
dnl dnl
dnl Developers, please strive to achieve this order: dnl Developers, please strive to achieve this order:
dnl dnl
...@@ -881,6 +881,11 @@ pgac_need_repl_snprintf=no ...@@ -881,6 +881,11 @@ pgac_need_repl_snprintf=no
AC_CHECK_FUNCS(snprintf, [], pgac_need_repl_snprintf=yes) AC_CHECK_FUNCS(snprintf, [], pgac_need_repl_snprintf=yes)
AC_CHECK_FUNCS(vsnprintf, [], pgac_need_repl_snprintf=yes) AC_CHECK_FUNCS(vsnprintf, [], pgac_need_repl_snprintf=yes)
PGAC_FUNC_PRINTF_ARG_CONTROL
# cross compiler should use our snprintf too
if test $pgac_cv_printf_arg_control != yes ; then
pgac_need_repl_snprintf=yes
fi
# Check whether <stdio.h> declares snprintf() and vsnprintf(); if not, # Check whether <stdio.h> declares snprintf() and vsnprintf(); if not,
# include/c.h will provide declarations. Note this is a separate test # include/c.h will provide declarations. Note this is a separate test
...@@ -1069,6 +1074,8 @@ AC_MSG_ERROR([[ ...@@ -1069,6 +1074,8 @@ AC_MSG_ERROR([[
[AC_MSG_RESULT([cross-compiling])]) [AC_MSG_RESULT([cross-compiling])])
dnl 64-bit section
dnl
dnl Check to see if we have a working 64-bit integer type. dnl Check to see if we have a working 64-bit integer type.
dnl This breaks down into two steps: dnl This breaks down into two steps:
dnl (1) figure out if the compiler has a 64-bit int type with working dnl (1) figure out if the compiler has a 64-bit int type with working
......
...@@ -57,6 +57,10 @@ typedef long long_long; ...@@ -57,6 +57,10 @@ typedef long long_long;
typedef unsigned long ulong_long; typedef unsigned long ulong_long;
#endif #endif
#ifndef NL_ARGMAX
#define NL_ARGMAX 4096
#endif
/* /*
** SNPRINTF, VSNPRINT -- counted versions of printf ** SNPRINTF, VSNPRINT -- counted versions of printf
** **
...@@ -79,14 +83,32 @@ typedef unsigned long ulong_long; ...@@ -79,14 +83,32 @@ typedef unsigned long ulong_long;
* causing nast effects. * causing nast effects.
**************************************************************/ **************************************************************/
/*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.4 2004/08/29 05:07:02 momjian Exp $";*/ /*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.5 2005/02/22 03:56:22 momjian Exp $";*/
static char *end; static char *end;
static int SnprfOverflow; static int SnprfOverflow;
int snprintf(char *str, size_t count, const char *fmt,...); int snprintf(char *str, size_t count, const char *fmt,...);
int vsnprintf(char *str, size_t count, const char *fmt, va_list args); int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
int printf(const char *format, ...);
static void dopr(char *buffer, const char *format, va_list args); static void dopr(char *buffer, const char *format, va_list args);
int
printf(const char *fmt,...)
{
int len;
va_list args;
static char* buffer[4096];
char* p;
va_start(args, fmt);
len = vsnprintf((char*)buffer, (size_t)4096, fmt, args);
va_end(args);
p = (char*)buffer;
for(;*p;p++)
putchar(*p);
return len;
}
int int
snprintf(char *str, size_t count, const char *fmt,...) snprintf(char *str, size_t count, const char *fmt,...)
{ {
...@@ -124,6 +146,10 @@ static void dopr_outch(int c); ...@@ -124,6 +146,10 @@ static void dopr_outch(int c);
static char *output; static char *output;
#define FMTSTR 1
#define FMTNUM 2
#define FMTFLOAT 3
#define FMTCHAR 4
static void static void
dopr(char *buffer, const char *format, va_list args) dopr(char *buffer, const char *format, va_list args)
...@@ -139,7 +165,34 @@ dopr(char *buffer, const char *format, va_list args) ...@@ -139,7 +165,34 @@ dopr(char *buffer, const char *format, va_list args)
int ljust; int ljust;
int len; int len;
int zpad; int zpad;
int i;
const char* format_save;
const char* fmtbegin;
int fmtpos = 1;
int realpos = 0;
int position;
static struct{
const char* fmtbegin;
const char* fmtend;
void* value;
long_long numvalue;
double fvalue;
int charvalue;
int ljust;
int len;
int zpad;
int maxwidth;
int base;
int dosign;
char type;
int precision;
int pointflag;
char func;
int realpos;
} fmtpar[NL_ARGMAX+1], *fmtparptr[NL_ARGMAX+1];
format_save = format;
output = buffer; output = buffer;
while ((ch = *format++)) while ((ch = *format++))
{ {
...@@ -148,14 +201,15 @@ dopr(char *buffer, const char *format, va_list args) ...@@ -148,14 +201,15 @@ dopr(char *buffer, const char *format, va_list args)
case '%': case '%':
ljust = len = zpad = maxwidth = 0; ljust = len = zpad = maxwidth = 0;
longflag = longlongflag = pointflag = 0; longflag = longlongflag = pointflag = 0;
fmtbegin = format - 1;
realpos = 0;
position = 0;
nextch: nextch:
ch = *format++; ch = *format++;
switch (ch) switch (ch)
{ {
case 0: case 0:
dostr("**end of format**", 0); goto performpr;
*output = '\0';
return;
case '-': case '-':
ljust = 1; ljust = 1;
goto nextch; goto nextch;
...@@ -174,7 +228,14 @@ dopr(char *buffer, const char *format, va_list args) ...@@ -174,7 +228,14 @@ dopr(char *buffer, const char *format, va_list args)
if (pointflag) if (pointflag)
maxwidth = maxwidth * 10 + ch - '0'; maxwidth = maxwidth * 10 + ch - '0';
else else
{
len = len * 10 + ch - '0'; len = len * 10 + ch - '0';
position = position * 10 + ch - '0';
}
goto nextch;
case '$':
realpos = position;
len = 0;
goto nextch; goto nextch;
case '*': case '*':
if (pointflag) if (pointflag)
...@@ -203,7 +264,17 @@ dopr(char *buffer, const char *format, va_list args) ...@@ -203,7 +264,17 @@ dopr(char *buffer, const char *format, va_list args)
} }
else else
value = va_arg(args, unsigned int); value = va_arg(args, unsigned int);
fmtnum(value, 10, 0, ljust, len, zpad); fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
fmtpar[fmtpos].base = 10;
fmtpar[fmtpos].dosign = 0;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
fmtpar[fmtpos].func = FMTNUM;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
break; break;
case 'o': case 'o':
case 'O': case 'O':
...@@ -217,7 +288,17 @@ dopr(char *buffer, const char *format, va_list args) ...@@ -217,7 +288,17 @@ dopr(char *buffer, const char *format, va_list args)
} }
else else
value = va_arg(args, unsigned int); value = va_arg(args, unsigned int);
fmtnum(value, 8, 0, ljust, len, zpad); fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
fmtpar[fmtpos].base = 8;
fmtpar[fmtpos].dosign = 0;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
fmtpar[fmtpos].func = FMTNUM;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
break; break;
case 'd': case 'd':
case 'D': case 'D':
...@@ -230,7 +311,17 @@ dopr(char *buffer, const char *format, va_list args) ...@@ -230,7 +311,17 @@ dopr(char *buffer, const char *format, va_list args)
} }
else else
value = va_arg(args, int); value = va_arg(args, int);
fmtnum(value, 10, 1, ljust, len, zpad); fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
fmtpar[fmtpos].base = 10;
fmtpar[fmtpos].dosign = 1;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
fmtpar[fmtpos].func = FMTNUM;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
break; break;
case 'x': case 'x':
if (longflag) if (longflag)
...@@ -242,7 +333,17 @@ dopr(char *buffer, const char *format, va_list args) ...@@ -242,7 +333,17 @@ dopr(char *buffer, const char *format, va_list args)
} }
else else
value = va_arg(args, unsigned int); value = va_arg(args, unsigned int);
fmtnum(value, 16, 0, ljust, len, zpad); fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
fmtpar[fmtpos].base = 16;
fmtpar[fmtpos].dosign = 0;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
fmtpar[fmtpos].func = FMTNUM;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
break; break;
case 'X': case 'X':
if (longflag) if (longflag)
...@@ -254,7 +355,17 @@ dopr(char *buffer, const char *format, va_list args) ...@@ -254,7 +355,17 @@ dopr(char *buffer, const char *format, va_list args)
} }
else else
value = va_arg(args, unsigned int); value = va_arg(args, unsigned int);
fmtnum(value, -16, 0, ljust, len, zpad); fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
fmtpar[fmtpos].base = -16;
fmtpar[fmtpos].dosign = 1;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
fmtpar[fmtpos].func = FMTNUM;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
break; break;
case 's': case 's':
strvalue = va_arg(args, char *); strvalue = va_arg(args, char *);
...@@ -262,12 +373,26 @@ dopr(char *buffer, const char *format, va_list args) ...@@ -262,12 +373,26 @@ dopr(char *buffer, const char *format, va_list args)
{ {
if (pointflag && len > maxwidth) if (pointflag && len > maxwidth)
len = maxwidth; /* Adjust padding */ len = maxwidth; /* Adjust padding */
fmtstr(strvalue, ljust, len, zpad, maxwidth); 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; break;
case 'c': case 'c':
ch = va_arg(args, int); ch = va_arg(args, int);
dopr_outch(ch); fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].charvalue = ch;
fmtpar[fmtpos].func = FMTCHAR;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
break; break;
case 'e': case 'e':
case 'E': case 'E':
...@@ -275,11 +400,20 @@ dopr(char *buffer, const char *format, va_list args) ...@@ -275,11 +400,20 @@ dopr(char *buffer, const char *format, va_list args)
case 'g': case 'g':
case 'G': case 'G':
fvalue = va_arg(args, double); fvalue = va_arg(args, double);
fmtfloat(fvalue, ch, ljust, len, maxwidth, pointflag); fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].fvalue = fvalue;
fmtpar[fmtpos].type = ch;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].maxwidth = maxwidth;
fmtpar[fmtpos].pointflag = pointflag;
fmtpar[fmtpos].func = FMTFLOAT;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
break; break;
case '%': case '%':
dopr_outch(ch); break;
continue;
default: default:
dostr("???????", 0); dostr("???????", 0);
} }
...@@ -289,6 +423,53 @@ dopr(char *buffer, const char *format, va_list args) ...@@ -289,6 +423,53 @@ dopr(char *buffer, const char *format, va_list args)
break; break;
} }
} }
performpr:
/* shuffle pointers */
for(i = 1; i < fmtpos; i++)
{
fmtparptr[i] = &fmtpar[fmtpar[i].realpos];
}
output = buffer;
format = format_save;
while ((ch = *format++))
{
for(i = 1; i < fmtpos; i++)
{
if(ch == '%' && *format == '%')
{
format++;
continue;
}
if(fmtpar[i].fmtbegin == format - 1)
{
switch(fmtparptr[i]->func){
case FMTSTR:
fmtstr(fmtparptr[i]->value, fmtparptr[i]->ljust,
fmtparptr[i]->len, fmtparptr[i]->zpad,
fmtparptr[i]->maxwidth);
break;
case FMTNUM:
fmtnum(fmtparptr[i]->numvalue, fmtparptr[i]->base,
fmtparptr[i]->dosign, fmtparptr[i]->ljust,
fmtparptr[i]->len, fmtparptr[i]->zpad);
break;
case FMTFLOAT:
fmtfloat(fmtparptr[i]->fvalue, fmtparptr[i]->type,
fmtparptr[i]->ljust, fmtparptr[i]->len,
fmtparptr[i]->precision, fmtparptr[i]->pointflag);
break;
case FMTCHAR:
dopr_outch(fmtparptr[i]->charvalue);
break;
}
format = fmtpar[i].fmtend;
goto nochar;
}
}
dopr_outch(ch);
nochar:
/* nothing */
}
*output = '\0'; *output = '\0';
} }
......
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