Re: [HACKERS] %2$, %1$ gettext placeholder replacement is not working under Win32

Nicolai Tufar <[email protected]>
Newsgroups gmane.comp.db.postgresql.devel.win32,gmane.comp.db.postgresql.devel.general
Message-ID <[email protected]>
Greetings,

I would like to submit a new version of src/port/snprintf.c 
It passes regression tests on Linux and Win32 and
prints all of %n$ messages finely.

I added printf() function too because --help usage-type 
output is printed with printf().

I have no experience with autoconf so I would ask you
for help on what changes to do to include libpgport to 
src/Makefile.global and  src/Makefile.shlib.

PostgreSQL uses snprintf() in more places than I expected.
So these changes need a through testing. I have no 64-bit
to able to run regression test on it would be nice to run
it on a 64-bit platform too.

Best regards,
Nicolai Tufar


---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
      subscribe-nomail command to [email protected] so that your
      message can get through to the mailing list cleanly
snprintf.c (text/plain, 15.4 KB)
/*
 * 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.
 */

/* might be in either frontend or backend */
#include "postgres_fe.h"

#ifdef ENABLE_THREAD_SAFETY
#error	The replacement snprintf() is not thread-safe.	\
Your platform must have a thread-safe snprintf() to compile with threads.
#endif

#if !defined(WIN32) && !defined(__CYGWIN__)
	#include <sys/ioctl.h>
#endif
#include <sys/param.h>


/*
 * We do all internal arithmetic in the widest available integer type,
 * here called long_long (or ulong_long for unsigned).
 */
#ifdef HAVE_LONG_LONG_INT_64
typedef long long long_long;
typedef unsigned long long ulong_long;

#else
typedef long long_long;
typedef unsigned long ulong_long;
#endif

#ifndef NL_ARGMAX
#define NL_ARGMAX 4096
#endif

/*
**	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 nast effects.
 **************************************************************/

/*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.4 2004/08/29 05:07:02 momjian Exp $";*/
static char *end;
static int	SnprfOverflow;

int			snprintf(char *str, size_t count, const char *fmt,...);
int			vsnprintf(char *str, size_t count, const char *fmt, va_list args);
int			printf(const char *format, ...);
static void dopr(char *buffer, const char *format, va_list args);

int
printf(const char *fmt,...)
{
	int			len;
	va_list			args;
	static char*		buffer[4096];
	char*			p;

	va_start(args, fmt);
	len = vsnprintf((char*)buffer, (size_t)4096, fmt, args);
	va_end(args);
	p = (char*)buffer;
	for(;*p;p++)
		putchar(*p);
	return len;
}

int
snprintf(char *str, size_t count, const char *fmt,...)
{
	int			len;
	va_list		args;

	va_start(args, fmt);
	len = vsnprintf(str, count, fmt, args);
	va_end(args);
	return len;
}


int
vsnprintf(char *str, size_t count, const char *fmt, va_list args)
{
	str[0] = '\0';
	end = str + count - 1;
	SnprfOverflow = 0;
	dopr(str, fmt, args);
	if (count > 0)
		end[0] = '\0';
	return strlen(str);
}

/*
 * dopr(): poor man's version of doprintf
 */

static void fmtstr(char *value, int ljust, int len, int zpad, int maxwidth);
static void fmtnum(long_long value, int base, int dosign, int ljust, int len, int zpad);
static void fmtfloat(double value, char type, int ljust, int len, int precision, int pointflag);
static void dostr(char *str, int cut);
static void dopr_outch(int c);

static char *output;

#define	FMTSTR		1
#define	FMTNUM		2
#define	FMTFLOAT	3
#define	FMTCHAR		4

