Re: [HACKERS] snprintf() argument reordering not working under Windows - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: [HACKERS] snprintf() argument reordering not working under Windows
Date
Msg-id 200512031616.jB3GG3A19977@candle.pha.pa.us
Whole thread Raw
Responses Re: [HACKERS] snprintf() argument reordering not working under Windows
Re: [HACKERS] snprintf() argument reordering not working under Windows in 8.1
List pgsql-patches
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;
      }
  }

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: [HACKERS] Should libedit be preferred to libreadline?
Next
From: Tom Lane
Date:
Subject: Re: [HACKERS] snprintf() argument reordering not working under Windows