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;
        }
  }
---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faq

Reply via email to