static void
dopr(char *buffer, const char *format, va_list args)
{
	int			ch;
	long_long	value;
	double		fvalue;
	int			longlongflag = 0;
	int			longflag = 0;
	int			pointflag = 0;
	int			maxwidth = 0;
	char	   *strvalue;
	int			ljust;
	int			len;
	int			zpad;
	int			i;
	const char*		format_save;
	const char*		fmtbegin;
	int			fmtpos = 1;
	int			realpos = 0;
	int			position;
	static struct{
		const char*	fmtbegin;
		const char*	fmtend;
		union{
			void*	value;
			long_long	numvalue;
			double		fvalue;
			int		charvalue;
		};
		int	ljust;
		int	len;
		int	zpad;
		int	maxwidth;
		int	base;
		int	dosign;
		char	type;
		int	precision;
		int	pointflag;
		char	func;
		int	realpos;
	}fmtpar[NL_ARGMAX+1], *fmtparptr[NL_ARGMAX+1];


	format_save = format;
	output = buffer;
	while ((ch = *format++))
	{
		switch (ch)
		{
			case '%':
				ljust = len = zpad = maxwidth = 0;
				longflag = longlongflag = pointflag = 0;
				fmtbegin = format - 1;
				realpos = 0;
				position = 0;
		nextch:
				ch = *format++;
				switch (ch)
				{
					case 0:
						goto performpr;
					case '-':
						ljust = 1;
						goto nextch;
					case '0':	/* set zero padding if len not set */
						if (len == 0 && !pointflag)
							zpad = '0';
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						if (pointflag)
							maxwidth = maxwidth * 10 + ch - '0';
						else
						{ 
							len = len * 10 + ch - '0';
							position = position * 10 + ch - '0';
						}
						goto nextch;
					case '$':
						realpos = position;
						len = 0;
						goto nextch;
					case '*':
						if (pointflag)
							maxwidth = va_arg(args, int);
						else
							len = va_arg(args, int);
						goto nextch;
					case '.':
						pointflag = 1;
						goto nextch;
					case 'l':
						if (longflag)
							longlongflag = 1;
						else
							longflag = 1;
						goto nextch;
					case 'u':
					case 'U':
						/* fmtnum(value,base,dosign,ljust,len,zpad) */
						if (longflag)
						{
							if (longlongflag)
								value = va_arg(args, ulong_long);
							else
								value = va_arg(args, unsigned long);
						}
						else
							value = va_arg(args, unsigned int);
						fmtpar[fmtpos].fmtbegin = fmtbegin;
						fmtpar[fmtpos].fmtend = format;
						fmtpar[fmtpos].numvalue = value;
						fmtpar[fmtpos].base = 10;
						fmtpar[fmtpos].dosign = 0;
						fmtpar[fmtpos].ljust = ljust;
						fmtpar[fmtpos].len = len;
						fmtpar[fmtpos].zpad = zpad;
						fmtpar[fmtpos].func = FMTNUM;
						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
						fmtpos++;
						break;
					case 'o':
					case 'O':
						/* fmtnum(value,base,dosign,ljust,len,zpad) */
						if (longflag)
						{
							if (longlongflag)
								value = va_arg(args, ulong_long);
							else
								value = va_arg(args, unsigned long);
						}
						else
							value = va_arg(args, unsigned int);
						fmtpar[fmtpos].fmtbegin = fmtbegin;
						fmtpar[fmtpos].fmtend = format;
						fmtpar[fmtpos].numvalue = value;
						fmtpar[fmtpos].base = 8;
						fmtpar[fmtpos].dosign = 0;
						fmtpar[fmtpos].ljust = ljust;
						fmtpar[fmtpos].len = len;
						fmtpar[fmtpos].zpad = zpad;
						fmtpar[fmtpos].func = FMTNUM;
						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
						fmtpos++;
						break;
					case 'd':
					case 'D':
						if (longflag)
						{
							if (longlongflag)
								value = va_arg(args, long_long);
							else
								value = va_arg(args, long);
						}
						else
							value = va_arg(args, int);
						fmtpar[fmtpos].fmtbegin = fmtbegin;
						fmtpar[fmtpos].fmtend = format;
						fmtpar[fmtpos].numvalue = value;
						fmtpar[fmtpos].base = 10;
						fmtpar[fmtpos].dosign = 1;
						fmtpar[fmtpos].ljust = ljust;
						fmtpar[fmtpos].len = len;
						fmtpar[fmtpos].zpad = zpad;
						fmtpar[fmtpos].func = FMTNUM;
						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
						fmtpos++;
						break;
					case 'x':
						if (longflag)
						{
							if (longlongflag)
								value = va_arg(args, ulong_long);
							else
								value = va_arg(args, unsigned long);
						}
						else
							value = va_arg(args, unsigned int);
						fmtpar[fmtpos].fmtbegin = fmtbegin;
						fmtpar[fmtpos].fmtend = format;
						fmtpar[fmtpos].numvalue = value;
						fmtpar[fmtpos].base = 16;
						fmtpar[fmtpos].dosign = 0;
						fmtpar[fmtpos].ljust = ljust;
						fmtpar[fmtpos].len = len;
						fmtpar[fmtpos].zpad = zpad;
						fmtpar[fmtpos].func = FMTNUM;
						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
						fmtpos++;
						break;
					case 'X':
						if (longflag)
						{
							if (longlongflag)
								value = va_arg(args, ulong_long);
							else
								value = va_arg(args, unsigned long);
						}
						else
							value = va_arg(args, unsigned int);
						fmtpar[fmtpos].fmtbegin = fmtbegin;
						fmtpar[fmtpos].fmtend = format;
						fmtpar[fmtpos].numvalue = value;
						fmtpar[fmtpos].base = -16;
						fmtpar[fmtpos].dosign = 1;
						fmtpar[fmtpos].ljust = ljust;
						fmtpar[fmtpos].len = len;
						fmtpar[fmtpos].zpad = zpad;
						fmtpar[fmtpos].func = FMTNUM;
						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
						fmtpos++;
						break;
					case 's':
						strvalue = va_arg(args, char *);
						if (maxwidth > 0 || !pointflag)
						{
							if (pointflag && len > maxwidth)
								len = maxwidth; /* Adjust padding */
							fmtpar[fmtpos].fmtbegin = fmtbegin;
							fmtpar[fmtpos].fmtend = format;
							fmtpar[fmtpos].value = strvalue;
							fmtpar[fmtpos].ljust = ljust;
							fmtpar[fmtpos].len = len;
							fmtpar[fmtpos].zpad = zpad;
							fmtpar[fmtpos].maxwidth = maxwidth;
							fmtpar[fmtpos].func = FMTSTR;
							fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
							fmtpos++;
						}
						break;
					case 'c':
						ch = va_arg(args, int);
						fmtpar[fmtpos].fmtbegin = fmtbegin;
						fmtpar[fmtpos].fmtend = format;
						fmtpar[fmtpos].charvalue = ch;
						fmtpar[fmtpos].func = FMTCHAR;
						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
						fmtpos++;
						break;
					case 'e':
					case 'E':
					case 'f':
					case 'g':
					case 'G':
						fvalue = va_arg(args, double);
						fmtpar[fmtpos].fmtbegin = fmtbegin;
						fmtpar[fmtpos].fmtend = format;
						fmtpar[fmtpos].fvalue = fvalue;
						fmtpar[fmtpos].type = ch;
						fmtpar[fmtpos].ljust = ljust;
						fmtpar[fmtpos].len = len;
						fmtpar[fmtpos].maxwidth = maxwidth;
						fmtpar[fmtpos].pointflag = pointflag;
						fmtpar[fmtpos].func = FMTFLOAT;
						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
						fmtpos++;
						break;
					case '%':
						break;
					default:
						dostr("???????", 0);
				}
				break;
			default:
				dopr_outch(ch);
				break;
		}
	}
performpr:
	/* shuffle pointers */
	for(i = 1; i < fmtpos; i++)
	{
		fmtparptr[i] = &fmtpar[fmtpar[i].realpos];
	}
	output = buffer;
	format = format_save;
	while ((ch = *format++))
	{
		for(i = 1; i < fmtpos; i++)
		{
			if(ch == '%' && *format == '%')
			{
				format++;
				continue;
			}
			if(fmtpar[i].fmtbegin == format - 1)
			{
				switch(fmtparptr[i]->func){
				case FMTSTR:
					fmtstr(fmtparptr[i]->value, fmtparptr[i]->ljust,
						fmtparptr[i]->len, fmtparptr[i]->zpad,
						fmtparptr[i]->maxwidth);
					break;
				case FMTNUM:
					fmtnum(fmtparptr[i]->numvalue, fmtparptr[i]->base,
						fmtparptr[i]->dosign, fmtparptr[i]->ljust,
						fmtparptr[i]->len, fmtparptr[i]->zpad);
					break;
				case FMTFLOAT:
					fmtfloat(fmtparptr[i]->fvalue, fmtparptr[i]->type,
						fmtparptr[i]->ljust, fmtparptr[i]->len,
						fmtparptr[i]->precision, fmtparptr[i]->pointflag);
					break;
				case FMTCHAR:
					dopr_outch(fmtparptr[i]->charvalue);
					break;
				}
				format = fmtpar[i].fmtend;
				goto nochar;
			}
		}
		dopr_outch(ch);
nochar:
	/* nothing */
	}
	*output = '\0';
}

