snprintf.c 11.7 KB
Newer Older
M
 
Marc G. Fournier 已提交
1 2 3
/*
 * Copyright (c) 1983, 1995, 1996 Eric P. Allman
 * Copyright (c) 1988, 1993
M
 
Marc G. Fournier 已提交
4 5 6 7 8 9
 *	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
M
 
Marc G. Fournier 已提交
10
 *    notice, this list of conditions and the following disclaimer.
M
 
Marc G. Fournier 已提交
11
 * 2. Redistributions in binary form must reproduce the above copyright
M
 
Marc G. Fournier 已提交
12 13
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
M
 
Marc G. Fournier 已提交
14
 * 3. All advertising materials mentioning features or use of this software
M
 
Marc G. Fournier 已提交
15
 *    must display the following acknowledgement:
M
 
Marc G. Fournier 已提交
16 17 18
 *	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
M
 
Marc G. Fournier 已提交
19 20
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
M
 
Marc G. Fournier 已提交
21 22 23 24
 *
 * 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
M
 
Marc G. Fournier 已提交
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
M
 
Marc G. Fournier 已提交
26 27 28 29 30 31 32 33
 * 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.
 */
V
Vadim B. Mikheev 已提交
34
#if 0
M
 
Marc G. Fournier 已提交
35 36
# include "sendmail.h"
# include "pathnames.h"
V
Vadim B. Mikheev 已提交
37 38 39 40
#endif

# include "postgres.h"

B
Bruce Momjian 已提交
41 42
# include "regex/cdefs.h"

V
Vadim B. Mikheev 已提交
43 44 45 46 47
# include <stdarg.h>
# define VA_LOCAL_DECL  va_list args;
# define VA_START(f)    va_start(args, f)
# define VA_END     va_end(args)

M
 
Marc G. Fournier 已提交
48 49
# include <sys/ioctl.h>
# include <sys/param.h>
50

51 52 53
/* IRIX doesn't do 'long long' in va_arg(), so use a typedef */
typedef long long long_long;

M
 
Marc G. Fournier 已提交
54 55 56 57 58 59 60
/*
**  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.
*/
61

M
 
Marc G. Fournier 已提交
62 63 64 65 66 67 68 69 70 71 72 73 74
/**************************************************************
 * 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...
 *
 * 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.
 **************************************************************/
M
 
Marc G. Fournier 已提交
75

76
/*static char _id[] = "$Id: snprintf.c,v 1.8 1998/10/02 15:38:01 momjian Exp $";*/
M
 
Marc G. Fournier 已提交
77 78
static char *end;
static int	SnprfOverflow;
M
 
Marc G. Fournier 已提交
79

V
Vadim B. Mikheev 已提交
80 81 82 83
int snprintf(char *str, size_t count, const char *fmt, ...);
int vsnprintf(char *str, size_t count, const char *fmt, ...);
static void dopr (char *buffer, const char *format, ... );

M
 
Marc G. Fournier 已提交
84
int
M
 
Marc G. Fournier 已提交
85 86 87 88 89 90
snprintf(char *str, size_t count, const char *fmt, ...)
{
	int len;
	VA_LOCAL_DECL

	VA_START(fmt);
V
Vadim B. Mikheev 已提交
91
	len = vsnprintf(str, count, fmt, args);
M
 
Marc G. Fournier 已提交
92 93 94 95 96
	VA_END;
	return len;
}


M
 
Marc G. Fournier 已提交
97
int
V
Vadim B. Mikheev 已提交
98
vsnprintf(char *str, size_t count, const char *fmt, ...)
M
 
Marc G. Fournier 已提交
99
{
V
Vadim B. Mikheev 已提交
100 101 102
	VA_LOCAL_DECL

	VA_START(fmt);
M
 
Marc G. Fournier 已提交
103 104 105
	str[0] = 0;
	end = str + count - 1;
	SnprfOverflow = 0;
V
Vadim B. Mikheev 已提交
106
	dopr( str, fmt, args);
M
 
Marc G. Fournier 已提交
107 108
	if (count > 0)
		end[0] = 0;
V
Vadim B. Mikheev 已提交
109 110 111 112
	if (SnprfOverflow)
		elog(NOTICE, "vsnprintf overflow, len = %d, str = %s",
			count, str);
	VA_END;
M
 
Marc G. Fournier 已提交
113 114
	return strlen(str);
}
115

M
 
Marc G. Fournier 已提交
116 117 118 119 120 121 122 123 124 125 126
/*
 * dopr(): poor man's version of doprintf
 */

static void fmtstr __P((char *value, int ljust, int len, int zpad, int maxwidth));
static void fmtnum __P((long value, int base, int dosign, int ljust, int len, int zpad));
static void dostr __P(( char * , int ));
static char *output;
static void dopr_outch __P(( int c ));

static void
V
Vadim B. Mikheev 已提交
127
dopr (char *buffer, const char *format, ... )
M
 
