Thread: Re: [HACKERS] snprintf() argument reordering not working under Windows
Nicolai Tufar wrote: > Greetings, > > Last April we have made some changes to src/ports/snprintf.c so that it > would support argument reordering like %2$s, %1$d and such on > platforms where original snprintf() does not support it, like Windows, > HP-UX or NetBSD. Sure, I remember. So glad you returned at this time. I found a design limitation in that file yesterday. It can not output more then 4096 characters, and there are some cases with NUMERIC that try to output more than that. For example: SELECT pow(10::numeric, 10000) + 1; should show a '1' at the end of the number, but with the existing code you will just see 4095 0's and no more. I am attaching the new snprintf.c and the patch itself for your review. The change is to pass 'stream' down into the routines and output to the FILE* right from inside the routine, rather than using a string. This fixes the problem. I am also thinking of modifying the code so if we are using snprintf.c only because we need positional parameter control, we check for '$' in the string and only use snprintf.c in those cases. > NLS messages of some languages, like Turkish, rely heavily on argument > reordering because of the language structure. In 8.1 Turkish messages > in Windows version are all broken because argument reordering is not there. Really? I have not heard any report of that but this is new code in 8.1. > I examined commit logs and came to conclusion that src/port/snprintf.c > is not included in server when compiling under Windows because of change > to src/port/Makefile made in revision 1.28 by Bruce Momjian. See here: > > http://developer.postgresql.org/cvsweb.cgi/pgsql/src/port/Makefile > > Comment to the commit says: > `No server version of snprintf needed, so remove Makefile rule.' > In fact I think we need snprintf in server because NLS messages are > printed by the server. Actually, that changes means that there was nothing backend-specific in snprintf.c so we don't need a _special_ version for the backend. The real change not to use snprintf.c on Win32 is in configure.in with this comment: # 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 fi fi Here is the commit: revision 1.409 date: 2005/05/05 19:15:54; author: momjian; state: Exp; lines: +8 -2 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. So, I think it was Magnus who said that Win32 didn' need and couldn't use our snprintf. Magnus, any ideas? -- 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 /* * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "c.h" #ifndef WIN32 #include <sys/ioctl.h> #endif #include <sys/param.h> /* ** SNPRINTF, VSNPRINT -- counted versions of printf ** ** These versions have been grabbed off the net. They have been ** cleaned up to compile properly and support for .precision and ** %lx has been added. */ /************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 * A bombproof version of doprnt (dopr) included. * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point. (now it does ... tgl) * * snprintf() is used instead of sprintf() as it does limit checks * 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.29 2005/10/15 02:49:51 momjian Exp $";*/ static int dopr(FILE *stream, char *buffer, const char *format, va_list args, char *end); /* Prevent recursion */ #undef vsnprintf #undef snprintf #undef sprintf #undef fprintf #undef printf static int pg_fvsnprintf(FILE *stream, char *str, size_t count, const char *fmt, va_list args) { char *end = NULL; int len; if (str) { str[0] = '\0'; end = str + count - 1; } len = dopr(stream, str, fmt, args, end); if (str && count > 0) end[0] = '\0'; return len; } int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args) { return pg_fvsnprintf(NULL, str, count, fmt, args); } int pg_snprintf(char *str, size_t count, const char *fmt,...) { int len; va_list args; va_start(args, fmt); len = pg_fvsnprintf(NULL, str, count, fmt, args); va_end(args); return len; } int pg_sprintf(char *str, const char *fmt,...) { int len; va_list args; char buffer[8192]; /* arbitrary limit */ va_start(args, fmt); len = pg_fvsnprintf(NULL, buffer, (size_t) 4096, fmt, args); va_end(args); /* limit output to string */ StrNCpy(str, buffer, (len + 1 < 8192) ? len + 1 : 8192); return len; } int pg_fprintf(FILE *stream, const char *fmt,...) { int len; va_list args; va_start(args, fmt); len = pg_fvsnprintf(stream, NULL, 0, fmt, args); va_end(args); return len; } int pg_printf(const char *fmt,...) { int len; va_list args; va_start(args, fmt); len = pg_fvsnprintf(stdout, NULL, 0, fmt, args); va_end(args); return len; } static int adjust_sign(int is_negative, int forcesign, int *signvalue); static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen); static void leading_pad(int zpad, int *signvalue, int *padlen, char *end, char **output, FILE *stream, int *outlen); static void trailing_pad(int *padlen, char *end, char **output, FILE *stream, int *outlen); static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, char *end, char **output, FILE *stream, int *outlen); static void fmtint(int64 value, int base, int dosign, int forcesign, int leftjust, int minlen, int zpad, char *end, char **output, FILE *stream, int *outlen); static void fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, char *end, char **output, FILE *stream, int *outlen); static void dostr(char *str, int cut, char *end, char **output, FILE *stream, int *outlen); static void dopr_outch(int c, char *end, char **output, FILE *stream, int *outlen); #define FMTSTR 1 #define FMTNUM 2 #define FMTNUM_U 3 #define FMTFLOAT 4 #define FMTCHAR 5 #define FMTWIDTH 6 #define FMTLEN 7 /* * dopr(): poor man's version of doprintf */ static int dopr(FILE *stream, char *buffer, const char *format, va_list args, char *end) { int ch; int longlongflag; int longflag; int pointflag; int maxwidth; int leftjust; int minlen; int zpad; int forcesign; int i; const char *format_save; const char *fmtbegin; int fmtpos = 1; int realpos = 0; int precision; int position; char *output; int nargs = 1; int outlen = 0; const char *p; struct fmtpar { const char *fmtbegin; const char *fmtend; void *value; int64 numvalue; double fvalue; int charvalue; int leftjust; int minlen; int zpad; int maxwidth; int base; int dosign; int forcesign; char type; int precision; int pointflag; char func; int realpos; int longflag; int longlongflag; } *fmtpar, **fmtparptr; /* * Create enough structures to hold all arguments. This overcounts, eg * not all '*' characters are necessarily arguments, but it's not worth * being exact. */ for (p = format; *p != '\0'; p++) if (*p == '%' || *p == '*') nargs++; /* Need to use malloc() because memory system might not be started yet. */ if ((fmtpar = malloc(sizeof(struct fmtpar) * nargs)) == NULL) { fprintf(stderr, _("out of memory\n")); exit(1); } if ((fmtparptr = malloc(sizeof(struct fmtpar *) * nargs)) == NULL) { fprintf(stderr, _("out of memory\n")); exit(1); } format_save = format; output = buffer; while ((ch = *format++)) { if (ch == '%') { leftjust = minlen = zpad = forcesign = maxwidth = 0; longflag = longlongflag = pointflag = 0; fmtbegin = format - 1; realpos = 0; position = precision = 0; nextch: ch = *format++; switch (ch) { case '\0': goto performpr; case '-': leftjust = 1; goto nextch; case '+': forcesign = 1; goto nextch; case '0': /* set zero padding if minlen not set */ if (minlen == 0 && !pointflag) zpad = '0'; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!pointflag) { minlen = minlen * 10 + ch - '0'; position = position * 10 + ch - '0'; } else { maxwidth = maxwidth * 10 + ch - '0'; precision = precision * 10 + ch - '0'; } goto nextch; case '$': realpos = position; minlen = 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; goto nextch; case 'l': if (longflag) longlongflag = 1; else longflag = 1; goto nextch; case 'h': /* ignore */ goto nextch; #ifdef NOT_USED /* * We might export this to client apps so we should * support 'qd' and 'I64d'(MinGW) also in case the * native version does. */ case 'q': longlongflag = 1; longflag = 1; goto nextch; case 'I': if (*format == '6' && *(format + 1) == '4') { format += 2; longlongflag = 1; longflag = 1; goto nextch; } break; #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].forcesign = forcesign; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; 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].forcesign = forcesign; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; 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].forcesign = forcesign; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].func = FMTNUM; 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 = 0; fmtpar[fmtpos].forcesign = forcesign; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; 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].forcesign = forcesign; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; 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].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; 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++; break; case 'e': case 'E': case 'f': case 'g': case 'G': fmtpar[fmtpos].fmtbegin = fmtbegin; fmtpar[fmtpos].fmtend = format; fmtpar[fmtpos].type = ch; fmtpar[fmtpos].forcesign = forcesign; fmtpar[fmtpos].leftjust = leftjust; fmtpar[fmtpos].minlen = minlen; fmtpar[fmtpos].zpad = zpad; fmtpar[fmtpos].precision = precision; fmtpar[fmtpos].pointflag = pointflag; fmtpar[fmtpos].func = FMTFLOAT; fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos; fmtpos++; break; case '%': 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: { int minlen = va_arg(args, int); int leftjust = 0; if (minlen < 0) { minlen = -minlen; leftjust = 1; } if (i + 1 < fmtpos && fmtparptr[i + 1]->func != FMTWIDTH) { fmtparptr[i + 1]->minlen = minlen; fmtparptr[i + 1]->leftjust |= leftjust; } /* For "%*.*f", use the second arg */ if (i + 2 < fmtpos && fmtparptr[i + 1]->func == FMTWIDTH) { fmtparptr[i + 2]->minlen = minlen; fmtparptr[i + 2]->leftjust |= leftjust; } } break; case FMTWIDTH: if (i + 1 < fmtpos) fmtparptr[i + 1]->maxwidth = fmtparptr[i + 1]->precision = va_arg(args, int); break; } } /* do the output */ output = buffer; format = format_save; while ((ch = *format++)) { bool skip_output = false; for (i = 1; i < fmtpos; i++) { if (ch == '%' && *format == '%') { format++; continue; } if (fmtpar[i].fmtbegin == format - 1) { switch (fmtparptr[i]->func) { case FMTSTR: fmtstr(fmtparptr[i]->value, fmtparptr[i]->leftjust, fmtparptr[i]->minlen, fmtparptr[i]->maxwidth, end, (output) ? &output : NULL, stream, &outlen); break; case FMTNUM: case FMTNUM_U: fmtint(fmtparptr[i]->numvalue, fmtparptr[i]->base, fmtparptr[i]->dosign, fmtparptr[i]->forcesign, fmtparptr[i]->leftjust, fmtparptr[i]->minlen, fmtparptr[i]->zpad, end, (output) ? &output : NULL, stream, &outlen); break; case FMTFLOAT: fmtfloat(fmtparptr[i]->fvalue, fmtparptr[i]->type, fmtparptr[i]->forcesign, fmtparptr[i]->leftjust, fmtparptr[i]->minlen, fmtparptr[i]->zpad, fmtparptr[i]->precision, fmtparptr[i]->pointflag, end, (output) ? &output : NULL, stream, &outlen); break; case FMTCHAR: dopr_outch(fmtparptr[i]->charvalue, end, (output) ? &output : NULL, stream, &outlen); break; } format = fmtpar[i].fmtend; skip_output = true; break; } } if (!skip_output) dopr_outch(ch, end, (output) ? &output : NULL, stream, &outlen); } if (output) *output = '\0'; free(fmtpar); free(fmtparptr); return outlen; } static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, char *end, char **output, FILE *stream, int *outlen) { int padlen, vallen; /* amount to pad */ if (value == NULL) value = "<NULL>"; vallen = strlen(value); if (maxwidth && vallen > maxwidth) vallen = maxwidth; adjust_padlen(minlen, vallen, leftjust, &padlen); while (padlen > 0) { dopr_outch(' ', end, output, stream, outlen); --padlen; } dostr(value, maxwidth, end, output, stream, outlen); trailing_pad(&padlen, end, output, stream, outlen); } static void fmtint(int64 value, int base, int dosign, int forcesign, int leftjust, int minlen, int zpad, char *end, char **output, FILE *stream, int *outlen) { int signvalue = 0; char convert[64]; int vallen = 0; int padlen = 0; /* amount to pad */ int caps = 0; /* Handle +/- and %X (uppercase hex) */ if (dosign && adjust_sign((value < 0), forcesign, &signvalue)) value = -value; if (base < 0) { caps = 1; base = -base; } /* make integer string */ do { convert[vallen++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") [value % (unsigned) base]; value = (value / (unsigned) base); } while (value); convert[vallen] = 0; adjust_padlen(minlen, vallen, leftjust, &padlen); leading_pad(zpad, &signvalue, &padlen, end, output, stream, outlen); while (vallen > 0) dopr_outch(convert[--vallen], end, output, stream, outlen); trailing_pad(&padlen, end, output, stream, outlen); } static void fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, char *end, char **output, FILE *stream, int *outlen) { int signvalue = 0; int vallen; 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); if (adjust_sign((value < 0), forcesign, &signvalue)) value = -value; vallen = sprintf(convert, fmt, value); adjust_padlen(minlen, vallen, leftjust, &padlen); leading_pad(zpad, &signvalue, &padlen, end, output, stream, outlen); dostr(convert, 0, end, output, stream, outlen); trailing_pad(&padlen, end, output, stream, outlen); } static void dostr(char *str, int cut, char *end, char **output, FILE *stream, int *outlen) { if (cut) while (*str && cut-- > 0) dopr_outch(*str++, end, output, stream, outlen); else while (*str) dopr_outch(*str++, end, output, stream, outlen); } static void dopr_outch(int c, char *end, char **output, FILE *stream, int *outlen) { #ifdef NOT_USED if (iscntrl((unsigned char) c) && c != '\n' && c != '\t') { c = '@' + (c & 0x1F); if (output) { if (end == 0 || *output < end) { *(*output)++ = '^'; (*outlen)++; } } else { putc(c, stream); (*outlen)++; } } #endif if (output) { if (end == 0 || *output < end) { *(*output)++ = c; (*outlen)++; } } else { putc(c, stream); (*outlen)++; } } static int adjust_sign(int is_negative, int forcesign, int *signvalue) { if (is_negative) { *signvalue = '-'; return true; } else if (forcesign) *signvalue = '+'; return false; } static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen) { *padlen = minlen - vallen; if (*padlen < 0) *padlen = 0; if (leftjust) *padlen = -*padlen; } static void leading_pad(int zpad, int *signvalue, int *padlen, char *end, char **output, FILE *stream, int *outlen) { if (*padlen > 0 && zpad) { if (*signvalue) { dopr_outch(*signvalue, end, output, stream, outlen); --*padlen; *signvalue = 0; } while (*padlen > 0) { dopr_outch(zpad, end, output, stream, outlen); --*padlen; } } while (*padlen > 0 + (*signvalue != 0)) { dopr_outch(' ', end, output, stream, outlen); --*padlen; } if (*signvalue) { dopr_outch(*signvalue, end, output, stream, outlen); if (*padlen > 0) --* padlen; if (padlen < 0) ++padlen; } } static void trailing_pad(int *padlen, char *end, char **output, FILE *stream, int *outlen) { while (*padlen < 0) { dopr_outch(' ', end, output, stream, outlen); ++*padlen; } } Index: src/port/snprintf.c =================================================================== RCS file: /cvsroot/pgsql/src/port/snprintf.c,v retrieving revision 1.29 diff -c -c -r1.29 snprintf.c *** src/port/snprintf.c 15 Oct 2005 02:49:51 -0000 1.29 --- src/port/snprintf.c 3 Dec 2005 05:01:16 -0000 *************** *** 64,70 **** /*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.29 2005/10/15 02:49:51 momjian Exp $";*/ ! static void dopr(char *buffer, const char *format, va_list args, char *end); /* Prevent recursion */ #undef vsnprintf --- 64,70 ---- /*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.29 2005/10/15 02:49:51 momjian Exp $";*/ ! static int dopr(FILE *stream, char *buffer, const char *format, va_list args, char *end); /* Prevent recursion */ #undef vsnprintf *************** *** 73,89 **** #undef fprintf #undef printf ! int ! pg_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); } int --- 73,100 ---- #undef fprintf #undef printf ! ! static int ! pg_fvsnprintf(FILE *stream, char *str, size_t count, const char *fmt, va_list args) { ! char *end = NULL; ! int len; ! if (str) ! { ! str[0] = '\0'; ! end = str + count - 1; ! } ! len = dopr(stream, str, fmt, args, end); ! if (str && count > 0) end[0] = '\0'; ! return len; ! } ! ! int ! pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args) ! { ! return pg_fvsnprintf(NULL, str, count, fmt, args); } int *************** *** 93,99 **** va_list args; va_start(args, fmt); ! len = pg_vsnprintf(str, count, fmt, args); va_end(args); return len; } --- 104,110 ---- va_list args; va_start(args, fmt); ! len = pg_fvsnprintf(NULL, str, count, fmt, args); va_end(args); return len; } *************** *** 103,115 **** { 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; } --- 114,126 ---- { int len; va_list args; ! char buffer[8192]; /* arbitrary limit */ va_start(args, fmt); ! len = pg_fvsnprintf(NULL, buffer, (size_t) 4096, fmt, args); va_end(args); /* limit output to string */ ! StrNCpy(str, buffer, (len + 1 < 8192) ? len + 1 : 8192); return len; } *************** *** 118,131 **** { 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; } --- 129,138 ---- { int len; va_list args; va_start(args, fmt); ! len = pg_fvsnprintf(stream, NULL, 0, fmt, args); va_end(args); return len; } *************** *** 134,166 **** { 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; } static int adjust_sign(int is_negative, int forcesign, int *signvalue); static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen); static void leading_pad(int zpad, int *signvalue, int *padlen, char *end, ! char **output); ! static void trailing_pad(int *padlen, char *end, char **output); static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, ! char *end, char **output); static void fmtint(int64 value, int base, int dosign, int forcesign, ! int leftjust, int minlen, int zpad, char *end, char **output); static void fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, 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); #define FMTSTR 1 #define FMTNUM 2 --- 141,172 ---- { int len; va_list args; va_start(args, fmt); ! len = pg_fvsnprintf(stdout, NULL, 0, fmt, args); va_end(args); return len; } static int adjust_sign(int is_negative, int forcesign, int *signvalue); static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen); static void leading_pad(int zpad, int *signvalue, int *padlen, char *end, ! char **output, FILE *stream, int *outlen); ! static void trailing_pad(int *padlen, char *end, char **output, ! FILE *stream, int *outlen); static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, ! char *end, char **output, FILE *stream, int *outlen); static void fmtint(int64 value, int base, int dosign, int forcesign, ! int leftjust, int minlen, int zpad, char *end, char **output, ! FILE *stream, int *outlen); static void fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, char *end, ! char **output, FILE *stream, int *outlen); ! static void dostr(char *str, int cut, char *end, char **output, FILE *stream, ! int *outlen); ! static void dopr_outch(int c, char *end, char **output, FILE *stream, int *outlen); #define FMTSTR 1 #define FMTNUM 2 *************** *** 174,181 **** * dopr(): poor man's version of doprintf */ ! static void ! dopr(char *buffer, const char *format, va_list args, char *end) { int ch; int longlongflag; --- 180,187 ---- * dopr(): poor man's version of doprintf */ ! static int ! dopr(FILE *stream, char *buffer, const char *format, va_list args, char *end) { int ch; int longlongflag; *************** *** 195,200 **** --- 201,207 ---- int position; char *output; int nargs = 1; + int outlen = 0; const char *p; struct fmtpar { *************** *** 246,463 **** output = buffer; while ((ch = *format++)) { ! switch (ch) { ! case '%': ! leftjust = minlen = zpad = forcesign = maxwidth = 0; ! longflag = longlongflag = pointflag = 0; ! fmtbegin = format - 1; ! realpos = 0; ! position = precision = 0; ! nextch: ! ch = *format++; ! switch (ch) ! { ! case '\0': ! goto performpr; ! case '-': ! leftjust = 1; ! goto nextch; ! case '+': ! forcesign = 1; ! goto nextch; ! case '0': /* set zero padding if minlen not set */ ! if (minlen == 0 && !pointflag) ! zpad = '0'; ! case '1': ! case '2': ! case '3': ! case '4': ! case '5': ! case '6': ! case '7': ! case '8': ! case '9': ! if (!pointflag) ! { ! minlen = minlen * 10 + ch - '0'; ! position = position * 10 + ch - '0'; ! } ! else ! { ! maxwidth = maxwidth * 10 + ch - '0'; ! precision = precision * 10 + ch - '0'; ! } ! goto nextch; ! case '$': ! realpos = position; ! minlen = 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; ! goto nextch; ! case 'l': ! if (longflag) ! longlongflag = 1; ! else ! longflag = 1; ! goto nextch; ! case 'h': ! /* ignore */ ! goto nextch; #ifdef NOT_USED ! /* ! * We might export this to client apps so we should ! * support 'qd' and 'I64d'(MinGW) also in case the ! * native version does. ! */ ! case 'q': longlongflag = 1; longflag = 1; goto nextch; ! case 'I': ! if (*format == '6' && *(format + 1) == '4') ! { ! format += 2; ! longlongflag = 1; ! longflag = 1; ! goto nextch; ! } ! break; #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].forcesign = forcesign; ! fmtpar[fmtpos].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! 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].forcesign = forcesign; ! fmtpar[fmtpos].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! 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].forcesign = forcesign; ! fmtpar[fmtpos].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! fmtpar[fmtpos].zpad = zpad; ! fmtpar[fmtpos].func = FMTNUM; ! 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 = 0; ! fmtpar[fmtpos].forcesign = forcesign; ! fmtpar[fmtpos].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! 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].forcesign = forcesign; ! fmtpar[fmtpos].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! 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].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! 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++; ! break; ! case 'e': ! case 'E': ! case 'f': ! case 'g': ! case 'G': ! fmtpar[fmtpos].fmtbegin = fmtbegin; ! fmtpar[fmtpos].fmtend = format; ! fmtpar[fmtpos].type = ch; ! fmtpar[fmtpos].forcesign = forcesign; ! fmtpar[fmtpos].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! fmtpar[fmtpos].zpad = zpad; ! fmtpar[fmtpos].precision = precision; ! fmtpar[fmtpos].pointflag = pointflag; ! fmtpar[fmtpos].func = FMTFLOAT; ! fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos; ! fmtpos++; ! break; ! case '%': ! break; ! default: ! dostr("???????", 0, end, &output); ! } ! break; ! default: ! dopr_outch(ch, end, &output); ! break; } } --- 253,463 ---- output = buffer; while ((ch = *format++)) { ! if (ch == '%') { ! leftjust = minlen = zpad = forcesign = maxwidth = 0; ! longflag = longlongflag = pointflag = 0; ! fmtbegin = format - 1; ! realpos = 0; ! position = precision = 0; ! nextch: ! ch = *format++; ! switch (ch) ! { ! case '\0': ! goto performpr; ! case '-': ! leftjust = 1; ! goto nextch; ! case '+': ! forcesign = 1; ! goto nextch; ! case '0': /* set zero padding if minlen not set */ ! if (minlen == 0 && !pointflag) ! zpad = '0'; ! case '1': ! case '2': ! case '3': ! case '4': ! case '5': ! case '6': ! case '7': ! case '8': ! case '9': ! if (!pointflag) ! { ! minlen = minlen * 10 + ch - '0'; ! position = position * 10 + ch - '0'; ! } ! else ! { ! maxwidth = maxwidth * 10 + ch - '0'; ! precision = precision * 10 + ch - '0'; ! } ! goto nextch; ! case '$': ! realpos = position; ! minlen = 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; ! goto nextch; ! case 'l': ! if (longflag) ! longlongflag = 1; ! else ! longflag = 1; ! goto nextch; ! case 'h': ! /* ignore */ ! goto nextch; #ifdef NOT_USED ! /* ! * We might export this to client apps so we should ! * support 'qd' and 'I64d'(MinGW) also in case the ! * native version does. ! */ ! case 'q': ! longlongflag = 1; ! longflag = 1; ! goto nextch; ! case 'I': ! if (*format == '6' && *(format + 1) == '4') ! { ! format += 2; longlongflag = 1; longflag = 1; goto nextch; ! } ! break; #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].forcesign = forcesign; ! fmtpar[fmtpos].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! 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].forcesign = forcesign; ! fmtpar[fmtpos].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! 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].forcesign = forcesign; ! fmtpar[fmtpos].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! fmtpar[fmtpos].zpad = zpad; ! fmtpar[fmtpos].func = FMTNUM; ! 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 = 0; ! fmtpar[fmtpos].forcesign = forcesign; ! fmtpar[fmtpos].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! 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].forcesign = forcesign; ! fmtpar[fmtpos].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! 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].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! 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++; ! break; ! case 'e': ! case 'E': ! case 'f': ! case 'g': ! case 'G': ! fmtpar[fmtpos].fmtbegin = fmtbegin; ! fmtpar[fmtpos].fmtend = format; ! fmtpar[fmtpos].type = ch; ! fmtpar[fmtpos].forcesign = forcesign; ! fmtpar[fmtpos].leftjust = leftjust; ! fmtpar[fmtpos].minlen = minlen; ! fmtpar[fmtpos].zpad = zpad; ! fmtpar[fmtpos].precision = precision; ! fmtpar[fmtpos].pointflag = pointflag; ! fmtpar[fmtpos].func = FMTFLOAT; ! fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos; ! fmtpos++; ! break; ! case '%': ! break; ! } } } *************** *** 538,543 **** --- 538,545 ---- format = format_save; while ((ch = *format++)) { + bool skip_output = false; + for (i = 1; i < fmtpos; i++) { if (ch == '%' && *format == '%') *************** *** 552,596 **** case FMTSTR: fmtstr(fmtparptr[i]->value, fmtparptr[i]->leftjust, fmtparptr[i]->minlen, fmtparptr[i]->maxwidth, ! end, &output); break; case FMTNUM: case FMTNUM_U: fmtint(fmtparptr[i]->numvalue, fmtparptr[i]->base, fmtparptr[i]->dosign, fmtparptr[i]->forcesign, fmtparptr[i]->leftjust, fmtparptr[i]->minlen, ! fmtparptr[i]->zpad, end, &output); break; case FMTFLOAT: fmtfloat(fmtparptr[i]->fvalue, fmtparptr[i]->type, fmtparptr[i]->forcesign, fmtparptr[i]->leftjust, fmtparptr[i]->minlen, fmtparptr[i]->zpad, fmtparptr[i]->precision, fmtparptr[i]->pointflag, ! end, &output); break; case FMTCHAR: ! dopr_outch(fmtparptr[i]->charvalue, end, &output); break; } format = fmtpar[i].fmtend; ! goto nochar; } } ! dopr_outch(ch, end, &output); ! nochar: ! /* nothing */ ! ; /* semicolon required because a goto has to be ! * attached to a statement */ } ! *output = '\0'; free(fmtpar); free(fmtparptr); } static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, char *end, ! char **output) { int padlen, vallen; /* amount to pad */ --- 554,601 ---- case FMTSTR: fmtstr(fmtparptr[i]->value, fmtparptr[i]->leftjust, fmtparptr[i]->minlen, fmtparptr[i]->maxwidth, ! end, (output) ? &output : NULL, stream, &outlen); break; case FMTNUM: case FMTNUM_U: fmtint(fmtparptr[i]->numvalue, fmtparptr[i]->base, fmtparptr[i]->dosign, fmtparptr[i]->forcesign, fmtparptr[i]->leftjust, fmtparptr[i]->minlen, ! fmtparptr[i]->zpad, end, ! (output) ? &output : NULL, stream, &outlen); break; case FMTFLOAT: fmtfloat(fmtparptr[i]->fvalue, fmtparptr[i]->type, fmtparptr[i]->forcesign, fmtparptr[i]->leftjust, fmtparptr[i]->minlen, fmtparptr[i]->zpad, fmtparptr[i]->precision, fmtparptr[i]->pointflag, ! end, (output) ? &output : NULL, stream, &outlen); break; case FMTCHAR: ! dopr_outch(fmtparptr[i]->charvalue, end, ! (output) ? &output : NULL, stream, &outlen); break; } format = fmtpar[i].fmtend; ! skip_output = true; ! break; } } ! if (!skip_output) ! dopr_outch(ch, end, (output) ? &output : NULL, stream, &outlen); } ! if (output) ! *output = '\0'; free(fmtpar); free(fmtparptr); + + return outlen; } static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, char *end, ! char **output, FILE *stream, int *outlen) { int padlen, vallen; /* amount to pad */ *************** *** 606,622 **** while (padlen > 0) { ! dopr_outch(' ', end, output); --padlen; } ! dostr(value, maxwidth, end, output); ! trailing_pad(&padlen, end, output); } static void fmtint(int64 value, int base, int dosign, int forcesign, int leftjust, ! int minlen, int zpad, char *end, char **output) { int signvalue = 0; char convert[64]; --- 611,628 ---- while (padlen > 0) { ! dopr_outch(' ', end, output, stream, outlen); --padlen; } ! dostr(value, maxwidth, end, output, stream, outlen); ! trailing_pad(&padlen, end, output, stream, outlen); } static void fmtint(int64 value, int base, int dosign, int forcesign, int leftjust, ! int minlen, int zpad, char *end, char **output, FILE *stream, ! int *outlen) { int signvalue = 0; char convert[64]; *************** *** 644,661 **** adjust_padlen(minlen, vallen, leftjust, &padlen); ! leading_pad(zpad, &signvalue, &padlen, end, output); while (vallen > 0) ! dopr_outch(convert[--vallen], end, output); ! trailing_pad(&padlen, end, output); } static void fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, char *end, ! char **output) { int signvalue = 0; int vallen; --- 650,667 ---- adjust_padlen(minlen, vallen, leftjust, &padlen); ! leading_pad(zpad, &signvalue, &padlen, end, output, stream, outlen); while (vallen > 0) ! dopr_outch(convert[--vallen], end, output, stream, outlen); ! trailing_pad(&padlen, end, output, stream, outlen); } static void fmtfloat(double value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, char *end, ! char **output, FILE *stream, int *outlen) { int signvalue = 0; int vallen; *************** *** 676,712 **** adjust_padlen(minlen, vallen, leftjust, &padlen); ! leading_pad(zpad, &signvalue, &padlen, end, output); ! dostr(convert, 0, end, output); ! trailing_pad(&padlen, end, output); } static void ! 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 ! dopr_outch(int c, char *end, char **output) { #ifdef NOT_USED if (iscntrl((unsigned char) c) && c != '\n' && c != '\t') { c = '@' + (c & 0x1F); ! if (end == 0 || *output < end) ! *(*output)++ = '^'; } #endif ! if (end == 0 || *output < end) ! *(*output)++ = c; } --- 682,740 ---- adjust_padlen(minlen, vallen, leftjust, &padlen); ! leading_pad(zpad, &signvalue, &padlen, end, output, stream, outlen); ! dostr(convert, 0, end, output, stream, outlen); ! trailing_pad(&padlen, end, output, stream, outlen); } static void ! dostr(char *str, int cut, char *end, char **output, FILE *stream, int *outlen) { if (cut) while (*str && cut-- > 0) ! dopr_outch(*str++, end, output, stream, outlen); else while (*str) ! dopr_outch(*str++, end, output, stream, outlen); } static void ! dopr_outch(int c, char *end, char **output, FILE *stream, int *outlen) { #ifdef NOT_USED if (iscntrl((unsigned char) c) && c != '\n' && c != '\t') { c = '@' + (c & 0x1F); ! if (output) ! { ! if (end == 0 || *output < end) ! { ! *(*output)++ = '^'; ! (*outlen)++; ! } ! } ! else ! { ! putc(c, stream); ! (*outlen)++; ! } } #endif ! if (output) ! { ! if (end == 0 || *output < end) ! { ! *(*output)++ = c; ! (*outlen)++; ! } ! } ! else ! { ! putc(c, stream); ! (*outlen)++; ! } } *************** *** 736,765 **** static void ! leading_pad(int zpad, int *signvalue, int *padlen, char *end, char **output) { if (*padlen > 0 && zpad) { if (*signvalue) { ! dopr_outch(*signvalue, end, output); --*padlen; *signvalue = 0; } while (*padlen > 0) { ! dopr_outch(zpad, end, output); --*padlen; } } while (*padlen > 0 + (*signvalue != 0)) { ! dopr_outch(' ', end, output); --*padlen; } if (*signvalue) { ! dopr_outch(*signvalue, end, output); if (*padlen > 0) --* padlen; if (padlen < 0) --- 764,794 ---- static void ! leading_pad(int zpad, int *signvalue, int *padlen, char *end, char **output, ! FILE *stream, int *outlen) { if (*padlen > 0 && zpad) { if (*signvalue) { ! dopr_outch(*signvalue, end, output, stream, outlen); --*padlen; *signvalue = 0; } while (*padlen > 0) { ! dopr_outch(zpad, end, output, stream, outlen); --*padlen; } } while (*padlen > 0 + (*signvalue != 0)) { ! dopr_outch(' ', end, output, stream, outlen); --*padlen; } if (*signvalue) { ! dopr_outch(*signvalue, end, output, stream, outlen); if (*padlen > 0) --* padlen; if (padlen < 0) *************** *** 769,779 **** static void ! trailing_pad(int *padlen, char *end, char **output) { while (*padlen < 0) { ! dopr_outch(' ', end, output); ++*padlen; } } --- 798,808 ---- static void ! trailing_pad(int *padlen, char *end, char **output, FILE *stream, int *outlen) { while (*padlen < 0) { ! dopr_outch(' ', end, output, stream, outlen); ++*padlen; } }
Bruce Momjian <pgman@candle.pha.pa.us> writes: > I am also thinking of modifying the code so if we are using snprintf.c > only because we need positional parameter control, we check for '$' in > the string and only use snprintf.c in those cases. What's the point? If the code is in there we may as well use it. regards, tom lane
Tom Lane wrote: > Bruce Momjian <pgman@candle.pha.pa.us> writes: > > I am also thinking of modifying the code so if we are using snprintf.c > > only because we need positional parameter control, we check for '$' in > > the string and only use snprintf.c in those cases. > > What's the point? If the code is in there we may as well use it. I was thinking it might avoid us hitting other bugs in there, but that is pessimistic, of course. I will hold off on that idea. -- 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
Re: [HACKERS] snprintf() argument reordering not working under Windows in 8.1
From
Nicolai Tufar
Date:
Greetings, I thought it will be as simple as changing Makefile, the issue seem to be much more complicated. Unfortunately I have no PostgreSQL building environment handy and will not be able to look at it until the end of next week because I am moving my house :( But since this issue waited for so long it may wait a week more. 2005/12/3, Bruce Momjian <pgman@candle.pha.pa.us>: > Sure, I remember. So glad you returned at this time. I found a design > limitation in that file yesterday. It can not output more then 4096 > characters, and there are some cases with NUMERIC that try to output > more than that. For example: > > SELECT pow(10::numeric, 10000) + 1; > > should show a '1' at the end of the number, but with the existing code > you will just see 4095 0's and no more. > > I am attaching the new snprintf.c and the patch itself for your review. > The change is to pass 'stream' down into the routines and output to the > FILE* right from inside the routine, rather than using a string. This > fixes the problem. Your patch increase buffers from 4095 to 8192. Sounds good to me. > I am also thinking of modifying the code so if we are using snprintf.c > only because we need positional parameter control, we check for '$' in > the string and only use snprintf.c in those cases. I too, was thinking of it at the beginning but decided that the code would get even more complicated than it was at the moment and was afraid that core team would not accept my patch. :) > > NLS messages of some languages, like Turkish, rely heavily on argument > > reordering because of the language structure. In 8.1 Turkish messages > > in Windows version are all broken because argument reordering is not there. > > Really? I have not heard any report of that but this is new code in 8.1. Windows installer does not set lc_messages configuration variable correctly in postgresql.conf file. It is a known issue and will be solved in next version. Meanwhile user needs to open postgresql.conf file and change lc_messages = 'Turkish_Turkey.28599' to lc_messages = 'tr_TR.UTF-8' manually. Apparently nobody cared to do it and Devrim never ever touches Windows. The problem is there, I am definitely positive about it, here are two lines from log file: 2005-11-20 12:36:37 HATA: "$s" yerinde $s 1 karakterinde 2005-12-03 19:14:27 LOG: "$s" veritabanın transaction ID warp limiti $u > > Actually, that changes means that there was nothing backend-specific in > snprintf.c so we don't need a _special_ version for the backend. The > real change not to use snprintf.c on Win32 is in configure.in with this > comment: > > # 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 > fi > fi > > Here is the commit: > > revision 1.409 > date: 2005/05/05 19:15:54; author: momjian; state: Exp; lines: +8 -2 > 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. I don't have MinGW build environment on my computer at the moment and will not be able to install it until the end of next week but log messages above were produced by PostgreSQL installed with 8.1.0-2 Windows installer downloaded from postgresql.org. Since Turkish messages are printed I suppose it was compiled with $enable_nls = yes Thank you for your attention, Regards, Nicolai Tufar