static void
fmtstr(char *value, int ljust, int len, int zpad, int maxwidth)
{
	int			padlen,
				strlen;			/* amount to pad */

	if (value == 0)
		value = "<NULL>";
	for (strlen = 0; value[strlen]; ++strlen);	/* strlen */
	if (strlen > maxwidth && maxwidth)
		strlen = maxwidth;
	padlen = len - strlen;
	if (padlen < 0)
		padlen = 0;
	if (ljust)
		padlen = -padlen;
	while (padlen > 0)
	{
		dopr_outch(' ');
		--padlen;
	}
	dostr(value, maxwidth);
	while (padlen < 0)
	{
		dopr_outch(' ');
		++padlen;
	}
}

static void
fmtnum(long_long value, int base, int dosign, int ljust, int len, int zpad)
{
	int			signvalue = 0;
	ulong_long	uvalue;
	char		convert[64];
	int			place = 0;
	int			padlen = 0;		/* amount to pad */
	int			caps = 0;

	/*
	 * DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad
	 * %d\n", value, base, dosign, ljust, len, zpad ));
	 */
	uvalue = value;
	if (dosign)
	{
		if (value < 0)
		{
			signvalue = '-';
			uvalue = -value;
		}
	}
	if (base < 0)
	{
		caps = 1;
		base = -base;
	}
	do
	{
		convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
			[uvalue % (unsigned) base];
		uvalue = (uvalue / (unsigned) base);
	} while (uvalue);
	convert[place] = 0;

	if (len < 0)
	{
		/* this could happen with a "*" width spec */
		ljust = 1;
		len = -len;
	}
	padlen = len - place;
	if (padlen < 0)
		padlen = 0;
	if (ljust)
		padlen = -padlen;

	/*
	 * DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
	 * convert,place,signvalue,padlen));
	 */
	if (zpad && padlen > 0)
	{
		if (signvalue)
		{
			dopr_outch(signvalue);
			--padlen;
			signvalue = 0;
		}
		while (padlen > 0)
		{
			dopr_outch(zpad);
			--padlen;
		}
	}
	while (padlen > 0)
	{
		dopr_outch(' ');
		--padlen;
	}
	if (signvalue)
		dopr_outch(signvalue);
	while (place > 0)
		dopr_outch(convert[--place]);
	while (padlen < 0)
	{
		dopr_outch(' ');
		++padlen;
	}
}