Marc G. Fournier 已提交
128
{
V
Vadim B. Mikheev 已提交
129 130 131
	int ch;
	long value;
	int longflag  = 0;
M
 
Marc G. Fournier 已提交
132
	int longlongflag  = 0;
V
Vadim B. Mikheev 已提交
133 134 135 136 137 138 139 140 141
	int pointflag = 0;
	int maxwidth  = 0;
	char *strvalue;
	int ljust;
	int len;
	int zpad;
	VA_LOCAL_DECL

	VA_START(format);
M
 
Marc G. Fournier 已提交
142 143 144 145 146 147 148 149 150 151 152 153

       output = buffer;
       while( (ch = *format++) ){
               switch( ch ){
               case '%':
                       ljust = len = zpad = maxwidth = 0;
                       longflag = pointflag = 0;
               nextch:
                       ch = *format++;
                       switch( ch ){
                       case 0:
                               dostr( "**end of format**" , 0);
V
Vadim B. Mikheev 已提交
154
							   VA_END;
M
 
Marc G. Fournier 已提交
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
                               return;
                       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';
                               goto nextch;
		       case '*': 
			       if (pointflag)
				 maxwidth = va_arg( args, int );
			       else
				 len = va_arg( args, int );
			       goto nextch;
		       case '.': pointflag = 1; goto nextch;
M
 
Marc G. Fournier 已提交
174 175 176 177 178
                       case 'l': if(longflag) {
                                   longlongflag = 1; goto nextch;
                                 } else {
                                   longflag = 1; goto nextch;
                                 }
M
 
Marc G. Fournier 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
                       case 'u': case 'U':
                               /*fmtnum(value,base,dosign,ljust,len,zpad) */
                               if( longflag ){
                                       value = va_arg( args, long );
                               } else {
                                       value = va_arg( args, int );
                               }
                               fmtnum( value, 10,0, ljust, len, zpad ); break;
                       case 'o': case 'O':
                               /*fmtnum(value,base,dosign,ljust,len,zpad) */
                               if( longflag ){
                                       value = va_arg( args, long );
                               } else {
                                       value = va_arg( args, int );
                               }
                               fmtnum( value, 8,0, ljust, len, zpad ); break;
                       case 'd': case 'D':
                               if( longflag ){
M
 
Marc G. Fournier 已提交
197
                                 if( longlongflag ) {
198
                                       value = va_arg( args, long_long );
M
 
Marc G. Fournier 已提交
199
                                 } else {
M
 
Marc G. Fournier 已提交
200
                                       value = va_arg( args, long );
M
 
Marc G. Fournier 已提交
201
                                 }
M
 
Marc G. Fournier 已提交
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
                               } else {
                                       value = va_arg( args, int );
                               }
                               fmtnum( value, 10,1, ljust, len, zpad ); break;
                       case 'x':
                               if( longflag ){
                                       value = va_arg( args, long );
                               } else {
                                       value = va_arg( args, int );
                               }
                               fmtnum( value, 16,0, ljust, len, zpad ); break;
                       case 'X':
                               if( longflag ){
                                       value = va_arg( args, long );
                               } else {
                                       value = va_arg( args, int );
                               }
                               fmtnum( value,-16,0, ljust, len, zpad ); break;
                       case 's':
                               strvalue = va_arg( args, char *);
			       if (maxwidth > 0 || !pointflag) {
				 if (pointflag && len > maxwidth)
				   len = maxwidth; /* Adjust padding */
				 fmtstr( strvalue,ljust,len,zpad, maxwidth);
			       }
			       break;
                       case 'c':
                               ch = va_arg( args, int );
                               dopr_outch( ch ); break;
                       case '%': dopr_outch( ch ); continue;
                       default:
                               dostr(  "???????" , 0);
                       }
                       break;
               default:
                       dopr_outch( ch );
                       break;
               }
       }
       *output = 0;
V
Vadim B. Mikheev 已提交
242
	   VA_END;
M
 
Marc G. Fournier 已提交
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
}

static void
fmtstr(  value, ljust, len, zpad, maxwidth )
       char *value;
       int ljust, len, zpad, 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(  value, base, dosign, ljust, len, zpad )
       long value;
       int base, dosign, ljust, len, zpad;
{
       int signvalue = 0;
       unsigned long uvalue;
       char convert[20];
       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;
       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
dostr( str , cut)
     char *str;
     int cut;
{
  if (cut) {
    while(*str && cut-- > 0) dopr_outch(*str++);
  } else {
    while(*str) dopr_outch(*str++);
  }
}

static void
dopr_outch( c )
       int c;
{
#if 0
       if( iscntrl(c) && c != '\n' && c != '\t' ){
               c = '@' + (c & 0x1F);
               if( end == 0 || output < end )
                       *output++ = '^';
       }
M
 
Marc G. Fournier 已提交
354
#endif
M
 
Marc G. Fournier 已提交
355 356 357 358
       if( end == 0 || output < end )
               *output++ = c;
       else
		SnprfOverflow++;
M
 
Marc G. Fournier 已提交
359
}
M
 
Marc G. Fournier 已提交
360

V
Vadim B. Mikheev 已提交
361