snprintf causes regression tests to fail
Hi!
The new snpritnf code appears not to deal with 64-bit ints. I'm getting
failures on win32 for int8 as well as all the time related tests (win32
uses int8 for tinmestamps). Removing the snprintf code and falling back
to the OS code makes everything pass again.
I would guess this affects int8 etc on other platforms as well (assuming
they use our snprintf and not the libc one), but I haven't checked it.
//Magnus
Linux and Solaris 10 x86 pass regression tests fine when I force the use of new
snprintf(). The problem should be win32 - specific. I will
investigate it throughly
tonight. Can someone experienced in win32 what can possibly be the problem?
Nick
Show quoted text
On Sun, 27 Feb 2005 19:07:16 +0100, Magnus Hagander <mha@sollentuna.net> wrote:
Hi!
The new snpritnf code appears not to deal with 64-bit ints. I'm getting
failures on win32 for int8 as well as all the time related tests (win32
uses int8 for tinmestamps). Removing the snprintf code and falling back
to the OS code makes everything pass again.I would guess this affects int8 etc on other platforms as well (assuming
they use our snprintf and not the libc one), but I haven't checked it.//Magnus
Nicolai Tufar wrote:
Linux and Solaris 10 x86 pass regression tests fine when I force the use of new
snprintf(). The problem should be win32 - specific. I will
investigate it throughly
tonight. Can someone experienced in win32 what can possibly be the problem?
Yea, I am confused too because my BSD uses the new snprintf.c code was
well. Magnus, what failures are you seeing on Win32?
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Linux and Solaris 10 x86 pass regression tests fine when I force the use
of new
snprintf(). The problem should be win32 - specific. I will
investigate it throughly
tonight. Can someone experienced in win32 what can possibly be the
problem?
Do we have any idea about what format string causes the regression failure?
It may be that certain integer types are not promoted uniformly when
pushed on the stack.
Show quoted text
Nick
On Sun, 27 Feb 2005 19:07:16 +0100, Magnus Hagander <mha@sollentuna.net>
wrote:Hi!
The new snpritnf code appears not to deal with 64-bit ints. I'm getting
failures on win32 for int8 as well as all the time related tests (win32
uses int8 for tinmestamps). Removing the snprintf code and falling back
to the OS code makes everything pass again.I would guess this affects int8 etc on other platforms as well (assuming
they use our snprintf and not the libc one), but I haven't checked it.//Magnus
---------------------------(end of broadcast)---------------------------
TIP 9: the planner will ignore your desire to choose an index scan if your
joining column's datatypes do not match
After some extensive debugging with Magnus's
help we finally managed to a kind of isolate the
problem. We placed snprintf.c in a separate
file, added necessary #includes and wrote
a simple main() function:
main()
{
unsigned long long ull=4567890123456789ULL;
static char buf[1024];
mysnprintf(buf,1024,"%lld\n",ull);
printf(buf);
}
When compiled with -D HAVE_LONG_LONG_INT_64=1
which declares long_long and ulong_long like:
typedef long long long_long;
typedef unsigned long long ulong_long;
It compiles fine and produces desired result. If not,
it produces "-869367531" as in regression tests.
Amazingly enough HAVE_LONG_LONG_INT_64 is
defined when compilation comes to src/port/snprintf.c
but the result is still wrong. I looked into configure.in
but the check for HAVE_LONG_LONG_INT_64 is too
complicated for me to understand. Bruce, could you
take a look at this? I am 90% sure it is an issue with
some configure definitions.
Best regards,
Nicolai
Show quoted text
On Mon, 28 Feb 2005 19:58:15 +0200, Nicolai Tufar <ntufar@gmail.com> wrote:
Regression test diff is attached.
It fails on the following tests:
int8
subselect
union
sequenceIt fails to display correctly number "4567890123456789".
In output is shows "-869367531". Apparent overflow or
interpreting int8 as int4.while rewriting snprintf() I did not touch the actual functions
that convert number to ASCII digit string. In truth, if you
force PostgreSQL to use snprintf.c without my patch applied
it produces the same errors.What can be wrong? GCC bug? The one I use is:
gcc.exe (GCC) 3.3.1 (mingw special 20030804-1)Any thoughts?
On Mon, 28 Feb 2005 09:17:20 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:Nicolai Tufar wrote:
Linux and Solaris 10 x86 pass regression tests fine when I force the use of new
snprintf(). The problem should be win32 - specific. I will
investigate it throughly
tonight. Can someone experienced in win32 what can possibly be the problem?Yea, I am confused too because my BSD uses the new snprintf.c code was
well. Magnus, what failures are you seeing on Win32?-- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073
Import Notes
Reply to msg id not found: d809293905022809583d9524b8@mail.gmail.com
pgsql@mohawksoft.com writes:
Do we have any idea about what format string causes the regression failure?
I'll bet the problem is that configure.in is doing things in the wrong
order: it computes INT64_FORMAT against the system printf before
deciding we should use our own printf.
regards, tom lane
Tom Lane wrote:
pgsql@mohawksoft.com writes:
Do we have any idea about what format string causes the regression failure?
I'll bet the problem is that configure.in is doing things in the wrong
order: it computes INT64_FORMAT against the system printf before
deciding we should use our own printf.
Ah, the problem was introduced here:
revision 1.401
date: 2005/02/24 02:12:15; author: tgl; state: Exp; lines: +13 -12
We aren't supposed to try to run test programs until after we've
verified that AC_TRY_RUN works.
The problem is that the PGAC_FUNC_PRINTF_ARG_CONTROL call was moved
below the printf 64-bit tests. This commited patch moves
PGAC_FUNC_PRINTF_ARG_CONTROL which is after we know AC_TRY_RUN works and
just before printf 64-bit args are tested.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Attachments:
/bjm/difftext/plainDownload
Index: configure
===================================================================
RCS file: /cvsroot/pgsql/configure,v
retrieving revision 1.428
diff -c -c -r1.428 configure
*** configure 24 Feb 2005 02:12:14 -0000 1.428
--- configure 28 Feb 2005 20:33:41 -0000
***************
*** 14809,14814 ****
--- 14809,14876 ----
# snprintfs that use %lld, %qd, or %I64d as the format. If none of these
# work, fall back to our own snprintf emulation (which we know uses %lld).
+ # Also force use of our snprintf if system's doesn't do arg control
+ if test $pgac_need_repl_snprintf = no; then
+ echo "$as_me:$LINENO: checking whether printf supports argument control" >&5
+ echo $ECHO_N "checking whether 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>
+ #include <string.h>
+
+ int main()
+ {
+ char buf[100];
+
+ /* can it swap arguments? */
+ snprintf(buf, 100, "%2\$d %1\$d", 3, 4);
+ if (strcmp(buf, "4 3") != 0)
+ return 1;
+ return 0;
+ }
+ _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
+
+ if test $pgac_cv_printf_arg_control != yes ; then
+ pgac_need_repl_snprintf=yes
+ fi
+ fi
+
+ if test $pgac_need_repl_snprintf = yes; then
+ LIBOBJS="$LIBOBJS snprintf.$ac_objext"
+ fi
+
if test "$HAVE_LONG_LONG_INT_64" = yes ; then
if test $pgac_need_repl_snprintf = no; then
echo "$as_me:$LINENO: checking snprintf format for long long int" >&5
***************
*** 14911,14978 ****
_ACEOF
- # Also force use of our snprintf if system's doesn't do arg control
- if test $pgac_need_repl_snprintf = no; then
- echo "$as_me:$LINENO: checking whether printf supports argument control" >&5
- echo $ECHO_N "checking whether 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>
- #include <string.h>
-
- int main()
- {
- char buf[100];
-
- /* can it swap arguments? */
- snprintf(buf, 100, "%2\$d %1\$d", 3, 4);
- if (strcmp(buf, "4 3") != 0)
- return 1;
- return 0;
- }
- _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
-
- if test $pgac_cv_printf_arg_control != yes ; then
- pgac_need_repl_snprintf=yes
- fi
- fi
-
- if test $pgac_need_repl_snprintf = yes; then
- LIBOBJS="$LIBOBJS snprintf.$ac_objext"
- fi
-
# Need a #define for the size of Datum (unsigned long)
echo "$as_me:$LINENO: checking for unsigned long" >&5
echo $ECHO_N "checking for unsigned long... $ECHO_C" >&6
--- 14973,14978 ----
Index: configure.in
===================================================================
RCS file: /cvsroot/pgsql/configure.in,v
retrieving revision 1.401
diff -c -c -r1.401 configure.in
*** configure.in 24 Feb 2005 02:12:15 -0000 1.401
--- configure.in 28 Feb 2005 20:33:44 -0000
***************
*** 1104,1109 ****
--- 1104,1121 ----
# snprintfs that use %lld, %qd, or %I64d as the format. If none of these
# work, fall back to our own snprintf emulation (which we know uses %lld).
+ # Also force use of our snprintf if system's doesn't do arg control
+ if test $pgac_need_repl_snprintf = no; then
+ PGAC_FUNC_PRINTF_ARG_CONTROL
+ if test $pgac_cv_printf_arg_control != yes ; then
+ pgac_need_repl_snprintf=yes
+ fi
+ fi
+
+ if test $pgac_need_repl_snprintf = yes; then
+ AC_LIBOBJ(snprintf)
+ fi
+
if test "$HAVE_LONG_LONG_INT_64" = yes ; then
if test $pgac_need_repl_snprintf = no; then
PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT
***************
*** 1131,1148 ****
AC_DEFINE_UNQUOTED(UINT64_FORMAT, $UINT64_FORMAT,
[Define to the appropriate snprintf format for unsigned 64-bit ints, if any.])
- # Also force use of our snprintf if system's doesn't do arg control
- if test $pgac_need_repl_snprintf = no; then
- PGAC_FUNC_PRINTF_ARG_CONTROL
- if test $pgac_cv_printf_arg_control != yes ; then
- pgac_need_repl_snprintf=yes
- fi
- fi
-
- if test $pgac_need_repl_snprintf = yes; then
- AC_LIBOBJ(snprintf)
- fi
-
# Need a #define for the size of Datum (unsigned long)
AC_CHECK_SIZEOF([unsigned long])
--- 1143,1148 ----
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Ah, the problem was introduced here:
Right, it was my fault.
The problem is that the PGAC_FUNC_PRINTF_ARG_CONTROL call was moved
below the printf 64-bit tests. This commited patch moves
PGAC_FUNC_PRINTF_ARG_CONTROL which is after we know AC_TRY_RUN works and
just before printf 64-bit args are tested.
This patch breaks things in a different way: you should not have moved
the AC_LIBOBJ(snprintf) step. Also you randomly placed the arg-control
test between a chunk of code and the comment describing same.
Corrected version committed.
regards, tom lane
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Ah, the problem was introduced here:
Right, it was my fault.
The problem is that the PGAC_FUNC_PRINTF_ARG_CONTROL call was moved
below the printf 64-bit tests. This commited patch moves
PGAC_FUNC_PRINTF_ARG_CONTROL which is after we know AC_TRY_RUN works and
just before printf 64-bit args are tested.This patch breaks things in a different way: you should not have moved
the AC_LIBOBJ(snprintf) step. Also you randomly placed the arg-control
test between a chunk of code and the comment describing same.
Thanks.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Neither Bruce's nor subsequent Tom's patch did not fix
the issue. The command used is:
make maintainer-clean && ./configure && make && make install && make check
It should have be fine to recompile the source code
completely. I attach the resulting config.log. May be it
will give a clue. Regression test failure are in the
same places as previous ones.
Best regards,
Nicolai
On Mon, 28 Feb 2005 16:29:57 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:
Show quoted text
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Ah, the problem was introduced here:
Right, it was my fault.
The problem is that the PGAC_FUNC_PRINTF_ARG_CONTROL call was moved
below the printf 64-bit tests. This commited patch moves
PGAC_FUNC_PRINTF_ARG_CONTROL which is after we know AC_TRY_RUN works and
just before printf 64-bit args are tested.This patch breaks things in a different way: you should not have moved
the AC_LIBOBJ(snprintf) step. Also you randomly placed the arg-control
test between a chunk of code and the comment describing same.Thanks. -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073
Nicolai Tufar wrote:
Neither Bruce's nor subsequent Tom's patch did not fix
the issue. The command used is:make maintainer-clean && ./configure && make && make install && make check
It should have be fine to recompile the source code
completely. I attach the resulting config.log. May be it
will give a clue. Regression test failure are in the
same places as previous ones.
No log attached. Please email the log to me privately.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
And while we are on it, I would like to submit minor
changes to make snprintf() vsnprintf() and printf()
functions in src/port/snprintf.c thread-safe.
Best regards,
Nicolai Tufar
Attachments:
snprintf.difftext/x-patch; name=snprintf.diffDownload
Index: src/port/snprintf.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/port/snprintf.c,v
retrieving revision 1.7
diff -c -r1.7 snprintf.c
*** src/port/snprintf.c 28 Feb 2005 14:16:16 -0000 1.7
--- src/port/snprintf.c 28 Feb 2005 23:11:22 -0000
***************
*** 82,105 ****
* for string length. This covers a nasty loophole.
*
* The other functions are there to prevent NULL pointers from
! * causing nast effects.
**************************************************************/
! /*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.7 2005/02/28 14:16:16 momjian Exp $";*/
! static char *end;
! static int SnprfOverflow;
int snprintf(char *str, size_t count, const char *fmt,...);
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);
int
printf(const char *fmt,...)
{
int len;
va_list args;
! static char* buffer[4096];
char* p;
va_start(args, fmt);
--- 82,103 ----
* for string length. This covers a nasty loophole.
*
* The other functions are there to prevent NULL pointers from
! * causing nasty effects.
**************************************************************/
! /*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.6 2005/02/22 04:57:24 momjian Exp $";*/
int snprintf(char *str, size_t count, const char *fmt,...);
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, char *end);
int
printf(const char *fmt,...)
{
int len;
va_list args;
! char* buffer[4096];
char* p;
va_start(args, fmt);
***************
*** 127,136 ****
int
vsnprintf(char *str, size_t count, const char *fmt, va_list args)
{
str[0] = '\0';
end = str + count - 1;
! SnprfOverflow = 0;
! dopr(str, fmt, args);
if (count > 0)
end[0] = '\0';
return strlen(str);
--- 125,134 ----
int
vsnprintf(char *str, size_t count, const char *fmt, va_list args)
{
+ char *end;
str[0] = '\0';
end = str + count - 1;
! dopr(str, fmt, args, end);
if (count > 0)
end[0] = '\0';
return strlen(str);
***************
*** 140,150 ****
* dopr(): poor man's version of doprintf
*/
! static void fmtstr(char *value, int ljust, int len, int zpad, int maxwidth);
! static void fmtnum(long_long value, int base, int dosign, int ljust, int len, int zpad);
! static void fmtfloat(double value, char type, int ljust, int len, int precision, int pointflag);
! static void dostr(char *str, int cut);
! static void dopr_outch(int c);
static char *output;
--- 138,148 ----
* dopr(): poor man's version of doprintf
*/
! static void fmtstr(char *value, int ljust, int len, int zpad, int maxwidth, char *end);
! static void fmtnum(long_long value, int base, int dosign, int ljust, int len, int zpad, char *end);
! static void fmtfloat(double value, char type, int ljust, int len, int precision, int pointflag, char *end);
! static void dostr(char *str, int cut, char *end);
! static void dopr_outch(int c, char *end);
static char *output;
***************
*** 154,160 ****
#define FMTCHAR 4
static void
! dopr(char *buffer, const char *format, va_list args)
{
int ch;
long_long value;
--- 152,158 ----
#define FMTCHAR 4
static void
! dopr(char *buffer, const char *format, va_list args, char *end)
{
int ch;
long_long value;
***************
*** 417,427 ****
case '%':
break;
default:
! dostr("???????", 0);
}
break;
default:
! dopr_outch(ch);
break;
}
}
--- 415,425 ----
case '%':
break;
default:
! dostr("???????", 0, end);
}
break;
default:
! dopr_outch(ch, end);
break;
}
}
***************
*** 448,474 ****
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 */
; /* semicolon required because a goto has to be attached to a statement */
--- 446,473 ----
case FMTSTR:
fmtstr(fmtparptr[i]->value, fmtparptr[i]->ljust,
fmtparptr[i]->len, fmtparptr[i]->zpad,
! fmtparptr[i]->maxwidth, end);
break;
case FMTNUM:
fmtnum(fmtparptr[i]->numvalue, fmtparptr[i]->base,
fmtparptr[i]->dosign, fmtparptr[i]->ljust,
! fmtparptr[i]->len, fmtparptr[i]->zpad, end);
break;
case FMTFLOAT:
fmtfloat(fmtparptr[i]->fvalue, fmtparptr[i]->type,
fmtparptr[i]->ljust, fmtparptr[i]->len,
! fmtparptr[i]->precision, fmtparptr[i]->pointflag,
! end);
break;
case FMTCHAR:
! dopr_outch(fmtparptr[i]->charvalue, end);
break;
}
format = fmtpar[i].fmtend;
goto nochar;
}
}
! dopr_outch(ch, end);
nochar:
/* nothing */
; /* semicolon required because a goto has to be attached to a statement */
***************
*** 477,483 ****
}
static void
! fmtstr(char *value, int ljust, int len, int zpad, int maxwidth)
{
int padlen,
strlen; /* amount to pad */
--- 476,482 ----
}
static void
! fmtstr(char *value, int ljust, int len, int zpad, int maxwidth, char *end)
{
int padlen,
strlen; /* amount to pad */
***************
*** 494,512 ****
padlen = -padlen;
while (padlen > 0)
{
! dopr_outch(' ');
--padlen;
}
! dostr(value, maxwidth);
while (padlen < 0)
{
! dopr_outch(' ');
++padlen;
}
}
static void
! fmtnum(long_long value, int base, int dosign, int ljust, int len, int zpad)
{
int signvalue = 0;
ulong_long uvalue;
--- 493,511 ----
padlen = -padlen;
while (padlen > 0)
{
! dopr_outch(' ', end);
--padlen;
}
! dostr(value, maxwidth, end);
while (padlen < 0)
{
! dopr_outch(' ', end);
++padlen;
}
}
static void
! fmtnum(long_long value, int base, int dosign, int ljust, int len, int zpad, char *end)
{
int signvalue = 0;
ulong_long uvalue;
***************
*** 561,594 ****
{
if (signvalue)
{
! dopr_outch(signvalue);
--padlen;
signvalue = 0;
}
while (padlen > 0)
{
! dopr_outch(zpad);
--padlen;
}
}
while (padlen > 0)
{
! dopr_outch(' ');
--padlen;
}
if (signvalue)
! dopr_outch(signvalue);
while (place > 0)
! dopr_outch(convert[--place]);
while (padlen < 0)
{
! dopr_outch(' ');
++padlen;
}
}
static void
! fmtfloat(double value, char type, int ljust, int len, int precision, int pointflag)
{
char fmt[32];
char convert[512];
--- 560,593 ----
{
if (signvalue)
{
! dopr_outch(signvalue, end);
--padlen;
signvalue = 0;
}
while (padlen > 0)
{
! dopr_outch(zpad, end);
--padlen;
}
}
while (padlen > 0)
{
! dopr_outch(' ', end);
--padlen;
}
if (signvalue)
! dopr_outch(signvalue, end);
while (place > 0)
! dopr_outch(convert[--place], end);
while (padlen < 0)
{
! dopr_outch(' ', end);
++padlen;
}
}
static void
! fmtfloat(double value, char type, int ljust, int len, int precision, int pointflag, char *end)
{
char fmt[32];
char convert[512];
***************
*** 615,648 ****
while (padlen > 0)
{
! dopr_outch(' ');
--padlen;
}
! dostr(convert, 0);
while (padlen < 0)
{
! dopr_outch(' ');
++padlen;
}
}
static void
! dostr(char *str, int cut)
{
if (cut)
{
while (*str && cut-- > 0)
! dopr_outch(*str++);
}
else
{
while (*str)
! dopr_outch(*str++);
}
}
static void
! dopr_outch(int c)
{
#ifdef NOT_USED
if (iscntrl((unsigned char) c) && c != '\n' && c != '\t')
--- 614,647 ----
while (padlen > 0)
{
! dopr_outch(' ', end);
--padlen;
}
! dostr(convert, 0, end);
while (padlen < 0)
{
! dopr_outch(' ', end);
++padlen;
}
}
static void
! dostr(char *str, int cut, char *end)
{
if (cut)
{
while (*str && cut-- > 0)
! dopr_outch(*str++, end);
}
else
{
while (*str)
! dopr_outch(*str++, end);
}
}
static void
! dopr_outch(int c, char *end)
{
#ifdef NOT_USED
if (iscntrl((unsigned char) c) && c != '\n' && c != '\t')
***************
*** 654,659 ****
#endif
if (end == 0 || output < end)
*output++ = c;
- else
- SnprfOverflow++;
}
--- 653,656 ----
Import Notes
Reply to msg id not found: d809293905022809583d9524b8@mail.gmail.com
Patch applied. Thanks.
---------------------------------------------------------------------------
Nicolai Tufar wrote:
And while we are on it, I would like to submit minor
changes to make snprintf() vsnprintf() and printf()
functions in src/port/snprintf.c thread-safe.Best regards,
Nicolai Tufar
[ Attachment, skipping... ]
---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Nicolai Tufar wrote:
Regression test diff is attached.
It fails on the following tests:
int8
subselect
union
sequenceIt fails to display correctly number "4567890123456789".
In output is shows "-869367531". Apparent overflow or
interpreting int8 as int4.while rewriting snprintf() I did not touch the actual functions
that convert number to ASCII digit string. In truth, if you
force PostgreSQL to use snprintf.c without my patch applied
it produces the same errors.What can be wrong? GCC bug? The one I use is:
gcc.exe (GCC) 3.3.1 (mingw special 20030804-1)
I can confirm your failure in current sources on Win32:
template1=# create table test(x int8);
CREATE TABLE
template1=# insert into test values ('4567890123456789');
INSERT 17235 1
template1=# select * from test;
x
------------
-869367531
(1 row)
and it knows it is a large number:
template1=# select * from test where x > 1000::int8;
x
------------
-869367531
(1 row)
template1=# select * from test where x < 1000::int8;
x
---
(0 rows)
I am going to add some debugs to see what is being passed to *printf().
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Import Notes
Reply to msg id not found: d809293905022809583d9524b8@mail.gmail.com | Resolved by subject fallback
Bruce Momjian wrote:
I can confirm your failure in current sources on Win32:
template1=# create table test(x int8);
CREATE TABLE
template1=# insert into test values ('4567890123456789');
INSERT 17235 1
template1=# select * from test;
x
------------
-869367531
(1 row)and it knows it is a large number:
template1=# select * from test where x > 1000::int8;
x
------------
-869367531
(1 row)
template1=# select * from test where x < 1000::int8;
x
---
(0 rows)I am going to add some debugs to see what is being passed to *printf().
I have not found the solution yet but am heading to bed. My next guess
is that Win32 isn't handling va_arg(..., long long int) properly.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
On Tue, 1 Mar 2005 00:55:20 -0500 (EST), Bruce Momjian
My next guess
is that Win32 isn't handling va_arg(..., long long int) properly.
I am trying various combination of number and types
of parameters in my test program and everything prints fine.
When it comes to pg, it fails :(
template1=# select * from test where x > 1000::int8;
x
------------
-869367531
(1 row)
I am not too fluent in source code, could someone
point me to there actual call to snprintf() is being done
when a query like this is executed. I could not find it myslef
:(
Regards,
Nick
Nicolai Tufar wrote:
On Tue, 1 Mar 2005 00:55:20 -0500 (EST), Bruce Momjian
My next guess
is that Win32 isn't handling va_arg(..., long long int) properly.I am trying various combination of number and types
of parameters in my test program and everything prints fine.
When it comes to pg, it fails :(template1=# select * from test where x > 1000::int8;
x
------------
-869367531
(1 row)I am not too fluent in source code, could someone
point me to there actual call to snprintf() is being done
when a query like this is executed. I could not find it myslef
Sure, in src/backend/utils/adt/int8.c, there is a call in int8out():
if ((len = snprintf(buf, MAXINT8LEN, INT64_FORMAT, val)) < 0)
and that calls port/snprintf.c.
I have added a puts() in snprintf.c to make sure it is getting the
long/long specifier.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
I spent all day debugging it. Still have absolutely
no idea what could possibly go wrong. Does
anyone have a slightest clue what can it be and
why it manifests itself only on win32?
On Tue, 1 Mar 2005 09:29:07 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:
Show quoted text
Nicolai Tufar wrote:
On Tue, 1 Mar 2005 00:55:20 -0500 (EST), Bruce Momjian
My next guess
is that Win32 isn't handling va_arg(..., long long int) properly.I am trying various combination of number and types
of parameters in my test program and everything prints fine.
When it comes to pg, it fails :(template1=# select * from test where x > 1000::int8;
x
------------
-869367531
(1 row)I am not too fluent in source code, could someone
point me to there actual call to snprintf() is being done
when a query like this is executed. I could not find it myslefSure, in src/backend/utils/adt/int8.c, there is a call in int8out():
if ((len = snprintf(buf, MAXINT8LEN, INT64_FORMAT, val)) < 0)
and that calls port/snprintf.c.
I have added a puts() in snprintf.c to make sure it is getting the
long/long specifier.-- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073
Nicolai Tufar wrote:
On Tue, 1 Mar 2005 00:55:20 -0500 (EST), Bruce Momjian
My next guess
is that Win32 isn't handling va_arg(..., long long int) properly.I am trying various combination of number and types
of parameters in my test program and everything prints fine.
When it comes to pg, it fails :(template1=# select * from test where x > 1000::int8;
x
------------
-869367531
(1 row)I am not too fluent in source code, could someone
point me to there actual call to snprintf() is being done
when a query like this is executed. I could not find it myslefSure, in src/backend/utils/adt/int8.c, there is a call in int8out():
if ((len = snprintf(buf, MAXINT8LEN, INT64_FORMAT, val)) < 0)
and that calls port/snprintf.c.
I have added a puts() in snprintf.c to make sure it is getting the
long/long specifier.
Just a question, and don't mind me if I am being rude, isn't this the
WRONG PLACE for a "printf" function? Wouldn't an "itoa" function be more
efficient and be less problematic?
pgsql@mohawksoft.com writes:
Just a question, and don't mind me if I am being rude, isn't this the
WRONG PLACE for a "printf" function? Wouldn't an "itoa" function be more
efficient and be less problematic?
This particular call could be so replaced, but it wouldn't solve the
general problem. snprintf has to work.
regards, tom lane
I spent all day debugging it. Still have absolutely
no idea what could possibly go wrong. Does
anyone have a slightest clue what can it be and
why it manifests itself only on win32?
It may be that the CLIB has badly broken support for 64bit integers on 32
bit platforms. Does anyone know of any Cygwin/Ming issues?
Is this only with the new snprintf code in Win32?
Is this a problem with snprintf as implemented in src/port?
Is there a reason why we don't use the snprintf that comes with the
various C compilers?
Show quoted text
On Tue, 1 Mar 2005 09:29:07 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:Nicolai Tufar wrote:
On Tue, 1 Mar 2005 00:55:20 -0500 (EST), Bruce Momjian
My next guess
is that Win32 isn't handling va_arg(..., long long int) properly.I am trying various combination of number and types
of parameters in my test program and everything prints fine.
When it comes to pg, it fails :(template1=# select * from test where x > 1000::int8;
x
------------
-869367531
(1 row)I am not too fluent in source code, could someone
point me to there actual call to snprintf() is being done
when a query like this is executed. I could not find it myslefSure, in src/backend/utils/adt/int8.c, there is a call in int8out():
if ((len = snprintf(buf, MAXINT8LEN, INT64_FORMAT, val)) < 0)
and that calls port/snprintf.c.
I have added a puts() in snprintf.c to make sure it is getting the
long/long specifier.-- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073---------------------------(end of broadcast)---------------------------
TIP 8: explain analyze is your friend
I spent all day debugging it. Still have absolutely
no idea what could possibly go wrong. Does
anyone have a slightest clue what can it be and
why it manifests itself only on win32?It may be that the CLIB has badly broken support for 64bit
integers on 32
bit platforms. Does anyone know of any Cygwin/Ming issues?Is this only with the new snprintf code in Win32?
Yes.
Is this a problem with snprintf as implemented in src/port?
Yes. Only. It works with the snprintf() in the runtime (this particular
part).
Is there a reason why we don't use the snprintf that comes with the
various C compilers?
It does not support "positional parameters" (I think it's called) which
is required for proper translations.
We do use that one when it works...
//Magnus
Import Notes
Resolved by subject fallback
On Tue, 1 Mar 2005 15:38:58 -0500 (EST), pgsql@mohawksoft.com
<pgsql@mohawksoft.com> wrote:
Is there a reason why we don't use the snprintf that comes with the
various C compilers?
snprintf() is usually buried in OS libraries. We implement
our own snprintf to make things like this:
snprintf(buf,"%2$s %1$s","world","Hello");
which is not supported on some platforms work.
We do it for national language translation of
messages. In some languages you may need
to change order of parameters to make a meaningful
sentence.
Another question is why we are using it for printing
values from database. I am not too good on function
overriding in standard C but maybe there is a way
to usage of standard snprintf() in a particular place.
On Tue, 1 Mar 2005 15:38:58 -0500 (EST), pgsql@mohawksoft.com
<pgsql@mohawksoft.com> wrote:Is there a reason why we don't use the snprintf that comes with the
various C compilers?snprintf() is usually buried in OS libraries. We implement
our own snprintf to make things like this:
snprintf(buf,"%2$s %1$s","world","Hello");
which is not supported on some platforms work.We do it for national language translation of
messages. In some languages you may need
to change order of parameters to make a meaningful
sentence.Another question is why we are using it for printing
values from database. I am not too good on function
overriding in standard C but maybe there is a way
to usage of standard snprintf() in a particular place.
Well, here is a stupid question, do we even know which snprintf we are
using on Win32? May it be possible that we are using the MingW version
which may be broken?
pgsql@mohawksoft.com writes:
Well, here is a stupid question, do we even know which snprintf we are
using on Win32? May it be possible that we are using the MingW version
which may be broken?
The regression tests were not failing until we started using the port/
version ...
regards, tom lane
Hi,
On Tuesday 01 March 2005 21:44, you wrote:
I spent all day debugging it. Still have absolutely
no idea what could possibly go wrong. Does
anyone have a slightest clue what can it be and
why it manifests itself only on win32?It may be that the CLIB has badly broken support for 64bit
integers on 32
bit platforms. Does anyone know of any Cygwin/Ming issues?Is this only with the new snprintf code in Win32?
Yes.
Is this a problem with snprintf as implemented in src/port?
Yes. Only. It works with the snprintf() in the runtime (this particular
part).Is there a reason why we don't use the snprintf that comes with the
various C compilers?It does not support "positional parameters" (I think it's called) which
is required for proper translations.
We do use that one when it works...//Magnus
Some stupid idea just crossed my mind: what if the /ports version just
re-arranges the va_list according to the positional args and calls
vsnprintf()?
At least we know compiler and library...
Or, another idea: why not format the va_args individually using the original
format specifiers alone (without positional args), and assemble the resulting
string?
Am I on dope? Or does this sound at least doable?
Didn't code too much C lately...
Greetings,
J�rg
--
Leading SW developer - S.E.A GmbH
Mail: joerg.hessdoerfer@sea-gmbh.com
WWW: http://www.sea-gmbh.com
On Tue, 1 Mar 2005 22:42:52 +0100, Joerg Hessdoerfer
<Joerg.Hessdoerfer@sea-gmbh.com> wrote:
Some stupid idea just crossed my mind: what if the /ports version just
re-arranges the va_list according to the positional args and calls
vsnprintf()?
At least we know compiler and library...
I thought about it a lot. Some platforms do not support
all of % formant strings. src/port/snprintf.c is used both
for the platforms that do not support all necessary
% modifiers and the ones that do not support %n$
modifiers. Here is a comment from configure:
# If we found "long int" is 64 bits, assume snprintf handles it. If
# we found we need to use "long long int", better check. We cope with
# snprintfs that use %lld, %qd, or %I64d as the format. If none of these
# work, fall back to our own snprintf emulation (which we know uses %lld).
Any comments on this idea? Should we have two
versions of snprintf.c for these occasions?
Or, another idea: why not format the va_args individually using the original
format specifiers alone (without positional args), and assemble the resulting
string?
That is exactly what the code does :)
Greetings,
Jörg
Nick
Joerg Hessdoerfer <Joerg.Hessdoerfer@sea-gmbh.com> writes:
Some stupid idea just crossed my mind: what if the /ports version just
re-arranges the va_list according to the positional args and calls
vsnprintf()?
Having looked at the current snprintf.c, I don't actually believe that
it works at all in the presence of positional parameter specs. It picks
up the arguments in the order they are mentioned in the format string,
which is exactly not what it's supposed to do, if I understand the
concept of positional specifiers properly. This is certain to give the
wrong answers when the arguments are of different widths.
I'm also less than thrilled with the 300K+ local array ;-). I don't see
any point in saving the width specs from the first pass to the second
when they are not needed in the first pass. NL_ARGMAX could have a more
sane value (surely not more than a couple hundred) and we need some
checks that it's not exceeded in any case. On the other side of the
coin, the hardwired 4K limit in printf() is certainly *not* enough.
I think a correct implementation is probably a three-pass affair:
1. Scan format string to determine the basic datatypes (int, float, char*,
etc) of each actual parameter and their positions. Note that runtime
width and precision specs have to be counted as actual parameters.
2. Perform the va_arg() fetches in position order, and stash the actual
parameter values into a local array.
3. Rescan format string and do the outputting.
I don't offhand see what is making the regression tests fail (it's not
the above because the problem occurs with a nonpositional format string);
but there's not much point in trying to get rid of porting issues when
the fundamental algorithm is wrong.
regards, tom lane
On Tue, 1 Mar 2005 16:20:50 -0500 (EST), pgsql@mohawksoft.com
<pgsql@mohawksoft.com> wrote:
Well, here is a stupid question, do we even know which snprintf we are
using on Win32? May it be possible that we are using the MingW version
which may be broken?
Defenitely not. I checked it by placing debugging print
statements in code.
Nicolai Tufar <ntufar@gmail.com> writes:
Amazingly enough HAVE_LONG_LONG_INT_64 is
defined when compilation comes to src/port/snprintf.c
but the result is still wrong. I looked into configure.in
but the check for HAVE_LONG_LONG_INT_64 is too
complicated for me to understand. Bruce, could you
take a look at this? I am 90% sure it is an issue with
some configure definitions.
Just out of curiosity, do either HAVE_INT64 or HAVE_UINT64 get set
in pg_config.h? The observed symptoms would be explained if typedef
int64 were ending up as "long" rather than "long long". Looking at
the #ifdef nest in include/c.h, there are a couple of ways that could
happen, including importing a definition from system header files.
If this were happening, it would presumably break all int8 math not
only snprintf, so I'm not sure it's the story. As far as I've seen,
no one has actually posted the regression diffs seen in this failure,
so most of us are in the dark about the details of the problem.
regards, tom lane
Having looked at the current snprintf.c, I don't actually believe that
it works at all in the presence of positional parameter specs. It picks
up the arguments in the order they are mentioned in the format string,
which is exactly not what it's supposed to do, if I understand the
concept of positional specifiers properly. This is certain to give the
wrong answers when the arguments are of different widths.
It picks up arguments in order of appearance, places them in
array then shuffles them according to %n$ positional parameter.
I checked it with in many different combinations, it works!
I'm also less than thrilled with the 300K+ local array ;-). I don't see
any point in saving the width specs from the first pass to the second
when they are not needed in the first pass. NL_ARGMAX could have a more
sane value (surely not more than a couple hundred) and we need some
checks that it's not exceeded in any case. On the other side of the
coin, the hardwired 4K limit in printf() is certainly *not* enough.
How would one solve this issue. Calling malloc() from a print function
would be rather expensive. Maybe call snprintf() from printf() and
see if resulting string is 4K long then allocate a new buffer and
call snprintf() again? And by the way, what should I use malloc()
or palloc()?
What would you think will be a good value for NL_ARGMAX?
I think a correct implementation is probably a three-pass affair:
1. Scan format string to determine the basic datatypes (int, float, char*,
etc) of each actual parameter and their positions. Note that runtime
width and precision specs have to be counted as actual parameters.2. Perform the va_arg() fetches in position order, and stash the actual
parameter values into a local array.
I actually do it. But in one step. I left the scanning loop in place
but replaced calls to actual printing functions with code to fill
the array, preserving width and precision. Plus I store pointers
to beginning and endings of format placeholders to not to have
to scan format string again in the next step.
3. Rescan format string and do the outputting.
My version: reorder the array and do the outputting.
/* shuffle pointers */ comment in source is misleading,
it should have been /* reorder pointers */.
I don't offhand see what is making the regression tests fail (it's not
the above because the problem occurs with a nonpositional format string);
but there's not much point in trying to get rid of porting issues when
the fundamental algorithm is wrong.
I believe my algorithm is working and it is faster than your proposed algorithm.
But if it is not acceptable I am willing to change as deemed necessary. I tested
the function separately and it passed regression tests on many platforms.
Situation with win32 is really unusual. We may need a win32 and MinGG internals
guru to have a look a the issue.
regards, tom lane
Nicolai Tufar
On Tue, 01 Mar 2005 17:45:31 -0500, Tom Lane > Just out of curiosity,
do either HAVE_INT64 or HAVE_UINT64 get set
in pg_config.h?
pg_config.h is attached. What drew my attention is the
following declaration:
/* Define to 1 if `long long int' works and is 64 bits. */
#define HAVE_LONG_LONG_INT_64
is it normal? should it not be like this:
#define HAVE_LONG_LONG_INT_64 1
Attachments:
Nicolai Tufar <ntufar@gmail.com> writes:
Having looked at the current snprintf.c, I don't actually believe that
it works at all in the presence of positional parameter specs.
It picks up arguments in order of appearance, places them in
array then shuffles them according to %n$ positional parameter.
I checked it with in many different combinations, it works!
Did you try combinations of parameters of different sizes? For instance
snprintf(..., "%g %d", doubleval, intval);
and
snprintf(..., "%2$d %1$g", doubleval, intval);
You cannot pick this up in order of appearance and expect it to work.
It might fail to fail on some machine architectures, but it's not going
to be portable.
On the other side of the
coin, the hardwired 4K limit in printf() is certainly *not* enough.
How would one solve this issue. Calling malloc() from a print function
would be rather expensive.
printf shouldn't use a buffer at all. I was thinking in terms of
passing around a state struct like
typedef struct {
char *output;
char *end;
FILE *outfile;
} printf_target;
and making dopr_outch look like
static void
dopr_outch(int c, printf_target *state)
{
if (state->output)
{
if (state->end == NULL || state->output < state->end)
*(state->output++) = c;
}
else
fputc(c, state->outfile);
}
regards, tom lane
On Tue, 01 Mar 2005 18:15:49 -0500, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Nicolai Tufar <ntufar@gmail.com> writes:
Having looked at the current snprintf.c, I don't actually believe that
it works at all in the presence of positional parameter specs.It picks up arguments in order of appearance, places them in
array then shuffles them according to %n$ positional parameter.
I checked it with in many different combinations, it works!Did you try combinations of parameters of different sizes? For instance
snprintf(..., "%g %d", doubleval, intval);
and
snprintf(..., "%2$d %1$g", doubleval, intval);
It works perfectly fine. Just checked.
You cannot pick this up in order of appearance and expect it to work.
It might fail to fail on some machine architectures, but it's not going
to be portable.
I did not modify the code that picked up the values.
I just modified it to instead of passing to printing function
store values in array.
On the other side of the
coin, the hardwired 4K limit in printf() is certainly *not* enough.How would one solve this issue. Calling malloc() from a print function
would be rather expensive.printf shouldn't use a buffer at all. I was thinking in terms of
passing around a state struct liketypedef struct {
char *output;
char *end;
FILE *outfile;
} printf_target;and making dopr_outch look like
static void
dopr_outch(int c, printf_target *state)
{
if (state->output)
{
if (state->end == NULL || state->output < state->end)
*(state->output++) = c;
}
else
fputc(c, state->outfile);
}
I will consider it tomorrow. It is too late on this side of
the pond, I need to sleep. Thank you for your attention
and help.
best regards,
Nicolai Tufar
Nicolai Tufar <ntufar@gmail.com> writes:
On Tue, 01 Mar 2005 18:15:49 -0500, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Did you try combinations of parameters of different sizes? For instance
snprintf(..., "%g %d", doubleval, intval);
and
snprintf(..., "%2$d %1$g", doubleval, intval);
It works perfectly fine. Just checked.
Well, whatever architecture you're checking on may happen to make it
work, but that does *not* mean it's portable. On my machine it fails:
int main()
{
char buf[1000];
double d = 3.14159265358979;
int i = 42;
snprintf(buf, sizeof buf, "%.15g %d", d, i);
printf("result = '%s'\n", buf);
snprintf(buf, sizeof buf, "%2$d %1$.15g", d, i);
printf("result = '%s'\n", buf);
return 0;
}
"Correct" output with the system snprintf is
result = '3.14159265358979 42'
result = '42 3.14159265358979'
With CVS-tip snprintf I get
result = '3 42'
result = '3 3505'
The second value in the last line varies erratically from run to run,
presumably because it's picking up garbage. This output appears to
indicate some problems in passing around precision specs as well as the
values themselves...
regards, tom lane
Nicolai Tufar wrote:
On Tue, 01 Mar 2005 17:45:31 -0500, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Nicolai Tufar <ntufar@gmail.com> writes:
Just out of curiosity, do either HAVE_INT64 or HAVE_UINT64 get set
in pg_config.h? The observed symptoms would be explained if typedef
int64 were ending up as "long" rather than "long long". Looking at
the #ifdef nest in include/c.h, there are a couple of ways that could
happen, including importing a definition from system header files.If this were happening, it would presumably break all int8 math not
only snprintf, so I'm not sure it's the story.I am looking into it. Will report if find something of importance.
As far as I've seen,
no one has actually posted the regression diffs seen in this failure,
so most of us are in the dark about the details of the problem.Regression diiff is attached. The problem is reported by Magnus
and me. Probably nobody else compiles pg under Win32 these
days.
I am testing the failure here. I will keep at it until I find the
cause.
The only downside is that Win32 compiles are much slower than Unix.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Import Notes
Reply to msg id not found: d8092939050301150327addc9@mail.gmail.com | Resolved by subject fallback
BTW, you should read the official spec for snprintf:
http://www.opengroup.org/onlinepubs/007908799/xsh/fprintf.html
There are a couple of interesting things that the present code is most
certainly not doing correctly, notably:
In format strings containing the %n$ form of conversion
specifications, numbered arguments in the argument list can be
referenced from the format string as many times as required.
Also it seems that runtime precision specs are required to have explicit
numbers when used in a %n$ string, which is something I didn't know
until just now. This example in the spec is instructive:
printf("%1$d:%2$.*3$d:%4$.*3$d\n", hour, min, precision, sec);
It might be a good idea to go look at whichever *BSD we got this code
from originally, and see if they've upgraded it to do %n$. 'Cause it
will take a nontrivial amount of work to get from where we are now to
something that follows the full spec.
regards, tom lane
I have some new information. If I add the attached patch to snprintf.c,
I should see see snprintf() being called printing "0", vsnprintf()
printing "1" and dopr(), "2". However, I only see "0" printing in the
server logs.
I think this means it is finding our /port/snprintf(), but when it calls
vsnprintf, it must be using some other version, probably the operating
system version that doesn't support %lld.
I am also attaching the 'nm' output from libpgport_srv.a which does show
vsnprintf as being defined.
Win32 doesn't like multiply defined symbols so we use
-Wl,--allow-multiple-definition to allow multiple symbols.
I bet if I define LONG_LONG_INT_FORMAT as '%I64d' it would pass the
regression tests. (I will test now.) Our config/c-library.m4 file
confirms that format for MinGW:
# MinGW uses '%I64d', though gcc throws an warning with -Wall,
The big question is why our own vsnprintf() is not being called from
snprintf() in our port file.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Attachments:
/bjm/difftext/plainDownload
*** snprintf.c Tue Mar 1 19:02:13 2005
--- /laptop/tmp/snprintf.c Tue Mar 1 20:27:21 2005
***************
*** 96,101 ****
--- 96,102 ----
int len;
va_list args;
+ puts("0");
va_start(args, fmt);
len = vsnprintf(str, count, fmt, args);
va_end(args);
***************
*** 109,114 ****
--- 110,116 ----
char *end;
str[0] = '\0';
end = str + count - 1;
+ puts("1");
dopr(str, fmt, args, end);
if (count > 0)
end[0] = '\0';
***************
*** 178,183 ****
--- 180,186 ----
int realpos;
} fmtpar[NL_ARGMAX+1], *fmtparptr[NL_ARGMAX+1];
+ puts("2");
format_save = format;
output = buffer;
Import Notes
Reply to msg id not found: d809293905022809583d9524b8@mail.gmail.com | Resolved by subject fallback
Bruce Momjian <pgman@candle.pha.pa.us> writes:
I think this means it is finding our /port/snprintf(), but when it calls
vsnprintf, it must be using some other version, probably the operating
system version that doesn't support %lld.
Ya know, I was wondering about that but dismissed it because the
routines were all declared in the same file. Windows' linker must
behave very oddly to do this.
Does it help if you flip the order of the snprintf and vsnprintf
functions in snprintf.c?
regards, tom lane
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
I think this means it is finding our /port/snprintf(), but when it calls
vsnprintf, it must be using some other version, probably the operating
system version that doesn't support %lld.
I can confirm that using "%I64d" for the printf format allows the
regression tests to pass for int8.
Ya know, I was wondering about that but dismissed it because the
routines were all declared in the same file. Windows' linker must
behave very oddly to do this.
Yep, quite unusual.
Does it help if you flip the order of the snprintf and vsnprintf
functions in snprintf.c?
Testing now.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
I think this means it is finding our /port/snprintf(), but when it calls
vsnprintf, it must be using some other version, probably the operating
system version that doesn't support %lld.Ya know, I was wondering about that but dismissed it because the
routines were all declared in the same file. Windows' linker must
behave very oddly to do this.Does it help if you flip the order of the snprintf and vsnprintf
functions in snprintf.c?
Yes, it fixes the problem and I have applied the reordering with a
comment.
I will start working on fixing the large fmtpar allocations now.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Tom Lane wrote:
Does it help if you flip the order of the snprintf and vsnprintf
functions in snprintf.c?
Yes, it fixes the problem and I have applied the reordering with a
comment.
Fascinating.
I will start working on fixing the large fmtpar allocations now.
Quite honestly, this code is not worth micro-optimizing because it
is fundamentally broken. See my other comments in this thread.
Can we find a BSD-license implementation that follows the spec?
regards, tom lane
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Tom Lane wrote:
Does it help if you flip the order of the snprintf and vsnprintf
functions in snprintf.c?Yes, it fixes the problem and I have applied the reordering with a
comment.Fascinating.
I will start working on fixing the large fmtpar allocations now.
Quite honestly, this code is not worth micro-optimizing because it
is fundamentally broken. See my other comments in this thread.
I am working on something that just counts the '%' characters in the
format string and allocates an array that size.
Can we find a BSD-license implementation that follows the spec?
I would think NetBSD would be our best bet. I will download it and take
a look.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Bruce Momjian wrote:
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Tom Lane wrote:
Does it help if you flip the order of the snprintf and vsnprintf
functions in snprintf.c?Yes, it fixes the problem and I have applied the reordering with a
comment.Fascinating.
I will start working on fixing the large fmtpar allocations now.
Quite honestly, this code is not worth micro-optimizing because it
is fundamentally broken. See my other comments in this thread.I am working on something that just counts the '%' characters in the
format string and allocates an array that size.Can we find a BSD-license implementation that follows the spec?
I would think NetBSD would be our best bet. I will download it and take
a look.
Oops, I remember now that NetBSD doesn't support it. I think FreeBSD does.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Bruce Momjian wrote:
Bruce Momjian wrote:
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Tom Lane wrote:
Does it help if you flip the order of the snprintf and vsnprintf
functions in snprintf.c?Yes, it fixes the problem and I have applied the reordering with a
comment.Fascinating.
I will start working on fixing the large fmtpar allocations now.
Quite honestly, this code is not worth micro-optimizing because it
is fundamentally broken. See my other comments in this thread.I am working on something that just counts the '%' characters in the
format string and allocates an array that size.Can we find a BSD-license implementation that follows the spec?
I would think NetBSD would be our best bet. I will download it and take
a look.Oops, I remember now that NetBSD doesn't support it. I think FreeBSD does.
OK, I have the structure exceess patched at least with this applied
patch.
Have we considered what is going to happen to applications when they use
our snprintf instead of the one from the operating system? I don't
think it is going to always match and might cause confusion. Look at
the confusion is caused us.
Can we force only gettext() to call our special snprintf verions but
leave the application symbol space unchanged?
I just looked at my BSD/OS libpq based on CVS and see [v]snprintf
exported:
$ nm /pg/interfaces/libpq/libpq.so|grep snprintf
00052434 T snprintf
000523e0 T vsnprintf
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Attachments:
/pgpatches/snprintftext/plainDownload
Index: src/port/snprintf.c
===================================================================
RCS file: /cvsroot/pgsql/src/port/snprintf.c,v
retrieving revision 1.11
diff -c -c -r1.11 snprintf.c
*** src/port/snprintf.c 2 Mar 2005 03:21:52 -0000 1.11
--- src/port/snprintf.c 2 Mar 2005 05:17:01 -0000
***************
*** 32,49 ****
* SUCH DAMAGE.
*/
! /* might be in either frontend or backend */
#include "postgres_fe.h"
#ifndef WIN32
#include <sys/ioctl.h>
#endif
#include <sys/param.h>
- #ifndef NL_ARGMAX
- #define NL_ARGMAX 4096
- #endif
-
/*
** SNPRINTF, VSNPRINT -- counted versions of printf
**
--- 32,48 ----
* SUCH DAMAGE.
*/
! #ifndef FRONTEND
! #include "postgres.h"
! #else
#include "postgres_fe.h"
+ #endif
#ifndef WIN32
#include <sys/ioctl.h>
#endif
#include <sys/param.h>
/*
** SNPRINTF, VSNPRINT -- counted versions of printf
**
***************
*** 157,167 ****
int realpos = 0;
int position;
char *output;
! /* In thread mode this structure is too large. */
! #ifndef ENABLE_THREAD_SAFETY
! static
! #endif
! struct{
const char* fmtbegin;
const char* fmtend;
void* value;
--- 156,164 ----
int realpos = 0;
int position;
char *output;
! int percents = 1;
! const char *p;
! struct fmtpar {
const char* fmtbegin;
const char* fmtend;
void* value;
***************
*** 179,188 ****
int pointflag;
char func;
int realpos;
! } fmtpar[NL_ARGMAX+1], *fmtparptr[NL_ARGMAX+1];
!
format_save = format;
output = buffer;
while ((ch = *format++))
{
--- 176,205 ----
int pointflag;
char func;
int realpos;
! } *fmtpar, **fmtparptr;
+ /* Create enough structures to hold all arguments */
+ for (p = format; *p != '\0'; p++)
+ if (*p == '%') /* counts %% as two, so overcounts */
+ percents++;
+ #ifndef FRONTEND
+ fmtpar = pgport_palloc(sizeof(struct fmtpar) * percents);
+ fmtparptr = pgport_palloc(sizeof(struct fmtpar *) * percents);
+ #else
+ if ((fmtpar = malloc(sizeof(struct fmtpar) * percents)) == NULL)
+ {
+ fprintf(stderr, _("out of memory\n"));
+ exit(1);
+ }
+ if ((fmtparptr = malloc(sizeof(struct fmtpar *) * percents)) == NULL)
+ {
+ fprintf(stderr, _("out of memory\n"));
+ exit(1);
+ }
+ #endif
+
format_save = format;
+
output = buffer;
while ((ch = *format++))
{
***************
*** 418,426 ****
performpr:
/* shuffle pointers */
for(i = 1; i < fmtpos; i++)
- {
fmtparptr[i] = &fmtpar[fmtpar[i].realpos];
- }
output = buffer;
format = format_save;
while ((ch = *format++))
--- 435,441 ----
***************
*** 465,470 ****
--- 480,493 ----
; /* semicolon required because a goto has to be attached to a statement */
}
*output = '\0';
+
+ #ifndef FRONTEND
+ pgport_pfree(fmtpar);
+ pgport_pfree(fmtparptr);
+ #else
+ free(fmtpar);
+ free(fmtparptr);
+ #endif
}
static void
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Have we considered what is going to happen to applications when they use
our snprintf instead of the one from the operating system?
Hmm ...
First line of thought: we surely must not insert a snprintf into
libpq.so unless it is 100% up to spec *and* has no performance issues
... neither of which can be claimed of the CVS-tip version.
Second line of thought: libpq already feels free to insert allegedly
up-to-spec versions of a number of things, and no one has complained.
Maybe the linker prevents problems by not linking these versions to
any calls from outside libpq?
Third thought: Windows' linker seems to be broken enough that it may
create problems of this ilk that exist on no other platform.
regards, tom lane
Tom lane wrote:
With CVS-tip snprintf I get
result = '3 42'
result = '3 3505'
I get similar results:
result = '3 42'
result = '9e-313 1413754129'
Now I agree with you, it is fundamentally broken.
We need to replace this implementation.
Bruce Momjian wrote:
I can confirm that using "%I64d" for the printf format allows the
regression tests to pass for int8.
But snprintf.c code does not support "%I64d" construct. It must
be picking OS's vsnprintf()
Bruce Momjian wrote:
I think FreeBSD does.
I started with FreeBSD's vsnprintf() at first
but was set back by it's complexity and decided to
modify the port/snprintf.c code. Now would you like me
to incorporate FreeBSD's one into the code.
Give me a week and I will come with the patch.
Best regards,
Nicolai Tufar
Nicolai Tufar <ntufar@gmail.com> writes:
I started with FreeBSD's vsnprintf() at first
but was set back by it's complexity and decided to
modify the port/snprintf.c code. Now would you like me
to incorporate FreeBSD's one into the code.
Give me a week and I will come with the patch.
It's all yours ...
regards, tom lane
Hi,
On Wednesday 02 March 2005 01:28, you wrote:
BTW, you should read the official spec for snprintf:
http://www.opengroup.org/onlinepubs/007908799/xsh/fprintf.html
There are a couple of interesting things that the present code is most
certainly not doing correctly, notably:In format strings containing the %n$ form of conversion
specifications, numbered arguments in the argument list can be
referenced from the format string as many times as required.Also it seems that runtime precision specs are required to have explicit
numbers when used in a %n$ string, which is something I didn't know
until just now. This example in the spec is instructive:
printf("%1$d:%2$.*3$d:%4$.*3$d\n", hour, min, precision, sec);It might be a good idea to go look at whichever *BSD we got this code
from originally, and see if they've upgraded it to do %n$. 'Cause it
will take a nontrivial amount of work to get from where we are now to
something that follows the full spec.
don't know if PG borrowed the code from here, but according to the manpage
FreeBSD 5.3 seems to have a quite complete implementation, see
http://www.freebsd.org/cgi/man.cgi?query=snprintf&apropos=0&sektion=3&manpath=FreeBSD+5.3-RELEASE+and+Ports&format=html
Would this help?
Greetings,
J�rg
--
Leading SW developer - S.E.A GmbH
Mail: joerg.hessdoerfer@sea-gmbh.com
WWW: http://www.sea-gmbh.com
On Wed, 2 Mar 2005 09:24:32 +0100, Joerg Hessdoerfer
<Joerg.Hessdoerfer@sea-gmbh.com> wrote:
don't know if PG borrowed the code from here, but according to the manpage
FreeBSD 5.3 seems to have a quite complete implementation, see
http://www.freebsd.org/cgi/man.cgi?query=snprintf&apropos=0&sektion=3&manpath=FreeBSD+5.3-RELEASE+and+Ports&format=htmlWould this help?
Yes, it would. With Tom Lane's blessing I am starting on incorporating it into
PG now.
The big question is why our own vsnprintf() is not being called from
snprintf() in our port file.
I have seen this "problem" before, well, it isn't really a problem I guess.
I'm not sure of the gcc compiler options, but....
On the Microsoft compiler if you specify the option "/Gy" it separates the
functions within the object file, that way you don't load all the
functions from the object if they are not needed.
If, however, you create a function with the same name as another function,
and one is declared in an object compiled with the "/Gy" option, and the
other's object file is not, then if you also use a different function or
reference variable in the object file compiled without the "/Gy" option,
then the conflicting function will probably be used. Make sense?
I would suggest using macro to redefine snprintf and vnsprintf to avoid
the issue:
#define snprintf pg_snprintf
#define vnsprintf pg_vnsprintf
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Have we considered what is going to happen to applications when they use
our snprintf instead of the one from the operating system?Hmm ...
First line of thought: we surely must not insert a snprintf into
libpq.so unless it is 100% up to spec *and* has no performance issues
... neither of which can be claimed of the CVS-tip version.
Agreed, and we have to support all the 64-bit specifications a port
might support like %qd and %I64d as well as %lld. I have added that to
our current CVS version.
Second line of thought: libpq already feels free to insert allegedly
up-to-spec versions of a number of things, and no one has complained.
Maybe the linker prevents problems by not linking these versions to
any calls from outside libpq?
I just tested on BSD/OS and a program with a single printf() call does
call our printf if libpq is used on the link line. The program makes no
libpq calls at all.
Third thought: Windows' linker seems to be broken enough that it may
create problems of this ilk that exist on no other platform.
Yes, strangly the Window's linker is fine because libpqdll.def defines
what symbols are exported. I don't think Unix has that capability.
Is there any way we can have just gettext() call our snprintf under a
special name?
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Yes, strangly the Window's linker is fine because libpqdll.def defines
what symbols are exported. I don't think Unix has that capability.
A non-static "public" function in a Windows DLL is not available for
dynamic linking unless explicitly declared as dll export. This behavior is
completely different than UNIX shared libraries.
Windows static libraries operate completely differently than Windows DLLs,
they work like their UNIX equivilents.
So, if you create an snprintf function in code that will be in both a
static and dynamic library, the static library may have conflicts where as
the dynamic one will not.
Don't you love Windows?
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Tom Lane wrote:
First line of thought: we surely must not insert a snprintf into
libpq.so unless it is 100% up to spec *and* has no performance issues
... neither of which can be claimed of the CVS-tip version.
Agreed, and we have to support all the 64-bit specifications a port
might support like %qd and %I64d as well as %lld. I have added that to
our current CVS version.
I really dislike that idea and request that you revert it.
Is there any way we can have just gettext() call our snprintf under a
special name?
The issue only comes up in libpq --- in the backend there is no reason
that snprintf can't be our snprintf, and likewise in self-contained
programs like psql. It might be worth the pain-in-the-neck quality to
have libpq refer to the functions as pq_snprintf etc. Perhaps we could
do this via macros
#define snprintf pq_snprintf
and not have to uglify the source code.
regards, tom lane
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Tom Lane wrote:
First line of thought: we surely must not insert a snprintf into
libpq.so unless it is 100% up to spec *and* has no performance issues
... neither of which can be claimed of the CVS-tip version.Agreed, and we have to support all the 64-bit specifications a port
might support like %qd and %I64d as well as %lld. I have added that to
our current CVS version.I really dislike that idea and request that you revert it.
Is there any way we can have just gettext() call our snprintf under a
special name?The issue only comes up in libpq --- in the backend there is no reason
that snprintf can't be our snprintf, and likewise in self-contained
programs like psql. It might be worth the pain-in-the-neck quality to
have libpq refer to the functions as pq_snprintf etc. Perhaps we could
do this via macros#define snprintf pq_snprintf
Didn't I suggest that earlier? :) Also, since it is vsnprintf that seems
to be a bigger issue:
#define vsnprintf pq_vsnprintf
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Tom Lane wrote:
First line of thought: we surely must not insert a snprintf into
libpq.so unless it is 100% up to spec *and* has no performance issues
... neither of which can be claimed of the CVS-tip version.Agreed, and we have to support all the 64-bit specifications a port
might support like %qd and %I64d as well as %lld. I have added that to
our current CVS version.I really dislike that idea and request that you revert it.
Done.
Is there any way we can have just gettext() call our snprintf under a
special name?The issue only comes up in libpq --- in the backend there is no reason
that snprintf can't be our snprintf, and likewise in self-contained
programs like psql. It might be worth the pain-in-the-neck quality to
have libpq refer to the functions as pq_snprintf etc. Perhaps we could
do this via macros#define snprintf pq_snprintf
and not have to uglify the source code.
Yes, this is what I was thinking of too. I think it would need a macro
in libpq to map the libc names to the pq_* names, and a separate /port C
file that maps the normal libc names to the pg_* names. For client
applications and the backend, this new C file would catch all the
snprintf calls, while for libpq the pg_* calls would be used directly
and the new C file with the libc symbols would not be pulled in.
Does that sound like a plan?
The reason we can't just use the macro everwhere is that we don't want
applications using libpq to all be using pg_* functions, only psql and
our own. The only other solution I can think of is to make sure all
client apps use FRONTEND as a define and trigger the macros from libc
names to pg_* names on that.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Dear all,
After struggling for one week to to integrate FreeBSD's vfprintf.c into
PostgreSQL I finally gave up. It is too dependent on underlying
FreeBSD system functions. To incorporate it into PostgreSQL we need
to move vfprintf.c file itself, two dozen files form gdtoa and a half
a dozen __XXtoa.c files scattered in apparently random fashion all
around FreeBSD source tree.
Instead I researched some other implementations of snprintf on
the web released under a license compatible with PostgreSQL's.
The most suitable one I have come upon is Trio
[http://daniel.haxx.se/projects/trio/].
It is distributed under a MIT-like license which, I think will be
compatible with us.
What do you think about it? Shall I abandon FreeBSD and go ahead
ıncorporatıng Trıo?
And by the way, what ıs the conclusıon of snprıntf() vs. pg_snprintf()
and UNIX libraries discussion a week ago? Which one shall
I implement?
Regards,
Nicolai Tufar
From what I recall from the conversation, I would say rename the vsprintf
and the sprintf functions in postgres to pq_vsnprintf and pq_snprintf.
Define a couple macros: (in some common header, pqprintf.h?)
#define snprintf pq_snprintf
#define vsnprintf pq_snprintf
Then just maintain the postgres forms of printf which have seemed to be OK
except that on Win32 vnsprintf, although in the same object file was not
being used.
Show quoted text
Dear all,
After struggling for one week to to integrate FreeBSD's vfprintf.c into
PostgreSQL I finally gave up. It is too dependent on underlying
FreeBSD system functions. To incorporate it into PostgreSQL we need
to move vfprintf.c file itself, two dozen files form gdtoa and a half
a dozen __XXtoa.c files scattered in apparently random fashion all
around FreeBSD source tree.Instead I researched some other implementations of snprintf on
the web released under a license compatible with PostgreSQL's.
The most suitable one I have come upon is Trio
[http://daniel.haxx.se/projects/trio/].
It is distributed under a MIT-like license which, I think will be
compatible with us.What do you think about it? Shall I abandon FreeBSD and go ahead
ıncorporatıng Trıo?And by the way, what ıs the conclusıon of snprıntf() vs. pg_snprintf()
and UNIX libraries discussion a week ago? Which one shall
I implement?Regards,
Nicolai Tufar---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?
Nicolai Tufar wrote:
Dear all,
After struggling for one week to to integrate FreeBSD's vfprintf.c into
PostgreSQL I finally gave up. It is too dependent on underlying
FreeBSD system functions. To incorporate it into PostgreSQL we need
to move vfprintf.c file itself, two dozen files form gdtoa and a half
a dozen __XXtoa.c files scattered in apparently random fashion all
around FreeBSD source tree.Instead I researched some other implementations of snprintf on
the web released under a license compatible with PostgreSQL's.
The most suitable one I have come upon is Trio
[http://daniel.haxx.se/projects/trio/].
It is distributed under a MIT-like license which, I think will be
compatible with us.What do you think about it? Shall I abandon FreeBSD and go ahead
?ncorporat?ng Tr?o?
Yes, maybe just add the proper %$ handling from Trio to what we have
now.
And by the way, what ?s the conclus?on of snpr?ntf() vs. pg_snprintf()
and UNIX libraries discussion a week ago? Which one shall
I implement?
I think the proper direction is not to export snprintf() from libpq so
that user applications will use the native snprintf, but our code can
use our custom version.
I will work on a patch now.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
On Wed, 9 Mar 2005 22:51:27 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:
What do you think about it? Shall I abandon FreeBSD and go ahead
Incorporating Trio?Yes, maybe just add the proper %$ handling from Trio to what we have
now.
Adding proper %$ from Trio will require too much effort. I would
rather not do it. Not because I am lazy but because:
1) Trio team seem to be very serious about standards, update
the library as soon as new standards come out:
<quote>
Trio fully implements the C99 (ISO/IEC 9899:1999) and UNIX98 (the
Single Unix Specification, Version 2) standards, as well as many
features from other implementations, e.g. the GNU libc and BSD4.
</quote>
2) If we integrate the whole library in source code we will
not have to maintain it and will rely on Trio team for bug fixes
and updates. Integrating it will be very easy since all of the
functions begin with "trio_". I used it instead of the src/port/snrpintf.c
one and it passes regression tests under Win32 just fine.
The downside is that Trio library is rather big. It is 3 .c and 6 .h
files totalling 11556 lines. Compiled it is 71224 bytes not stripped
and 56204 bytes stripped on Solaris 10 for x86, 32-bit. Even for
a shared library it will probably be too much. Trio has a lot
of string handling functions which are probably not necessary.
Would you like me to try to remove everything unnecessary from
it or we will settle with the full version?
Regards,
Nicolai Tufar
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Tom Lane wrote:
First line of thought: we surely must not insert a snprintf into
libpq.so unless it is 100% up to spec *and* has no performance issues
... neither of which can be claimed of the CVS-tip version.Agreed, and we have to support all the 64-bit specifications a port
might support like %qd and %I64d as well as %lld. I have added that to
our current CVS version.I really dislike that idea and request that you revert it.
Is there any way we can have just gettext() call our snprintf under a
special name?The issue only comes up in libpq --- in the backend there is no reason
that snprintf can't be our snprintf, and likewise in self-contained
programs like psql. It might be worth the pain-in-the-neck quality to
have libpq refer to the functions as pq_snprintf etc. Perhaps we could
do this via macros#define snprintf pq_snprintf
and not have to uglify the source code.
OK, here is a patch that changes snprintf() to pg_snprintf() for
platforms that need our snprintf. We do the same thing with
pgrename/pgunlink.
It manages to preserve printf-like argument checking in gcc.
I considered using a macro just in libpq but realized it was going to be
too ugly and too easy to break without us detecting it.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Attachments:
/pgpatches/snprintftext/plainDownload
Index: configure
===================================================================
RCS file: /cvsroot/pgsql/configure,v
retrieving revision 1.432
diff -c -c -r1.432 configure
*** configure 2 Mar 2005 15:42:35 -0000 1.432
--- configure 10 Mar 2005 21:05:27 -0000
***************
*** 14973,14978 ****
--- 14973,14983 ----
# Now we have checked all the reasons to replace snprintf
if test $pgac_need_repl_snprintf = yes; then
+
+ cat >>confdefs.h <<\_ACEOF
+ #define USE_SNPRINTF 1
+ _ACEOF
+
LIBOBJS="$LIBOBJS snprintf.$ac_objext"
fi
Index: configure.in
===================================================================
RCS file: /cvsroot/pgsql/configure.in,v
retrieving revision 1.405
diff -c -c -r1.405 configure.in
*** configure.in 2 Mar 2005 15:42:35 -0000 1.405
--- configure.in 10 Mar 2005 21:05:28 -0000
***************
*** 1143,1148 ****
--- 1143,1149 ----
# Now we have checked all the reasons to replace snprintf
if test $pgac_need_repl_snprintf = yes; then
+ AC_DEFINE(USE_SNPRINTF, 1, [Use replacement snprintf() functions.])
AC_LIBOBJ(snprintf)
fi
Index: src/bin/pg_ctl/pg_ctl.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/pg_ctl/pg_ctl.c,v
retrieving revision 1.54
diff -c -c -r1.54 pg_ctl.c
*** src/bin/pg_ctl/pg_ctl.c 22 Feb 2005 04:39:22 -0000 1.54
--- src/bin/pg_ctl/pg_ctl.c 10 Mar 2005 21:05:30 -0000
***************
*** 337,355 ****
if (log_file != NULL)
#ifndef WIN32 /* Cygwin doesn't have START */
snprintf(cmd, MAXPGPATH, "%s\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1 &%s",
#else
snprintf(cmd, MAXPGPATH, "%sSTART /B \"\" \"%s\" %s%s < \"%s\" >> \"%s\" 2>&1%s",
- #endif
SYSTEMQUOTE, postgres_path, pgdata_opt, post_opts,
DEVNULL, log_file, SYSTEMQUOTE);
else
#ifndef WIN32 /* Cygwin doesn't have START */
snprintf(cmd, MAXPGPATH, "%s\"%s\" %s%s < \"%s\" 2>&1 &%s",
#else
snprintf(cmd, MAXPGPATH, "%sSTART /B \"\" \"%s\" %s%s < \"%s\" 2>&1%s",
- #endif
SYSTEMQUOTE, postgres_path, pgdata_opt, post_opts,
DEVNULL, SYSTEMQUOTE);
return system(cmd);
}
--- 337,359 ----
if (log_file != NULL)
#ifndef WIN32 /* Cygwin doesn't have START */
snprintf(cmd, MAXPGPATH, "%s\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1 &%s",
+ SYSTEMQUOTE, postgres_path, pgdata_opt, post_opts,
+ DEVNULL, log_file, SYSTEMQUOTE);
#else
snprintf(cmd, MAXPGPATH, "%sSTART /B \"\" \"%s\" %s%s < \"%s\" >> \"%s\" 2>&1%s",
SYSTEMQUOTE, postgres_path, pgdata_opt, post_opts,
DEVNULL, log_file, SYSTEMQUOTE);
+ #endif
else
#ifndef WIN32 /* Cygwin doesn't have START */
snprintf(cmd, MAXPGPATH, "%s\"%s\" %s%s < \"%s\" 2>&1 &%s",
+ SYSTEMQUOTE, postgres_path, pgdata_opt, post_opts,
+ DEVNULL, SYSTEMQUOTE);
#else
snprintf(cmd, MAXPGPATH, "%sSTART /B \"\" \"%s\" %s%s < \"%s\" 2>&1%s",
SYSTEMQUOTE, postgres_path, pgdata_opt, post_opts,
DEVNULL, SYSTEMQUOTE);
+ #endif
return system(cmd);
}
Index: src/bin/psql/command.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/command.c,v
retrieving revision 1.140
diff -c -c -r1.140 command.c
*** src/bin/psql/command.c 22 Feb 2005 04:40:51 -0000 1.140
--- src/bin/psql/command.c 10 Mar 2005 21:05:31 -0000
***************
*** 1175,1187 ****
* supplied path unless we use only backslashes, so we do that.
*/
#endif
- snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d", tmpdir,
#ifndef WIN32
! "/",
#else
! "", /* trailing separator already present */
#endif
- (int)getpid());
fname = (const char *) fnametmp;
--- 1175,1187 ----
* supplied path unless we use only backslashes, so we do that.
*/
#endif
#ifndef WIN32
! snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d", tmpdir,
! "/", (int)getpid());
#else
! snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d", tmpdir,
! "" /* trailing separator already present */, (int)getpid());
#endif
fname = (const char *) fnametmp;
Index: src/include/pg_config.h.in
===================================================================
RCS file: /cvsroot/pgsql/src/include/pg_config.h.in,v
retrieving revision 1.81
diff -c -c -r1.81 pg_config.h.in
*** src/include/pg_config.h.in 6 Nov 2004 23:06:25 -0000 1.81
--- src/include/pg_config.h.in 10 Mar 2005 21:05:31 -0000
***************
*** 648,653 ****
--- 648,656 ----
/* Define to 1 to build with Rendezvous support. (--with-rendezvous) */
#undef USE_RENDEZVOUS
+ /* Use replacement snprintf() functions. */
+ #undef USE_SNPRINTF
+
/* Define to build with (Open)SSL support. (--with-openssl) */
#undef USE_SSL
Index: src/include/port.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/port.h,v
retrieving revision 1.70
diff -c -c -r1.70 port.h
*** src/include/port.h 27 Feb 2005 00:53:29 -0000 1.70
--- src/include/port.h 10 Mar 2005 21:05:31 -0000
***************
*** 107,112 ****
--- 107,132 ----
extern unsigned char pg_toupper(unsigned char ch);
extern unsigned char pg_tolower(unsigned char ch);
+ #ifdef USE_SNPRINTF
+ extern int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args);
+ extern int pg_snprintf(char *str, size_t count, const char *fmt,...)
+ /* This extension allows gcc to check the format string */
+ __attribute__((format(printf, 3, 4)));
+ extern int pg_printf(const char *fmt,...)
+ /* This extension allows gcc to check the format string */
+ __attribute__((format(printf, 1, 2)));
+
+ #ifdef __GNUC__
+ #define vsnprintf(...) pg_vsnprintf(__VA_ARGS__)
+ #define snprintf(...) pg_snprintf(__VA_ARGS__)
+ #define printf(...) pg_printf(__VA_ARGS__)
+ #else
+ #define vsnprintf pg_vsnprintf
+ #define snprintf pg_snprintf
+ #define printf pg_printf
+ #endif
+ #endif
+
/* Portable prompt handling */
extern char *simple_prompt(const char *prompt, int maxlen, bool echo);
Index: src/port/snprintf.c
===================================================================
RCS file: /cvsroot/pgsql/src/port/snprintf.c,v
retrieving revision 1.16
diff -c -c -r1.16 snprintf.c
*** src/port/snprintf.c 2 Mar 2005 23:56:53 -0000 1.16
--- src/port/snprintf.c 10 Mar 2005 21:05:32 -0000
***************
*** 67,83 ****
/*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.16 2005/03/02 23:56:53 momjian Exp $";*/
! int snprintf(char *str, size_t count, const char *fmt,...);
! 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, char *end);
- /*
- * If vsnprintf() is not before snprintf() in this file, snprintf()
- * will call the system vsnprintf() on MinGW.
- */
int
! vsnprintf(char *str, size_t count, const char *fmt, va_list args)
{
char *end;
str[0] = '\0';
--- 67,79 ----
/*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.16 2005/03/02 23:56:53 momjian Exp $";*/
! 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_printf(const char *format, ...);
static void dopr(char *buffer, const char *format, va_list args, char *end);
int
! pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
{
char *end;
str[0] = '\0';
***************
*** 89,107 ****
}
int
! snprintf(char *str, size_t count, const char *fmt,...)
{
int len;
va_list args;
va_start(args, fmt);
! len = vsnprintf(str, count, fmt, args);
va_end(args);
return len;
}
int
! printf(const char *fmt,...)
{
int len;
va_list args;
--- 85,103 ----
}
int
! pg_snprintf(char *str, size_t count, const char *fmt,...)
{
int len;
va_list args;
va_start(args, fmt);
! len = pg_vsnprintf(str, count, fmt, args);
va_end(args);
return len;
}
int
! pg_printf(const char *fmt,...)
{
int len;
va_list args;
***************
*** 109,115 ****
char* p;
va_start(args, fmt);
! len = vsnprintf((char*)buffer, (size_t)4096, fmt, args);
va_end(args);
p = (char*)buffer;
for(;*p;p++)
--- 105,111 ----
char* p;
va_start(args, fmt);
! len = pg_vsnprintf((char*)buffer, (size_t)4096, fmt, args);
va_end(args);
p = (char*)buffer;
for(;*p;p++)
Nicolai Tufar wrote:
On Wed, 9 Mar 2005 22:51:27 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:What do you think about it? Shall I abandon FreeBSD and go ahead
Incorporating Trio?Yes, maybe just add the proper %$ handling from Trio to what we have
now.Adding proper %$ from Trio will require too much effort. I would
rather not do it. Not because I am lazy but because:1) Trio team seem to be very serious about standards, update
the library as soon as new standards come out:
<quote>
Trio fully implements the C99 (ISO/IEC 9899:1999) and UNIX98 (the
Single Unix Specification, Version 2) standards, as well as many
features from other implementations, e.g. the GNU libc and BSD4.
</quote>2) If we integrate the whole library in source code we will
not have to maintain it and will rely on Trio team for bug fixes
and updates. Integrating it will be very easy since all of the
functions begin with "trio_". I used it instead of the src/port/snrpintf.c
one and it passes regression tests under Win32 just fine.The downside is that Trio library is rather big. It is 3 .c and 6 .h
files totalling 11556 lines. Compiled it is 71224 bytes not stripped
and 56204 bytes stripped on Solaris 10 for x86, 32-bit. Even for
a shared library it will probably be too much. Trio has a lot
of string handling functions which are probably not necessary.
Would you like me to try to remove everything unnecessary from
it or we will settle with the full version?
Please see my posting about using a macro for snprintf. If the current
implementation of snprintf is enough for our existing translation users
we probably don't need to add anything more to it because snprintf will
not be exported to client applications.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
On Thu, 10 Mar 2005 16:26:47 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:
Please see my posting about using a macro for snprintf. If the current
implementation of snprintf is enough for our existing translation users
we probably don't need to add anything more to it because snprintf will
not be exported to client applications.
Oh, Bruce. It will be the best solution. I was worried about
the problems with my modifications to snprintf.c Tom Lane
pointed out. But if we really separate snprintf() used by
messages and snprintf() used by the like of
src/backend/utils/adt/int8.c then we are safe. We can claim
current release safe and I will modify src/port/snprintf.c at my
leisure later. I will try out your modifications tomorrow. It
is late here and I have a PostgreSQL class to to teach
tomorrow ;)
I still think that it is more convenient to rip off current
implementation of snprintf.c and replace it with a very much
stripped down of Trio's one. I will work on it and try to get
a patch in one week's time. Thank you all for your patience.
Best regards,
Nicolai Tufar
Show quoted text
-- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
(send "unregister YourEmailAddressHere" to majordomo@postgresql.org)
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Please see my posting about using a macro for snprintf. If the current
implementation of snprintf is enough for our existing translation users
we probably don't need to add anything more to it because snprintf will
not be exported to client applications.
The CVS-tip implementation is fundamentally broken and won't work even
for our internal uses. I've not wasted time complaining about it
because I thought we were going to replace it. If we can't find a
usable replacement then we're going to have to put a lot of effort
into fixing what's there. On the whole I think the effort would be
better spent importing someone else's solution.
regards, tom lane
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Please see my posting about using a macro for snprintf. If the current
implementation of snprintf is enough for our existing translation users
we probably don't need to add anything more to it because snprintf will
not be exported to client applications.The CVS-tip implementation is fundamentally broken and won't work even
for our internal uses. I've not wasted time complaining about it
because I thought we were going to replace it. If we can't find a
usable replacement then we're going to have to put a lot of effort
into fixing what's there. On the whole I think the effort would be
better spent importing someone else's solution.
Oh, so our existing implementation doesn't even meet our needs. OK.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Please see my posting about using a macro for snprintf. If the
current
implementation of snprintf is enough for our existing translation
users
we probably don't need to add anything more to it because snprintf
will
not be exported to client applications.
The CVS-tip implementation is fundamentally broken and won't work even
for our internal uses. I've not wasted time complaining about it
because I thought we were going to replace it. If we can't find a
usable replacement then we're going to have to put a lot of effort
into fixing what's there. On the whole I think the effort would be
better spent importing someone else's solution.Oh, so our existing implementation doesn't even meet our needs. OK.
Wasn't the issue about odd behavior of the Win32 linker choosing the wrong
vnsprintf?
pgsql@mohawksoft.com writes:
Please see my posting about using a macro for snprintf.
Wasn't the issue about odd behavior of the Win32 linker choosing the wrong
vnsprintf?
You're right, the point about the macro was to avoid linker weirdness on
Windows. We need to do that part in any case. I think Bruce confused
that issue with the one about whether our version supported %n$
adequately ... which it doesn't just yet ...
regards, tom lane
pgsql@mohawksoft.com wrote:
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Please see my posting about using a macro for snprintf. If the
current
implementation of snprintf is enough for our existing translation
users
we probably don't need to add anything more to it because snprintf
will
not be exported to client applications.
The CVS-tip implementation is fundamentally broken and won't work even
for our internal uses. I've not wasted time complaining about it
because I thought we were going to replace it. If we can't find a
usable replacement then we're going to have to put a lot of effort
into fixing what's there. On the whole I think the effort would be
better spent importing someone else's solution.Oh, so our existing implementation doesn't even meet our needs. OK.
Wasn't the issue about odd behavior of the Win32 linker choosing the wrong
vnsprintf?
Ah, but with my new patch to be applied tomorrow to use macros and
rename to pg_snprintf there no longer is any conflict with the system
versions of these functions.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Tom Lane wrote:
The CVS-tip implementation is fundamentally broken and won't work even
for our internal uses. I've not wasted time complaining about it
because I thought we were going to replace it. If we can't find a
usable replacement then we're going to have to put a lot of effort
into fixing what's there. On the whole I think the effort would be
better spent importing someone else's solution.
Bruce Momjian wrote:
Oh, so our existing implementation doesn't even meet our needs. OK.
Very well, I too, tend to think that importing some else's solution
is the way to go. Tom, have you looked at Trio? If it is fine with you too,
I will strip it to the bare minimum needed for snprintf(), vsnprintf() and
printf() by Saturday.
Regards,
Nicolai Tufar
Nicolai Tufar <ntufar@gmail.com> writes:
Very well, I too, tend to think that importing some else's solution
is the way to go. Tom, have you looked at Trio?
I have not seen it ... but if it looks reasonable to you, have a go
at it.
regards, tom lane
On Fri, 11 Mar 2005 01:14:31 -0500, Tom Lane wrote:
Nicolai Tufar <ntufar@gmail.com> writes:
Very well, I too, tend to think that importing some else's solution
is the way to go. Tom, have you looked at Trio?I have not seen it ... but if it looks reasonable to you, have a go
at it.
It looks reasonable to me. It claims to: fully implement C99 (ISO/IEC
9899:1999) and UNIX98 (the
Single Unix Specification, Version 2) standards, as well as many
features from other implementations, e.g. the GNU libc and BSD4.
I compiled and run regression tests with it used instead of
our current implementation and it worked fine under win32 and
Solaris x86. The only problem is that it is 11000 lines as
oposed to our curent implementation's 600. I will remove
everything unnecessary and submit a patch for consideration.
Regards,
Nicolai Tufar
Tom Lane wrote:
pgsql@mohawksoft.com writes:
Please see my posting about using a macro for snprintf.
Wasn't the issue about odd behavior of the Win32 linker choosing the wrong
vnsprintf?You're right, the point about the macro was to avoid linker weirdness on
Windows. We need to do that part in any case. I think Bruce confused
that issue with the one about whether our version supported %n$
adequately ... which it doesn't just yet ...
Perhaps I am reading old email in this reply but I thought I should
clarify:
Once we do:
#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__)
#define snprintf(...) pg_snprintf(__VA_ARGS__)
#define printf(...) pg_printf(__VA_ARGS__)
we also rename the functions in snprintf.c to pg_* names so there is no
longer a conflict with the system libc versions.
The macro is to prevent our snprintf from leaking out of libraries like
libpq, not to fix the win32 linker problem, which we already had fixed
by reordering the entries in the C file.
Perhaps the macro idea originally came as a fix for Win32 but it is much
larger that that now.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Nicolai Tufar wrote:
On Thu, 10 Mar 2005 16:26:47 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:Please see my posting about using a macro for snprintf. If the current
implementation of snprintf is enough for our existing translation users
we probably don't need to add anything more to it because snprintf will
not be exported to client applications.Oh, Bruce. It will be the best solution. I was worried about
the problems with my modifications to snprintf.c Tom Lane
pointed out. But if we really separate snprintf() used by
messages and snprintf() used by the like of
src/backend/utils/adt/int8.c then we are safe. We can claim
current release safe and I will modify src/port/snprintf.c at my
leisure later. I will try out your modifications tomorrow. It
is late here and I have a PostgreSQL class to to teach
tomorrow ;)I still think that it is more convenient to rip off current
implementation of snprintf.c and replace it with a very much
stripped down of Trio's one. I will work on it and try to get
a patch in one week's time. Thank you all for your patience.
I am not heading in the direction of using a different snprintf for
messages and for int8.c. I am just renaming the calls via macros so we
don't leak snprintf from libpq.
One new idea I had was to have pg_snprintf() look over the format string
and adjust the arguments to match what the format string is requesting,
remove %$ from the format string, and then pass it to the native libc
snprintf(). That might be the easiest solution for the many platforms
with a good snprintf but not %$ support.
Is that possible/easier?
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Tom Lane wrote:
pgsql@mohawksoft.com writes:
Please see my posting about using a macro for snprintf.
Wasn't the issue about odd behavior of the Win32 linker choosing the
wrong
vnsprintf?
You're right, the point about the macro was to avoid linker weirdness on
Windows. We need to do that part in any case. I think Bruce confused
that issue with the one about whether our version supported %n$
adequately ... which it doesn't just yet ...Perhaps I am reading old email in this reply but I thought I should
clarify:Once we do:
#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__)
#define snprintf(...) pg_snprintf(__VA_ARGS__)
#define printf(...) pg_printf(__VA_ARGS__)
I'm not sure that macros can have variable number of arguments on all
supported platforms. I've been burnt by this before.
pgsql@mohawksoft.com wrote:
Tom Lane wrote:
pgsql@mohawksoft.com writes:
Please see my posting about using a macro for snprintf.
Wasn't the issue about odd behavior of the Win32 linker choosing the
wrong
vnsprintf?
You're right, the point about the macro was to avoid linker weirdness on
Windows. We need to do that part in any case. I think Bruce confused
that issue with the one about whether our version supported %n$
adequately ... which it doesn't just yet ...Perhaps I am reading old email in this reply but I thought I should
clarify:Once we do:
#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__)
#define snprintf(...) pg_snprintf(__VA_ARGS__)
#define printf(...) pg_printf(__VA_ARGS__)I'm not sure that macros can have variable number of arguments on all
supported platforms. I've been burnt by this before.
The actual patch is:
+ #ifdef __GNUC__
+ #define vsnprintf(...) pg_vsnprintf(__VA_ARGS__)
+ #define snprintf(...) pg_snprintf(__VA_ARGS__)
+ #define printf(...) pg_printf(__VA_ARGS__)
+ #else
+ #define vsnprintf pg_vsnprintf
+ #define snprintf pg_snprintf
+ #define printf pg_printf
+ #endif
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Bruce Momjian <pgman@candle.pha.pa.us> writes:
I'm not sure that macros can have variable number of arguments on all
supported platforms. I've been burnt by this before.
The actual patch is:
+ #ifdef __GNUC__ + #define vsnprintf(...) pg_vsnprintf(__VA_ARGS__) + #define snprintf(...) pg_snprintf(__VA_ARGS__) + #define printf(...) pg_printf(__VA_ARGS__) + #else + #define vsnprintf pg_vsnprintf + #define snprintf pg_snprintf + #define printf pg_printf + #endif
Uh, why bother with the different approach for gcc?
Also, what happened to fprintf? We're going to need that too for
localization of the client programs.
regards, tom lane
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
I'm not sure that macros can have variable number of arguments on all
supported platforms. I've been burnt by this before.The actual patch is:
+ #ifdef __GNUC__ + #define vsnprintf(...) pg_vsnprintf(__VA_ARGS__) + #define snprintf(...) pg_snprintf(__VA_ARGS__) + #define printf(...) pg_printf(__VA_ARGS__) + #else + #define vsnprintf pg_vsnprintf + #define snprintf pg_snprintf + #define printf pg_printf + #endifUh, why bother with the different approach for gcc?
Because if we don't do that then the code above fails:
extern int pg_snprintf(char *str, size_t count, const char *fmt,...)
/* This extension allows gcc to check the format string */
__attribute__((format(printf, 3, 4)));
The issue is that the "printf" here is interpreted specially by the
compiler to mean "check arguments as printf". If the preprocessor
changes that, we get a failure. The good news is that only gcc supports
arg checking using __attribute__ and it also supports the __VA_ARGS__
macros. What I think we do lose is argument checking for non-gcc, but
this seems as close as we can get.
Also, what happened to fprintf? We're going to need that too for
localization of the client programs.
It was never there. I will add it now.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Bruce Momjian wrote:
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
I'm not sure that macros can have variable number of arguments on all
supported platforms. I've been burnt by this before.The actual patch is:
+ #ifdef __GNUC__ + #define vsnprintf(...) pg_vsnprintf(__VA_ARGS__) + #define snprintf(...) pg_snprintf(__VA_ARGS__) + #define printf(...) pg_printf(__VA_ARGS__) + #else + #define vsnprintf pg_vsnprintf + #define snprintf pg_snprintf + #define printf pg_printf + #endifUh, why bother with the different approach for gcc?
Because if we don't do that then the code above fails:
extern int pg_snprintf(char *str, size_t count, const char *fmt,...)
/* This extension allows gcc to check the format string */
__attribute__((format(printf, 3, 4)));The issue is that the "printf" here is interpreted specially by the
compiler to mean "check arguments as printf". If the preprocessor
changes that, we get a failure. The good news is that only gcc supports
arg checking using __attribute__ and it also supports the __VA_ARGS__
macros. What I think we do lose is argument checking for non-gcc, but
this seems as close as we can get.
I am adding a comment explaining why those macros are used.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
On Thu, 10 Mar 2005 19:21:41 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:
The CVS-tip implementation is fundamentally broken and won't work even
for our internal uses. I've not wasted time complaining about it
because I thought we were going to replace it. If we can't find a
usable replacement then we're going to have to put a lot of effort
into fixing what's there. On the whole I think the effort would be
better spent importing someone else's solution.Oh, so our existing implementation doesn't even meet our needs. OK.
Which made me wander why did I not aggree with
Tom Lane's suggestion to make do three passes
instead of two. Tom was right, as usual. It happened to
be much easier than I expected. The patch is attached.
Please apply.
Tom, what do you think? Will it be fine with you?
Best regards,
Nicolai
Attachments:
snprintf.difftext/x-patch; name=snprintf.diffDownload
*** ./src/port/snprintf.c.orig Sat Mar 12 01:28:49 2005
--- ./src/port/snprintf.c Sat Mar 12 01:08:30 2005
***************
*** 195,200 ****
--- 195,202 ----
int pointflag;
char func;
int realpos;
+ int longflag;
+ int longlongflag;
} *fmtpar, **fmtparptr;
/* Create enough structures to hold all arguments */
***************
*** 263,274 ****
--- 265,278 ----
realpos = position;
len = 0;
goto nextch;
+ /*
case '*':
if (pointflag)
maxwidth = va_arg(args, int);
else
len = va_arg(args, int);
goto nextch;
+ */
case '.':
pointflag = 1;
goto nextch;
***************
*** 300,315 ****
#endif
case 'u':
case 'U':
! /* fmtnum(value,base,dosign,ljust,len,zpad,&output) */
! if (longflag)
! {
! 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].fmtend = format;
fmtpar[fmtpos].numvalue = value;
--- 304,311 ----
#endif
case 'u':
case 'U':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
***************
*** 324,339 ****
break;
case 'o':
case 'O':
! /* fmtnum(value,base,dosign,ljust,len,zpad,&output) */
! if (longflag)
! {
! 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].fmtend = format;
fmtpar[fmtpos].numvalue = value;
--- 320,327 ----
break;
case 'o':
case 'O':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
***************
*** 348,364 ****
break;
case 'd':
case 'D':
! if (longflag)
! {
! 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].fmtend = format;
fmtpar[fmtpos].numvalue = value;
--- 336,343 ----
break;
case 'd':
case 'D':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
***************
*** 372,386 ****
fmtpos++;
break;
case 'x':
! if (longflag)
! {
! 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].fmtend = format;
fmtpar[fmtpos].numvalue = value;
--- 351,358 ----
fmtpos++;
break;
case 'x':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
***************
*** 394,408 ****
fmtpos++;
break;
case 'X':
! if (longflag)
! {
! 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].fmtend = format;
fmtpar[fmtpos].numvalue = value;
--- 366,373 ----
fmtpos++;
break;
case 'X':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
***************
*** 416,422 ****
fmtpos++;
break;
case 's':
- strvalue = va_arg(args, char *);
if (maxwidth > 0 || !pointflag)
{
if (pointflag && len > maxwidth)
--- 381,386 ----
***************
*** 434,440 ****
}
break;
case 'c':
- ch = va_arg(args, int);
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].charvalue = ch;
--- 398,403 ----
***************
*** 447,453 ****
case 'f':
case 'g':
case 'G':
- fvalue = va_arg(args, double);
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].fvalue = fvalue;
--- 410,415 ----
***************
*** 455,460 ****
--- 417,423 ----
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].maxwidth = maxwidth;
+ fmtpar[fmtpos].precision = maxwidth;
fmtpar[fmtpos].pointflag = pointflag;
fmtpar[fmtpos].func = FMTFLOAT;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
***************
*** 472,480 ****
}
}
performpr:
! /* shuffle pointers */
for(i = 1; i < fmtpos; i++)
fmtparptr[i] = &fmtpar[fmtpar[i].realpos];
output = buffer;
format = format_save;
while ((ch = *format++))
--- 435,471 ----
}
}
performpr:
! /* reorder pointers */
for(i = 1; i < fmtpos; i++)
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, 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;
+ }
+ }
+
+ /* do the output */
output = buffer;
format = format_save;
while ((ch = *format++))
Resubmission of yesterday's patch so that it would
cont conflict with Bruce's cvs commit. Pleas apply.
Best regards,
Nicolai.
Show quoted text
On Sat, 12 Mar 2005 01:58:15 +0200, Nicolai Tufar <ntufar@gmail.com> wrote:
On Thu, 10 Mar 2005 19:21:41 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:The CVS-tip implementation is fundamentally broken and won't work even
for our internal uses. I've not wasted time complaining about it
because I thought we were going to replace it. If we can't find a
usable replacement then we're going to have to put a lot of effort
into fixing what's there. On the whole I think the effort would be
better spent importing someone else's solution.Oh, so our existing implementation doesn't even meet our needs. OK.
Which made me wander why did I not aggree with
Tom Lane's suggestion to make do three passes
instead of two. Tom was right, as usual. It happened to
be much easier than I expected. The patch is attached.
Please apply.Tom, what do you think? Will it be fine with you?
Best regards,
Nicolai
Attachments:
snprintf.difftext/x-patch; name=snprintf.diffDownload
*** ./src/port/snprintf.c.orig Sat Mar 12 09:13:43 2005
--- ./src/port/snprintf.c Sat Mar 12 10:01:44 2005
***************
*** 195,200 ****
--- 195,202 ----
int pointflag;
char func;
int realpos;
+ int longflag;
+ int longlongflag;
} *fmtpar, **fmtparptr;
/* Create enough structures to hold all arguments */
***************
*** 264,275 ****
--- 266,279 ----
realpos = position;
len = 0;
goto nextch;
+ /*
case '*':
if (pointflag)
maxwidth = va_arg(args, int);
else
len = va_arg(args, int);
goto nextch;
+ */
case '.':
pointflag = 1;
goto nextch;
***************
*** 301,316 ****
#endif
case 'u':
case 'U':
! /* fmtnum(value,base,dosign,ljust,len,zpad,&output) */
! if (longflag)
! {
! 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].fmtend = format;
fmtpar[fmtpos].numvalue = value;
--- 305,312 ----
#endif
case 'u':
case 'U':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
***************
*** 325,340 ****
break;
case 'o':
case 'O':
! /* fmtnum(value,base,dosign,ljust,len,zpad,&output) */
! if (longflag)
! {
! 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].fmtend = format;
fmtpar[fmtpos].numvalue = value;
--- 321,328 ----
break;
case 'o':
case 'O':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
***************
*** 349,365 ****
break;
case 'd':
case 'D':
! if (longflag)
! {
! 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].fmtend = format;
fmtpar[fmtpos].numvalue = value;
--- 337,344 ----
break;
case 'd':
case 'D':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
***************
*** 373,387 ****
fmtpos++;
break;
case 'x':
! if (longflag)
! {
! 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].fmtend = format;
fmtpar[fmtpos].numvalue = value;
--- 352,359 ----
fmtpos++;
break;
case 'x':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
***************
*** 395,409 ****
fmtpos++;
break;
case 'X':
! if (longflag)
! {
! 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].fmtend = format;
fmtpar[fmtpos].numvalue = value;
--- 367,374 ----
fmtpos++;
break;
case 'X':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].numvalue = value;
***************
*** 417,423 ****
fmtpos++;
break;
case 's':
- strvalue = va_arg(args, char *);
if (maxwidth > 0 || !pointflag)
{
if (pointflag && len > maxwidth)
--- 382,387 ----
***************
*** 435,441 ****
}
break;
case 'c':
- ch = va_arg(args, int);
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].charvalue = ch;
--- 399,404 ----
***************
*** 448,454 ****
case 'f':
case 'g':
case 'G':
- fvalue = va_arg(args, double);
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].fvalue = fvalue;
--- 411,416 ----
***************
*** 474,482 ****
}
}
performpr:
! /* shuffle pointers */
for(i = 1; i < fmtpos; i++)
fmtparptr[i] = &fmtpar[fmtpar[i].realpos];
output = buffer;
format = format_save;
while ((ch = *format++))
--- 436,472 ----
}
}
performpr:
! /* reorder pointers */
for(i = 1; i < fmtpos; i++)
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, 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;
+ }
+ }
+
+ /* do the output */
output = buffer;
format = format_save;
while ((ch = *format++))
Nicolai Tufar wrote:
On Thu, 10 Mar 2005 19:21:41 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:The CVS-tip implementation is fundamentally broken and won't work even
for our internal uses. I've not wasted time complaining about it
because I thought we were going to replace it. If we can't find a
usable replacement then we're going to have to put a lot of effort
into fixing what's there. On the whole I think the effort would be
better spent importing someone else's solution.Oh, so our existing implementation doesn't even meet our needs. OK.
(Your new patch is in the queue.)
I have been thinking about our current snprintf() implementation. As I
remember, we use snprintf mostly for an snprintf that doesn't support
long long, and now those that don't support %$. I am wondering if we
should just process long long args and %$ args, and pass everything else
to the native snprintf.
In fact, one trick would be to substitute long long and %$ in the printf
format string, and then pass that to the native libc printf, with
adjustments for the printf format arguments. That might be simpler than
emulating all of snprintf.
FYI, now that we are using pg_snprintf macros the native snprintf is
available to us.
Anyway, I am sure there are some platforms that don't have vsnprint or
snprintf, but could we just say we don't support them, or emulate one of
we only have the other?
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Bruce Momjian <pgman@candle.pha.pa.us> writes:
I am wondering if we should just process long long args and %$ args,
and pass everything else to the native snprintf.
AFAICS this is a non-starter --- how will you construct the call to
snprintf? Or even vsnprintf? C doesn't provide the tools you need
to make it happen.
regards, tom lane
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
I am wondering if we should just process long long args and %$ args,
and pass everything else to the native snprintf.AFAICS this is a non-starter --- how will you construct the call to
snprintf? Or even vsnprintf? C doesn't provide the tools you need
to make it happen.
Couldn't you spin through the varargs and reconstruct a new one?
Is there no way to create a va_arg va_list structure in C?
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Bruce Momjian <pgman@candle.pha.pa.us> writes:
Is there no way to create a va_arg va_list structure in C?
Exactly. The standard lets you *read out* from such a structure,
but there's no provision for creating one on-the-fly.
regards, tom lane
I have applied a modified version of your patch, attached.
initdb will not work without %*s support, so I had to add that. Please
look over my work. I don't think i handle %*1$ but I am not even sure
what that means or if our translators would ever use such a thing. You
can probably test that better than I can.
Your patch didn't handle signed vs. unsigned va_arg values properly..
There were also maxwidth tests around 's' that I had to remove to
support %*. I think those tests are down in fmtstr too but please
check.
initdb and regression pass.
---------------------------------------------------------------------------
Nicolai Tufar wrote:
Resubmission of yesterday's patch so that it would
cont conflict with Bruce's cvs commit. Pleas apply.Best regards,
Nicolai.On Sat, 12 Mar 2005 01:58:15 +0200, Nicolai Tufar <ntufar@gmail.com> wrote:
On Thu, 10 Mar 2005 19:21:41 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:The CVS-tip implementation is fundamentally broken and won't work even
for our internal uses. I've not wasted time complaining about it
because I thought we were going to replace it. If we can't find a
usable replacement then we're going to have to put a lot of effort
into fixing what's there. On the whole I think the effort would be
better spent importing someone else's solution.Oh, so our existing implementation doesn't even meet our needs. OK.
Which made me wander why did I not aggree with
Tom Lane's suggestion to make do three passes
instead of two. Tom was right, as usual. It happened to
be much easier than I expected. The patch is attached.
Please apply.Tom, what do you think? Will it be fine with you?
Best regards,
Nicolai
[ Attachment, skipping... ]
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Attachments:
/bjm/difftext/plainDownload
Index: src/port/snprintf.c
===================================================================
RCS file: /cvsroot/pgsql/src/port/snprintf.c,v
retrieving revision 1.19
diff -c -c -r1.19 snprintf.c
*** src/port/snprintf.c 12 Mar 2005 04:00:56 -0000 1.19
--- src/port/snprintf.c 16 Mar 2005 05:46:33 -0000
***************
*** 151,170 ****
#define FMTSTR 1
#define FMTNUM 2
! #define FMTFLOAT 3
! #define FMTCHAR 4
static void
dopr(char *buffer, const char *format, va_list args, char *end)
{
int ch;
- int64 value;
- double fvalue;
int longlongflag = 0;
int longflag = 0;
int pointflag = 0;
int maxwidth = 0;
- char *strvalue;
int ljust;
int len;
int zpad;
--- 151,170 ----
#define FMTSTR 1
#define FMTNUM 2
! #define FMTNUM_U 3
! #define FMTFLOAT 4
! #define FMTCHAR 5
! #define FMTWIDTH 6
! #define FMTLEN 7
static void
dopr(char *buffer, const char *format, va_list args, char *end)
{
int ch;
int longlongflag = 0;
int longflag = 0;
int pointflag = 0;
int maxwidth = 0;
int ljust;
int len;
int zpad;
***************
*** 173,178 ****
--- 173,179 ----
const char* fmtbegin;
int fmtpos = 1;
int realpos = 0;
+ int precision;
int position;
char *output;
int percents = 1;
***************
*** 195,200 ****
--- 196,203 ----
int pointflag;
char func;
int realpos;
+ int longflag;
+ int longlongflag;
} *fmtpar, **fmtparptr;
/* Create enough structures to hold all arguments */
***************
*** 229,240 ****
longflag = longlongflag = pointflag = 0;
fmtbegin = format - 1;
realpos = 0;
! position = 0;
nextch:
ch = *format++;
switch (ch)
{
! case 0:
goto performpr;
case '-':
ljust = 1;
--- 232,243 ----
longflag = longlongflag = pointflag = 0;
fmtbegin = format - 1;
realpos = 0;
! position = precision = 0;
nextch:
ch = *format++;
switch (ch)
{
! case '\0':
goto performpr;
case '-':
ljust = 1;
***************
*** 251,274 ****
case '7':
case '8':
case '9':
! if (pointflag)
! /* could also be precision */
! maxwidth = maxwidth * 10 + ch - '0';
! else
{
len = len * 10 + ch - '0';
position = position * 10 + ch - '0';
}
goto nextch;
case '$':
realpos = position;
len = 0;
goto nextch;
case '*':
! if (pointflag)
! maxwidth = va_arg(args, int);
else
! len = va_arg(args, int);
goto nextch;
case '.':
pointflag = 1;
--- 254,282 ----
case '7':
case '8':
case '9':
! if (!pointflag)
{
len = len * 10 + ch - '0';
position = position * 10 + ch - '0';
}
+ else
+ {
+ maxwidth = maxwidth * 10 + ch - '0';
+ precision = precision * 10 + ch - '0';
+ }
goto nextch;
case '$':
realpos = position;
len = 0;
goto nextch;
case '*':
! MemSet(&fmtpar[fmtpos], 0, sizeof(fmtpar[fmtpos]));
! if (!pointflag)
! fmtpar[fmtpos].func = FMTLEN;
else
! fmtpar[fmtpos].func = FMTWIDTH;
! fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
! fmtpos++;
goto nextch;
case '.':
pointflag = 1;
***************
*** 301,368 ****
#endif
case 'u':
case 'U':
! /* fmtnum(value,base,dosign,ljust,len,zpad,&output) */
! if (longflag)
! {
! 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].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;
case 'o':
case 'O':
! /* fmtnum(value,base,dosign,ljust,len,zpad,&output) */
! if (longflag)
! {
! 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].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;
case 'd':
case 'D':
! if (longflag)
! {
! 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].fmtend = format;
- fmtpar[fmtpos].numvalue = value;
fmtpar[fmtpos].base = 10;
fmtpar[fmtpos].dosign = 1;
fmtpar[fmtpos].ljust = ljust;
--- 309,348 ----
#endif
case 'u':
case 'U':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].base = 10;
fmtpar[fmtpos].dosign = 0;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
! fmtpar[fmtpos].func = FMTNUM_U;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
break;
case 'o':
case 'O':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].base = 8;
fmtpar[fmtpos].dosign = 0;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
! fmtpar[fmtpos].func = FMTNUM_U;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
break;
case 'd':
case 'D':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].base = 10;
fmtpar[fmtpos].dosign = 1;
fmtpar[fmtpos].ljust = ljust;
***************
*** 373,444 ****
fmtpos++;
break;
case 'x':
! if (longflag)
! {
! 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].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;
case 'X':
! if (longflag)
! {
! 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].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;
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].fmtend = format;
- fmtpar[fmtpos].charvalue = ch;
fmtpar[fmtpos].func = FMTCHAR;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
--- 353,399 ----
fmtpos++;
break;
case 'x':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].base = 16;
fmtpar[fmtpos].dosign = 0;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
! fmtpar[fmtpos].func = FMTNUM_U;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
break;
case 'X':
! fmtpar[fmtpos].longflag = longflag;
! fmtpar[fmtpos].longlongflag = longlongflag;
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].base = -16;
fmtpar[fmtpos].dosign = 1;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
! fmtpar[fmtpos].func = FMTNUM_U;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
fmtpos++;
break;
case 's':
! fmtpar[fmtpos].fmtbegin = fmtbegin;
! fmtpar[fmtpos].fmtend = format;
! 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].realpos = realpos?realpos:fmtpos;
fmtpos++;
***************
*** 448,462 ****
case 'f':
case 'g':
case 'G':
- fvalue = va_arg(args, double);
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].precision = position;
fmtpar[fmtpos].pointflag = pointflag;
fmtpar[fmtpos].func = FMTFLOAT;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
--- 403,415 ----
case 'f':
case 'g':
case 'G':
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].type = ch;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].maxwidth = maxwidth;
! fmtpar[fmtpos].precision = precision;
fmtpar[fmtpos].pointflag = pointflag;
fmtpar[fmtpos].func = FMTFLOAT;
fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
***************
*** 473,494 ****
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:
--- 426,499 ----
break;
}
}
+
performpr:
! /* reorder pointers */
for(i = 1; i < fmtpos; i++)
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;
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:
***************
*** 497,502 ****
--- 502,508 ----
fmtparptr[i]->maxwidth, end, &output);
break;
case FMTNUM:
+ case FMTNUM_U:
fmtnum(fmtparptr[i]->numvalue, fmtparptr[i]->base,
fmtparptr[i]->dosign, fmtparptr[i]->ljust,
fmtparptr[i]->len, fmtparptr[i]->zpad, end, &output);
On Wed, 16 Mar 2005 01:00:21 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:
I have applied a modified version of your patch, attached.
I am so sorry, I sent untested patch again. Thank you very
much for patience in fixing it. The patch looks perfectly
fine and works under Solaris.
Under win32 I am still struggling with build environment.
In many directories link fails with "undefined reference to
`pg_snprintf'" in other it fails with "undefined reference to
`_imp__libintl_sprintf'". In yet another directory it fails with
both, like in src/interfaces/ecpg/pgtypeslib:
dlltool --export-all --output-def pgtypes.def numeric.o datetime.o
common.o dt_common.o timestamp.o interval.o pgstrcasecmp.o
dllwrap -o libpgtypes.dll --dllname libpgtypes.dll --def pgtypes.def
numeric.o datetime.o common.o dt_common.o timestamp.o interval.o
pgstrcasecmp.o -L../../../../src/port -lm
numeric.o(.text+0x19ea):numeric.c: undefined reference to
`_imp__libintl_sprintf'
datetime.o(.text+0x476):datetime.c: undefined reference to `pg_snprintf'
common.o(.text+0x1cd):common.c: undefined reference to `pg_snprintf'
common.o(.text+0x251):common.c: undefined reference to `pg_snprintf'
dt_common.o(.text+0x538):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x553):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x597):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x5d5):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x628):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x7e8):dt_common.c: more undefined references to
`_imp__libintl_sprintf' follow
c:\MinGW\bin\dllwrap.exe: c:\MinGW\bin\gcc exited with status 1
make: *** [libpgtypes.a] Error 1
Could someone with a better grasp of configure and
win32 environment check it? Aparently no one regularily
compiles source code under win32 during development cycle
these days.
Best regards,
Nicolai
Nicolai Tufar wrote:
On Wed, 16 Mar 2005 01:00:21 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:I have applied a modified version of your patch, attached.
Here is a patch that fixes the %*$ case.
FYI, I am going to pgindent snprintf.c to make it consistent so please
us CVS for your next patch.
I will work on your Win32 compile problem next.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Attachments:
/bjm/difftext/plainDownload
Index: src/port/snprintf.c
===================================================================
RCS file: /cvsroot/pgsql/src/port/snprintf.c,v
retrieving revision 1.20
diff -c -c -r1.20 snprintf.c
*** src/port/snprintf.c 16 Mar 2005 06:00:58 -0000 1.20
--- src/port/snprintf.c 16 Mar 2005 14:59:00 -0000
***************
*** 467,481 ****
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;
}
--- 467,481 ----
fmtparptr[i]->charvalue = va_arg(args, int);
break;
case FMTLEN:
! if (i + 1 < fmtpos && fmtparptr[i + 1]->func != FMTWIDTH)
! fmtparptr[i + 1]->len = va_arg(args, int);
/* For "%*.*f", use the second arg */
! if (i + 2 < fmtpos && fmtparptr[i + 1]->func == FMTWIDTH)
! fmtparptr[i + 2]->len = va_arg(args, int);
break;
case FMTWIDTH:
if (i + 1 < fmtpos)
! fmtparptr[i + 1]->maxwidth = fmtparptr[i + 1]->precision =
va_arg(args, int);
break;
}
Nicolai Tufar wrote:
On Wed, 16 Mar 2005 01:00:21 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:I have applied a modified version of your patch, attached.
I am so sorry, I sent untested patch again. Thank you very
much for patience in fixing it. The patch looks perfectly
fine and works under Solaris.
Here is another patch that adds sprintf() support, and support for '+',
'h', and fixes '%*s' support.
Applied.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Attachments:
/bjm/difftext/plainDownload
Index: src/bin/psql/command.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/command.c,v
retrieving revision 1.141
diff -c -c -r1.141 command.c
*** src/bin/psql/command.c 11 Mar 2005 17:20:34 -0000 1.141
--- src/bin/psql/command.c 16 Mar 2005 21:17:50 -0000
***************
*** 1574,1584 ****
shellName = DEFAULT_SHELL;
sys = pg_malloc(strlen(shellName) + 16);
sprintf(sys,
/* See EDITOR handling comment for an explaination */
- #ifndef WIN32
"exec %s", shellName);
#else
"%s\"%s\"%s", SYSTEMQUOTE, shellName, SYSTEMQUOTE);
#endif
result = system(sys);
--- 1574,1586 ----
shellName = DEFAULT_SHELL;
sys = pg_malloc(strlen(shellName) + 16);
+ #ifndef WIN32
sprintf(sys,
/* See EDITOR handling comment for an explaination */
"exec %s", shellName);
#else
+ sprintf(sys,
+ /* See EDITOR handling comment for an explaination */
"%s\"%s\"%s", SYSTEMQUOTE, shellName, SYSTEMQUOTE);
#endif
result = system(sys);
Index: src/include/port.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/port.h,v
retrieving revision 1.72
diff -c -c -r1.72 port.h
*** src/include/port.h 11 Mar 2005 19:13:42 -0000 1.72
--- src/include/port.h 16 Mar 2005 21:17:50 -0000
***************
*** 112,117 ****
--- 112,120 ----
extern int pg_snprintf(char *str, size_t count, const char *fmt,...)
/* This extension allows gcc to check the format string */
__attribute__((format(printf, 3, 4)));
+ extern int pg_sprintf(char *str, const char *fmt,...)
+ /* This extension allows gcc to check the format string */
+ __attribute__((format(printf, 2, 3)));
extern int pg_fprintf(FILE *stream, const char *fmt,...)
/* This extension allows gcc to check the format string */
__attribute__((format(printf, 2, 3)));
***************
*** 127,137 ****
--- 130,142 ----
#ifdef __GNUC__
#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__)
#define snprintf(...) pg_snprintf(__VA_ARGS__)
+ #define sprintf(...) pg_sprintf(__VA_ARGS__)
#define fprintf(...) pg_fprintf(__VA_ARGS__)
#define printf(...) pg_printf(__VA_ARGS__)
#else
#define vsnprintf pg_vsnprintf
#define snprintf pg_snprintf
+ #define sprintf pg_sprintf
#define fprintf pg_fprintf
#define printf pg_printf
#endif
Index: src/port/snprintf.c
===================================================================
RCS file: /cvsroot/pgsql/src/port/snprintf.c,v
retrieving revision 1.22
diff -c -c -r1.22 snprintf.c
*** src/port/snprintf.c 16 Mar 2005 15:12:18 -0000 1.22
--- src/port/snprintf.c 16 Mar 2005 21:17:51 -0000
***************
*** 67,80 ****
/*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.22 2005/03/16 15:12:18 momjian Exp $";*/
- 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_printf(const char *format,...);
static void dopr(char *buffer, const char *format, va_list args, char *end);
/* Prevent recursion */
#undef vsnprintf
#undef snprintf
#undef fprintf
#undef printf
--- 67,78 ----
/*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.22 2005/03/16 15:12:18 momjian Exp $";*/
static void dopr(char *buffer, const char *format, va_list args, char *end);
/* Prevent recursion */
#undef vsnprintf
#undef snprintf
+ #undef sprintf
#undef fprintf
#undef printf
***************
*** 104,121 ****
}
int
pg_fprintf(FILE *stream, const char *fmt,...)
{
int len;
va_list args;
! char *buffer[4096];
char *p;
va_start(args, fmt);
! len = pg_vsnprintf((char *) buffer, (size_t) 4096, fmt, args);
va_end(args);
! p = (char *) buffer;
! for (; *p; p++)
putc(*p, stream);
return len;
}
--- 102,133 ----
}
int
+ pg_sprintf(char *str, const char *fmt,...)
+ {
+ int len;
+ va_list args;
+ char buffer[4096];
+
+ va_start(args, fmt);
+ len = pg_vsnprintf(buffer, (size_t) 4096, fmt, args);
+ va_end(args);
+ /* limit output to string */
+ StrNCpy(str, buffer, (len + 1 < 4096) ? len + 1 : 4096);
+ return len;
+ }
+
+ int
pg_fprintf(FILE *stream, const char *fmt,...)
{
int len;
va_list args;
! char buffer[4096];
char *p;
va_start(args, fmt);
! len = pg_vsnprintf(buffer, (size_t) 4096, fmt, args);
va_end(args);
! for (p = buffer; *p; p++)
putc(*p, stream);
return len;
}
***************
*** 125,138 ****
{
int len;
va_list args;
! char *buffer[4096];
char *p;
va_start(args, fmt);
! len = pg_vsnprintf((char *) buffer, (size_t) 4096, fmt, args);
va_end(args);
! p = (char *) buffer;
! for (; *p; p++)
putchar(*p);
return len;
}
--- 137,150 ----
{
int len;
va_list args;
! char buffer[4096];
char *p;
va_start(args, fmt);
! len = pg_vsnprintf(buffer, (size_t) 4096, fmt, args);
va_end(args);
!
! for (p = buffer; *p; p++)
putchar(*p);
return len;
}
***************
*** 141,152 ****
* dopr(): poor man's version of doprintf
*/
! static void fmtstr(char *value, int ljust, int len, int zpad, int maxwidth,
char *end, char **output);
! static void fmtnum(int64 value, int base, int dosign, int ljust, int len,
! int zpad, char *end, char **output);
! static void fmtfloat(double value, char type, int ljust, int len,
! int precision, int pointflag, char *end, char **output);
static void dostr(char *str, int cut, char *end, char **output);
static void dopr_outch(int c, char *end, char **output);
--- 153,165 ----
* dopr(): poor man's version of doprintf
*/
! static void fmtstr(char *value, int ljust, int len, int maxwidth,
char *end, char **output);
! static void fmtnum(int64 value, int base, int dosign, int forcesign,
! int ljust, int len, int zpad, char *end, char **output);
! static void fmtfloat(double value, char type, int forcesign,
! int ljust, int len, int zpad, int precision, int pointflag, char *end,
! char **output);
static void dostr(char *str, int cut, char *end, char **output);
static void dopr_outch(int c, char *end, char **output);
***************
*** 162,174 ****
dopr(char *buffer, const char *format, va_list args, char *end)
{
int ch;
! int longlongflag = 0;
! int longflag = 0;
! int pointflag = 0;
! int maxwidth = 0;
int ljust;
int len;
int zpad;
int i;
const char *format_save;
const char *fmtbegin;
--- 175,188 ----
dopr(char *buffer, const char *format, va_list args, char *end)
{
int ch;
! int longlongflag;
! int longflag;
! int pointflag;
! int maxwidth;
int ljust;
int len;
int zpad;
+ int forcesign;
int i;
const char *format_save;
const char *fmtbegin;
***************
*** 193,198 ****
--- 207,213 ----
int maxwidth;
int base;
int dosign;
+ int forcesign;
char type;
int precision;
int pointflag;
***************
*** 230,236 ****
switch (ch)
{
case '%':
! ljust = len = zpad = maxwidth = 0;
longflag = longlongflag = pointflag = 0;
fmtbegin = format - 1;
realpos = 0;
--- 245,251 ----
switch (ch)
{
case '%':
! ljust = len = zpad = forcesign = maxwidth = 0;
longflag = longlongflag = pointflag = 0;
fmtbegin = format - 1;
realpos = 0;
***************
*** 244,249 ****
--- 259,267 ----
case '-':
ljust = 1;
goto nextch;
+ case '+':
+ forcesign = 1;
+ goto nextch;
case '0': /* set zero padding if len not set */
if (len == 0 && !pointflag)
zpad = '0';
***************
*** 289,294 ****
--- 307,315 ----
else
longflag = 1;
goto nextch;
+ case 'h':
+ /* ignore */
+ goto nextch;
#ifdef NOT_USED
/*
***************
*** 318,323 ****
--- 339,345 ----
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].base = 10;
fmtpar[fmtpos].dosign = 0;
+ fmtpar[fmtpos].forcesign = forcesign;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
***************
*** 333,338 ****
--- 355,361 ----
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].base = 8;
fmtpar[fmtpos].dosign = 0;
+ fmtpar[fmtpos].forcesign = forcesign;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
***************
*** 348,353 ****
--- 371,377 ----
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].base = 10;
fmtpar[fmtpos].dosign = 1;
+ fmtpar[fmtpos].forcesign = forcesign;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
***************
*** 362,367 ****
--- 386,392 ----
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].base = 16;
fmtpar[fmtpos].dosign = 0;
+ fmtpar[fmtpos].forcesign = forcesign;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
***************
*** 376,381 ****
--- 401,407 ----
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].base = -16;
fmtpar[fmtpos].dosign = 1;
+ fmtpar[fmtpos].forcesign = forcesign;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
fmtpar[fmtpos].zpad = zpad;
***************
*** 409,417 ****
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].type = ch;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
! fmtpar[fmtpos].maxwidth = maxwidth;
fmtpar[fmtpos].precision = precision;
fmtpar[fmtpos].pointflag = pointflag;
fmtpar[fmtpos].func = FMTFLOAT;
--- 435,444 ----
fmtpar[fmtpos].fmtbegin = fmtbegin;
fmtpar[fmtpos].fmtend = format;
fmtpar[fmtpos].type = ch;
+ fmtpar[fmtpos].forcesign = forcesign;
fmtpar[fmtpos].ljust = ljust;
fmtpar[fmtpos].len = len;
! fmtpar[fmtpos].zpad = zpad;
fmtpar[fmtpos].precision = precision;
fmtpar[fmtpos].pointflag = pointflag;
fmtpar[fmtpos].func = FMTFLOAT;
***************
*** 504,523 ****
{
case FMTSTR:
fmtstr(fmtparptr[i]->value, fmtparptr[i]->ljust,
! fmtparptr[i]->len, fmtparptr[i]->zpad,
! fmtparptr[i]->maxwidth, end, &output);
break;
case FMTNUM:
case FMTNUM_U:
fmtnum(fmtparptr[i]->numvalue, fmtparptr[i]->base,
! fmtparptr[i]->dosign, fmtparptr[i]->ljust,
! fmtparptr[i]->len, fmtparptr[i]->zpad, end, &output);
break;
case FMTFLOAT:
fmtfloat(fmtparptr[i]->fvalue, fmtparptr[i]->type,
! fmtparptr[i]->ljust, fmtparptr[i]->len,
! fmtparptr[i]->precision, fmtparptr[i]->pointflag,
! end, &output);
break;
case FMTCHAR:
dopr_outch(fmtparptr[i]->charvalue, end, &output);
--- 531,552 ----
{
case FMTSTR:
fmtstr(fmtparptr[i]->value, fmtparptr[i]->ljust,
! fmtparptr[i]->len, fmtparptr[i]->maxwidth,
! end, &output);
break;
case FMTNUM:
case FMTNUM_U:
fmtnum(fmtparptr[i]->numvalue, fmtparptr[i]->base,
! fmtparptr[i]->dosign, fmtparptr[i]->forcesign,
! fmtparptr[i]->ljust, fmtparptr[i]->len,
! fmtparptr[i]->zpad, end, &output);
break;
case FMTFLOAT:
fmtfloat(fmtparptr[i]->fvalue, fmtparptr[i]->type,
! fmtparptr[i]->forcesign, fmtparptr[i]->ljust,
! fmtparptr[i]->len, fmtparptr[i]->zpad,
! fmtparptr[i]->precision, fmtparptr[i]->pointflag,
! end, &output);
break;
case FMTCHAR:
dopr_outch(fmtparptr[i]->charvalue, end, &output);
***************
*** 545,562 ****
}
static void
! fmtstr(char *value, int ljust, int len, int zpad, int maxwidth, char *end,
char **output)
{
int padlen,
! strlen; /* amount to pad */
! if (value == 0)
value = "<NULL>";
! for (strlen = 0; value[strlen]; ++strlen); /* strlen */
! if (strlen > maxwidth && maxwidth)
! strlen = maxwidth;
! padlen = len - strlen;
if (padlen < 0)
padlen = 0;
if (ljust)
--- 574,597 ----
}
static void
! fmtstr(char *value, int ljust, int len, int maxwidth, char *end,
char **output)
{
int padlen,
! vallen; /* amount to pad */
! if (value == NULL)
value = "<NULL>";
! vallen = strlen(value);
! if (vallen > maxwidth && maxwidth)
! vallen = maxwidth;
! if (len < 0)
! {
! /* this could happen with a "*" width spec */
! ljust = 1;
! len = -len;
! }
! padlen = len - vallen;
if (padlen < 0)
padlen = 0;
if (ljust)
***************
*** 575,582 ****
}
static void
! fmtnum(int64 value, int base, int dosign, int ljust, int len, int zpad,
! char *end, char **output)
{
int signvalue = 0;
uint64 uvalue;
--- 610,617 ----
}
static void
! fmtnum(int64 value, int base, int dosign, int forcesign, int ljust,
! int len, int zpad, char *end, char **output)
{
int signvalue = 0;
uint64 uvalue;
***************
*** 597,602 ****
--- 632,639 ----
signvalue = '-';
uvalue = -value;
}
+ else if (forcesign)
+ signvalue = '+';
}
if (base < 0)
{
***************
*** 658,676 ****
}
static void
! fmtfloat(double value, char type, int ljust, int len, int precision,
! int pointflag, char *end, char **output)
{
char fmt[32];
char convert[512];
int padlen = 0; /* amount to pad */
/* we rely on regular C library's sprintf to do the basic conversion */
if (pointflag)
sprintf(fmt, "%%.%d%c", precision, type);
else
sprintf(fmt, "%%%c", type);
! sprintf(convert, fmt, value);
if (len < 0)
{
--- 695,726 ----
}
static void
! fmtfloat(double value, char type, int forcesign, int ljust,
! int len, int zpad, int precision, int pointflag, char *end,
! char **output)
{
+ int signvalue = 0;
+ double uvalue;
char fmt[32];
char convert[512];
int padlen = 0; /* amount to pad */
+ uvalue = value;
/* we rely on regular C library's sprintf to do the basic conversion */
if (pointflag)
sprintf(fmt, "%%.%d%c", precision, type);
else
sprintf(fmt, "%%%c", type);
!
! if (value < 0)
! {
! signvalue = '-';
! uvalue = -value;
! }
! else if (forcesign)
! signvalue = '+';
!
! sprintf(convert, fmt, uvalue);
if (len < 0)
{
***************
*** 684,694 ****
--- 734,760 ----
if (ljust)
padlen = -padlen;
+ if (zpad && padlen > 0)
+ {
+ if (signvalue)
+ {
+ dopr_outch(signvalue, end, output);
+ --padlen;
+ signvalue = 0;
+ }
+ while (padlen > 0)
+ {
+ dopr_outch(zpad, end, output);
+ --padlen;
+ }
+ }
while (padlen > 0)
{
dopr_outch(' ', end, output);
--padlen;
}
+ if (signvalue)
+ dopr_outch(signvalue, end, output);
dostr(convert, 0, end, output);
while (padlen < 0)
{
***************
*** 701,715 ****
dostr(char *str, int cut, char *end, char **output)
{
if (cut)
- {
while (*str && cut-- > 0)
dopr_outch(*str++, end, output);
- }
else
- {
while (*str)
dopr_outch(*str++, end, output);
- }
}
static void
--- 767,777 ----
Thanks to Andrew Dunstan, I found the cause of these link errors.
Andrew found this in libintl:
#undef snprintf
#define snprintf libintl_snprintf
extern int snprintf (char *, size_t, const char *, ...);
What is happening is that we do:
#define snprintf pg_snprintf
and then libintl.h (?) does:
#define snprintf libintl_snprintf
so the effect is:
#define pg_snprintf libintl_snprintf
In fact, in this example, the system complains about a missing X3 symbol:
#define X1 X2
#define X2 X3
int
main(int argc, char *argv[])
{
X1;
}
so the effet of the defines is:
#define X1 X3
Anyway, the reason ecpg is failing is that it is the only client-side
program that doesn't use libintl for internationalization. It is on our
TODO list to do that, but it hasn't been done yet.
However, only Win32 is seeing this failure, and only when configure
--enable-nls. I think this is because only Win32 does the redefine of
snprint and friends.
Comments?
---------------------------------------------------------------------------
Nicolai Tufar wrote:
On Wed, 16 Mar 2005 01:00:21 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:I have applied a modified version of your patch, attached.
I am so sorry, I sent untested patch again. Thank you very
much for patience in fixing it. The patch looks perfectly
fine and works under Solaris.Under win32 I am still struggling with build environment.
In many directories link fails with "undefined reference to
`pg_snprintf'" in other it fails with "undefined reference to
`_imp__libintl_sprintf'". In yet another directory it fails with
both, like in src/interfaces/ecpg/pgtypeslib:dlltool --export-all --output-def pgtypes.def numeric.o datetime.o
common.o dt_common.o timestamp.o interval.o pgstrcasecmp.o
dllwrap -o libpgtypes.dll --dllname libpgtypes.dll --def pgtypes.def
numeric.o datetime.o common.o dt_common.o timestamp.o interval.o
pgstrcasecmp.o -L../../../../src/port -lm
numeric.o(.text+0x19ea):numeric.c: undefined reference to
`_imp__libintl_sprintf'
datetime.o(.text+0x476):datetime.c: undefined reference to `pg_snprintf'
common.o(.text+0x1cd):common.c: undefined reference to `pg_snprintf'
common.o(.text+0x251):common.c: undefined reference to `pg_snprintf'
dt_common.o(.text+0x538):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x553):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x597):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x5d5):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x628):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x7e8):dt_common.c: more undefined references to
`_imp__libintl_sprintf' follow
c:\MinGW\bin\dllwrap.exe: c:\MinGW\bin\gcc exited with status 1
make: *** [libpgtypes.a] Error 1Could someone with a better grasp of configure and
win32 environment check it? Aparently no one regularily
compiles source code under win32 during development cycle
these days.Best regards,
Nicolai---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Bruce Momjian <pgman@candle.pha.pa.us> writes:
so the effect is:
#define pg_snprintf libintl_snprintf
That's not how CPP works.
In fact, in this example, the system complains about a missing X3 symbol:
#define X1 X2
#define X2 X3
In this case any occurrence of X1 replaced by X2 but then the result is
rescanned for macros and X2 is turned into X3.
--
greg
After some further digging, I think we have 3 problems.
1. On Windows gettext wants to hijack printf and friends, as below. This
strikes me as rather unfriendly behaviour by a library header file.
Anyway, mercifully libintl.h is included in our source in exactly one
spot, so I think the thing to do for this problem is a) undo that
hijacking and b) make sure any hijacking we want to do occurs after the
point where that file in included (in c.h). This causes most of the
noise, but is probably harmless, since our hijacking does in fact win
out. We need to fix the arnings, though.
2. We have multiple #defines for snprintf and vsnprintf (in port.h and
win32.h).
3. ecpg wants to use our pg*printf routines (because USE_SNPRINTF is
defined) but doesn't know where to find them.
what a mess :-(
cheers
andrew
Bruce Momjian wrote:
Show quoted text
Thanks to Andrew Dunstan, I found the cause of these link errors.
Andrew found this in libintl:#undef snprintf
#define snprintf libintl_snprintf
extern int snprintf (char *, size_t, const char *, ...);What is happening is that we do:
#define snprintf pg_snprintf
and then libintl.h (?) does:
#define snprintf libintl_snprintf
so the effect is:
#define pg_snprintf libintl_snprintf
In fact, in this example, the system complains about a missing X3 symbol:
#define X1 X2
#define X2 X3int
main(int argc, char *argv[])
{
X1;
}so the effet of the defines is:
#define X1 X3
Anyway, the reason ecpg is failing is that it is the only client-side
program that doesn't use libintl for internationalization. It is on our
TODO list to do that, but it hasn't been done yet.However, only Win32 is seeing this failure, and only when configure
--enable-nls. I think this is because only Win32 does the redefine of
snprint and friends.Comments?
---------------------------------------------------------------------------
Nicolai Tufar wrote:
On Wed, 16 Mar 2005 01:00:21 -0500 (EST), Bruce Momjian
<pgman@candle.pha.pa.us> wrote:I have applied a modified version of your patch, attached.
I am so sorry, I sent untested patch again. Thank you very
much for patience in fixing it. The patch looks perfectly
fine and works under Solaris.Under win32 I am still struggling with build environment.
In many directories link fails with "undefined reference to
`pg_snprintf'" in other it fails with "undefined reference to
`_imp__libintl_sprintf'". In yet another directory it fails with
both, like in src/interfaces/ecpg/pgtypeslib:dlltool --export-all --output-def pgtypes.def numeric.o datetime.o
common.o dt_common.o timestamp.o interval.o pgstrcasecmp.o
dllwrap -o libpgtypes.dll --dllname libpgtypes.dll --def pgtypes.def
numeric.o datetime.o common.o dt_common.o timestamp.o interval.o
pgstrcasecmp.o -L../../../../src/port -lm
numeric.o(.text+0x19ea):numeric.c: undefined reference to
`_imp__libintl_sprintf'
datetime.o(.text+0x476):datetime.c: undefined reference to `pg_snprintf'
common.o(.text+0x1cd):common.c: undefined reference to `pg_snprintf'
common.o(.text+0x251):common.c: undefined reference to `pg_snprintf'
dt_common.o(.text+0x538):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x553):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x597):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x5d5):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x628):dt_common.c: undefined reference to
`_imp__libintl_sprintf'
dt_common.o(.text+0x7e8):dt_common.c: more undefined references to
`_imp__libintl_sprintf' follow
c:\MinGW\bin\dllwrap.exe: c:\MinGW\bin\gcc exited with status 1
make: *** [libpgtypes.a] Error 1Could someone with a better grasp of configure and
win32 environment check it? Aparently no one regularily
compiles source code under win32 during development cycle
these days.Best regards,
Nicolai---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster
Andrew Dunstan wrote:
After some further digging, I think we have 3 problems.
1. On Windows gettext wants to hijack printf and friends, as below. This
strikes me as rather unfriendly behaviour by a library header file.
Anyway, mercifully libintl.h is included in our source in exactly one
spot, so I think the thing to do for this problem is a) undo that
hijacking and b) make sure any hijacking we want to do occurs after the
point where that file in included (in c.h). This causes most of the
noise, but is probably harmless, since our hijacking does in fact win
out. We need to fix the arnings, though.2. We have multiple #defines for snprintf and vsnprintf (in port.h and
win32.h).3. ecpg wants to use our pg*printf routines (because USE_SNPRINTF is
defined) but doesn't know where to find them.what a mess :-(
Based on the "mess" analysis, I decided it is better to allow libintl to
use its own snprintf() for Win32 when NLS is enabled, rather than try to
override that with our own snprintf. I have added code to configure.in
so that we don't check for arg control in native snprintf on Win32
because when we are using NLS, we are going to get their snprintf anyway
and not the native one.
Patch attached and applied.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Attachments:
/bjm/difftext/plainDownload
Index: configure
===================================================================
RCS file: /cvsroot/pgsql/configure,v
retrieving revision 1.435
diff -c -c -r1.435 configure
*** configure 5 May 2005 11:50:17 -0000 1.435
--- configure 5 May 2005 19:13:35 -0000
***************
*** 14706,14712 ****
# Force use of our snprintf if system's doesn't do arg control
# This feature is used by NLS
! if test "$enable_nls" = yes && test $pgac_need_repl_snprintf = no; then
echo "$as_me:$LINENO: checking whether printf supports argument control" >&5
echo $ECHO_N "checking whether printf supports argument control... $ECHO_C" >&6
if test "${pgac_cv_printf_arg_control+set}" = set; then
--- 14706,14718 ----
# Force use of our snprintf if system's doesn't do arg control
# This feature is used by NLS
! if test "$enable_nls" = yes &&
! test $pgac_need_repl_snprintf = no &&
! # On Win32, libintl replaces snprintf() with its own version that
! # understands arg control, so we don't need our own. In fact, it
! # also uses macros that conflict with ours, so we _can't_ use
! # our own.
! test "$PORTNAME" != "win32"; then
echo "$as_me:$LINENO: checking whether printf supports argument control" >&5
echo $ECHO_N "checking whether printf supports argument control... $ECHO_C" >&6
if test "${pgac_cv_printf_arg_control+set}" = set; then
Index: configure.in
===================================================================
RCS file: /cvsroot/pgsql/configure.in,v
retrieving revision 1.408
diff -c -c -r1.408 configure.in
*** configure.in 5 May 2005 11:50:18 -0000 1.408
--- configure.in 5 May 2005 19:13:36 -0000
***************
*** 1095,1101 ****
# Force use of our snprintf if system's doesn't do arg control
# This feature is used by NLS
! if test "$enable_nls" = yes && test $pgac_need_repl_snprintf = no; then
PGAC_FUNC_PRINTF_ARG_CONTROL
if test $pgac_cv_printf_arg_control != yes ; then
pgac_need_repl_snprintf=yes
--- 1095,1107 ----
# Force use of our snprintf if system's doesn't do arg control
# This feature is used by NLS
! if test "$enable_nls" = yes &&
! test $pgac_need_repl_snprintf = no &&
! # On Win32, libintl replaces snprintf() with its own version that
! # understands arg control, so we don't need our own. In fact, it
! # also uses macros that conflict with ours, so we _can't_ use
! # our own.
! test "$PORTNAME" != "win32"; then
PGAC_FUNC_PRINTF_ARG_CONTROL
if test $pgac_cv_printf_arg_control != yes ; then
pgac_need_repl_snprintf=yes