static void
fmtfloat(double value, char type, int ljust, int len, int precision, int pointflag)
{
	char		fmt[32];
	char		convert[512];
	int			padlen = 0;		/* amount to pad */

	/* we rely on regular C library's sprintf to do the basic conversion */
	if (pointflag)
		sprintf(fmt, "%%.%d%c", precision, type);
	else
		sprintf(fmt, "%%%c", type);
	sprintf(convert, fmt, value);

	if (len < 0)
	{
		/* this could happen with a "*" width spec */
		ljust = 1;
		len = -len;
	}
	padlen = len - strlen(convert);
	if (padlen < 0)
		padlen = 0;
	if (ljust)
		padlen = -padlen;

	while (padlen > 0)
	{
		dopr_outch(' ');
		--padlen;
	}
	dostr(convert, 0);
	while (padlen < 0)
	{
		dopr_outch(' ');
		++padlen;
	}
}

static void
dostr(char *str, int cut)
{
	if (cut)
	{
		while (*str && cut-- > 0)
			dopr_outch(*str++);
	}
	else
	{
		while (*str)
			dopr_outch(*str++);
	}
}

static void
dopr_outch(int c)
{
#ifdef NOT_USED
	if (iscntrl((unsigned char) c) && c != '\n' && c != '\t')
	{
		c = '@' + (c & 0x1F);
		if (end == 0 || output < end)
			*output++ = '^';
	}
#endif
	if (end == 0 || output < end)
		*output++ = c;
	else
		SnprfOverflow++;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.