/ circle3.1 / src / bsd-snprintf.c
bsd-snprintf.c
  1  /*
  2   * This file taken from openbsd-compat of OpenSSH 3.1. It is only used
  3   * if your operating system does not provide snprintf() or vsnprintf().
  4   *
  5   * --- 8< --- OpenSSH LICENSE --- 8< ---
  6   * Remaining components of the software are provided under a standard
  7   * 2-term BSD licence with the following names as copyright holders:
  8   *
  9   *      Markus Friedl
 10   *      Theo de Raadt
 11   *      Niels Provos
 12   *      Dug Song
 13   *      Aaron Campbell
 14   *      Damien Miller
 15   *      Kevin Steves
 16   *
 17   * Redistribution and use in source and binary forms, with or without
 18   * modification, are permitted provided that the following conditions
 19   * are met:
 20   * 1. Redistributions of source code must retain the above copyright
 21   *    notice, this list of conditions and the following disclaimer.
 22   * 2. Redistributions in binary form must reproduce the above copyright
 23   *    notice, this list of conditions and the following disclaimer in the
 24   *    documentation and/or other materials provided with the distribution.
 25   *
 26   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 27   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 28   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 29   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 30   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 31   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 32   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 33   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 34   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 35   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 36   * --- 8< --- OpenSSH LICENSE --- 8< ---
 37   */
 38  
 39  /**************************************************************
 40   * Original:
 41   * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
 42   * A bombproof version of doprnt (dopr) included.
 43   * Sigh.  This sort of thing is always nasty do deal with.  Note that
 44   * the version here does not include floating point...
 45   *
 46   * snprintf() is used instead of sprintf() as it does limit checks
 47   * for string length.  This covers a nasty loophole.
 48   *
 49   * The other functions are there to prevent NULL pointers from
 50   * causing nast effects.
 51   *
 52   * More Recently:
 53   *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
 54   *  This was ugly.  It is still ugly.  I opted out of floating point
 55   *  numbers, but the formatter understands just about everything
 56   *  from the normal C string format, at least as far as I can tell from
 57   *  the Solaris 2.5 printf(3S) man page.
 58   *
 59   *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
 60   *    Ok, added some minimal floating point support, which means this
 61   *    probably requires libm on most operating systems.  Don't yet
 62   *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
 63   *    was pretty badly broken, it just wasn't being exercised in ways
 64   *    which showed it, so that's been fixed.  Also, formated the code
 65   *    to mutt conventions, and removed dead code left over from the
 66   *    original.  Also, there is now a builtin-test, just compile with:
 67   *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
 68   *    and run snprintf for results.
 69   * 
 70   *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
 71   *    The PGP code was using unsigned hexadecimal formats. 
 72   *    Unfortunately, unsigned formats simply didn't work.
 73   *
 74   *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
 75   *    The original code assumed that both snprintf() and vsnprintf() were
 76   *    missing.  Some systems only have snprintf() but not vsnprintf(), so
 77   *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
 78   *
 79   *  Ben Lindstrom <mouring@eviladmin.org> 09/27/00 for OpenSSH
 80   *    Welcome to the world of %lld and %qd support.  With other
 81   *    long long support.  This is needed for sftp-server to work
 82   *    right.
 83   *
 84   *  Ben Lindstrom <mouring@eviladmin.org> 02/12/01 for OpenSSH
 85   *    Removed all hint of VARARGS stuff and banished it to the void,
 86   *    and did a bit of KNF style work to make things a bit more
 87   *    acceptable.  Consider stealing from mutt or enlightenment.
 88   **************************************************************/
 89  
 90  #if 0
 91  #include "includes.h"
 92  
 93  RCSID("$Id: bsd-snprintf.c,v 1.1 2002/04/16 02:22:12 greerga Exp $");
 94  #else
 95  # include "conf.h"
 96  # include "sysdep.h"
 97  # define MAX(a, b)	((a) < (b) ? (b) : (a))
 98  #endif
 99  
100  #if defined(BROKEN_SNPRINTF)		/* For those with broken snprintf() */
101  # undef HAVE_SNPRINTF
102  # undef HAVE_VSNPRINTF
103  #endif
104  
105  #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
106  
107  static void 
108  dopr(char *buffer, size_t maxlen, const char *format, va_list args);
109  
110  static void 
111  fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 
112         int min, int max);
113  
114  static void 
115  fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, 
116         int min, int max, int flags);
117  
118  static void 
119  fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
120        int min, int max, int flags);
121  
122  static void
123  dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
124  
125  /*
126   * dopr(): poor man's version of doprintf
127   */
128  
129  /* format read states */
130  #define DP_S_DEFAULT 0
131  #define DP_S_FLAGS   1
132  #define DP_S_MIN     2
133  #define DP_S_DOT     3
134  #define DP_S_MAX     4
135  #define DP_S_MOD     5
136  #define DP_S_CONV    6
137  #define DP_S_DONE    7
138  
139  /* format flags - Bits */
140  #define DP_F_MINUS 	(1 << 0)
141  #define DP_F_PLUS  	(1 << 1)
142  #define DP_F_SPACE 	(1 << 2)
143  #define DP_F_NUM   	(1 << 3)
144  #define DP_F_ZERO  	(1 << 4)
145  #define DP_F_UP    	(1 << 5)
146  #define DP_F_UNSIGNED 	(1 << 6)
147  
148  /* Conversion Flags */
149  #define DP_C_SHORT     1
150  #define DP_C_LONG      2
151  #define DP_C_LDOUBLE   3
152  #define DP_C_LONG_LONG 4
153  
154  #define char_to_int(p) (p - '0')
155  #define abs_val(p) (p < 0 ? -p : p)
156  
157  
158  static void 
159  dopr(char *buffer, size_t maxlen, const char *format, va_list args)
160  {
161  	char *strvalue;
162  	char ch;
163  	long value;
164  	long double fvalue;
165  	int min = 0;
166  	int max = -1;
167  	int state = DP_S_DEFAULT;
168  	int flags = 0;
169  	int cflags = 0;
170  	size_t currlen = 0;
171    
172  	ch = *format++;
173  
174  	while (state != DP_S_DONE) {
175  		if ((ch == '\0') || (currlen >= maxlen)) 
176  			state = DP_S_DONE;
177  
178  		switch(state) {
179  			case DP_S_DEFAULT:
180  				if (ch == '%') 
181  					state = DP_S_FLAGS;
182  				else 
183  					dopr_outch(buffer, &currlen, maxlen, ch);
184  				ch = *format++;
185  				break;
186  			case DP_S_FLAGS:
187  				switch (ch) {
188  					case '-':
189  						flags |= DP_F_MINUS;
190  						ch = *format++;
191  						break;
192  					case '+':
193  						flags |= DP_F_PLUS;
194  						ch = *format++;
195  						break;
196  					case ' ':
197  						flags |= DP_F_SPACE;
198  						ch = *format++;
199  						break;
200  					case '#':
201  						flags |= DP_F_NUM;
202  						ch = *format++;
203  						break;
204  					case '0':
205  						flags |= DP_F_ZERO;
206  						ch = *format++;
207  						break;
208  					default:
209  						state = DP_S_MIN;
210  						break;
211  				}
212  				break;
213  			case DP_S_MIN:
214  				if (isdigit((unsigned char)ch)) {
215  					min = 10*min + char_to_int (ch);
216  					ch = *format++;
217  				} else if (ch == '*') {
218  					min = va_arg (args, int);
219  					ch = *format++;
220  					state = DP_S_DOT;
221  				} else 
222  					state = DP_S_DOT;
223  				break;
224  			case DP_S_DOT:
225  				if (ch == '.') {
226  					state = DP_S_MAX;
227  					ch = *format++;
228  				} else 
229  					state = DP_S_MOD;
230  				break;
231  			case DP_S_MAX:
232  				if (isdigit((unsigned char)ch)) {
233  					if (max < 0)
234  						max = 0;
235  					max = 10*max + char_to_int(ch);
236  					ch = *format++;
237  				} else if (ch == '*') {
238  					max = va_arg (args, int);
239  					ch = *format++;
240  					state = DP_S_MOD;
241  				} else 
242  					state = DP_S_MOD;
243  				break;
244  			case DP_S_MOD:
245  				switch (ch) {
246  					case 'h':
247  						cflags = DP_C_SHORT;
248  						ch = *format++;
249  						break;
250  					case 'l':
251  						cflags = DP_C_LONG;
252  						ch = *format++;
253  						if (ch == 'l') {
254  							cflags = DP_C_LONG_LONG;
255  							ch = *format++;
256  						}
257  						break;
258  					case 'q':
259  						cflags = DP_C_LONG_LONG;
260  						ch = *format++;
261  						break;
262  					case 'L':
263  						cflags = DP_C_LDOUBLE;
264  						ch = *format++;
265  						break;
266  					default:
267  						break;
268  				}
269  				state = DP_S_CONV;
270  				break;
271  			case DP_S_CONV:
272  				switch (ch) {
273  					case 'd':
274  					case 'i':
275  						if (cflags == DP_C_SHORT) 
276  							value = va_arg(args, int);
277  						else if (cflags == DP_C_LONG)
278  							value = va_arg(args, long int);
279  						else if (cflags == DP_C_LONG_LONG)
280  							value = va_arg (args, long long);
281  						else
282  							value = va_arg (args, int);
283  						fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
284  						break;
285  					case 'o':
286  						flags |= DP_F_UNSIGNED;
287  						if (cflags == DP_C_SHORT)
288  							value = va_arg(args, unsigned int);
289  						else if (cflags == DP_C_LONG)
290  							value = va_arg(args, unsigned long int);
291  						else if (cflags == DP_C_LONG_LONG)
292  							value = va_arg(args, unsigned long long);
293  						else
294  							value = va_arg(args, unsigned int);
295  						fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
296  						break;
297  					case 'u':
298  						flags |= DP_F_UNSIGNED;
299  						if (cflags == DP_C_SHORT)
300  							value = va_arg(args, unsigned int);
301  						else if (cflags == DP_C_LONG)
302  							value = va_arg(args, unsigned long int);
303  						else if (cflags == DP_C_LONG_LONG)
304  							value = va_arg(args, unsigned long long);
305  						else
306  							value = va_arg(args, unsigned int);
307  						fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
308  						break;
309  					case 'X':
310  						flags |= DP_F_UP;
311  					case 'x':
312  						flags |= DP_F_UNSIGNED;
313  						if (cflags == DP_C_SHORT)
314  							value = va_arg(args, unsigned int);
315  						else if (cflags == DP_C_LONG)
316  							value = va_arg(args, unsigned long int);
317  						else if (cflags == DP_C_LONG_LONG)
318  							value = va_arg(args, unsigned long long);
319  						else
320  							value = va_arg(args, unsigned int);
321  						fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
322  						break;
323  					case 'f':
324  						if (cflags == DP_C_LDOUBLE)
325  							fvalue = va_arg(args, long double);
326  						else
327  							fvalue = va_arg(args, double);
328  						/* um, floating point? */
329  						fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
330  						break;
331  					case 'E':
332  						flags |= DP_F_UP;
333  					case 'e':
334  						if (cflags == DP_C_LDOUBLE)
335  							fvalue = va_arg(args, long double);
336  						else
337  							fvalue = va_arg(args, double);
338  						break;
339  					case 'G':
340  						flags |= DP_F_UP;
341  					case 'g':
342  						if (cflags == DP_C_LDOUBLE)
343  							fvalue = va_arg(args, long double);
344  						else
345  							fvalue = va_arg(args, double);
346  						break;
347  					case 'c':
348  						dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
349  						break;
350  					case 's':
351  						strvalue = va_arg(args, char *);
352  						if (max < 0) 
353  							max = maxlen; /* ie, no max */
354  						fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
355  						break;
356  					case 'p':
357  						strvalue = va_arg(args, void *);
358  						fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
359  						break;
360  					case 'n':
361  						if (cflags == DP_C_SHORT) {
362  							short int *num;
363  							num = va_arg(args, short int *);
364  							*num = currlen;
365  						} else if (cflags == DP_C_LONG) {
366  							long int *num;
367  							num = va_arg(args, long int *);
368  							*num = currlen;
369  						} else if (cflags == DP_C_LONG_LONG) {
370  							long long *num;
371  							num = va_arg(args, long long *);
372  							*num = currlen;
373  						} else {
374  							int *num;
375  							num = va_arg(args, int *);
376  							*num = currlen;
377  						}
378  						break;
379  					case '%':
380  						dopr_outch(buffer, &currlen, maxlen, ch);
381  						break;
382  					case 'w': /* not supported yet, treat as next char */
383  						ch = *format++;
384  						break;
385  					default: /* Unknown, skip */
386  					break;
387  				}
388  				ch = *format++;
389  				state = DP_S_DEFAULT;
390  				flags = cflags = min = 0;
391  				max = -1;
392  				break;
393  			case DP_S_DONE:
394  				break;
395  			default: /* hmm? */
396  				break; /* some picky compilers need this */
397  		}
398  	}
399  	if (currlen < maxlen - 1) 
400  		buffer[currlen] = '\0';
401  	else 
402  		buffer[maxlen - 1] = '\0';
403  }
404  
405  static void
406  fmtstr(char *buffer, size_t *currlen, size_t maxlen,
407         char *value, int flags, int min, int max)
408  {
409  	int padlen, strln;     /* amount to pad */
410  	int cnt = 0;
411    
412  	if (value == 0) 
413  		value = "<NULL>";
414  
415  	for (strln = 0; value[strln]; ++strln); /* strlen */
416  	padlen = min - strln;
417  	if (padlen < 0) 
418  		padlen = 0;
419  	if (flags & DP_F_MINUS) 
420  		padlen = -padlen; /* Left Justify */
421  
422  	while ((padlen > 0) && (cnt < max)) {
423  		dopr_outch(buffer, currlen, maxlen, ' ');
424  		--padlen;
425  		++cnt;
426  	}
427  	while (*value && (cnt < max)) {
428  		dopr_outch(buffer, currlen, maxlen, *value++);
429  		++cnt;
430  	}
431  	while ((padlen < 0) && (cnt < max)) {
432  		dopr_outch(buffer, currlen, maxlen, ' ');
433  		++padlen;
434  		++cnt;
435  	}
436  }
437  
438  /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
439  
440  static void 
441  fmtint(char *buffer, size_t *currlen, size_t maxlen,
442         long value, int base, int min, int max, int flags)
443  {
444  	unsigned long uvalue;
445  	char convert[20];
446  	int signvalue = 0;
447  	int place = 0;
448  	int spadlen = 0; /* amount to space pad */
449  	int zpadlen = 0; /* amount to zero pad */
450  	int caps = 0;
451    
452  	if (max < 0)
453  		max = 0;
454  
455  	uvalue = value;
456  
457  	if (!(flags & DP_F_UNSIGNED)) {
458  		if (value < 0) {
459  			signvalue = '-';
460  			uvalue = -value;
461  		} else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
462  			signvalue = '+';
463  		else if (flags & DP_F_SPACE)
464  			signvalue = ' ';
465  	}
466    
467  	if (flags & DP_F_UP) 
468  		caps = 1; /* Should characters be upper case? */
469  
470  	do {
471  		convert[place++] =
472  			(caps? "0123456789ABCDEF":"0123456789abcdef")
473  			[uvalue % (unsigned)base];
474  		uvalue = (uvalue / (unsigned)base );
475  	} while (uvalue && (place < 20));
476  	if (place == 20) 
477  		place--;
478  	convert[place] = 0;
479  
480  	zpadlen = max - place;
481  	spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
482  	if (zpadlen < 0)
483  		zpadlen = 0;
484  	if (spadlen < 0)
485  		spadlen = 0;
486  	if (flags & DP_F_ZERO) {
487  		zpadlen = MAX(zpadlen, spadlen);
488  		spadlen = 0;
489  	}
490  	if (flags & DP_F_MINUS) 
491  		spadlen = -spadlen; /* Left Justifty */
492  
493  
494  	/* Spaces */
495  	while (spadlen > 0) {
496  		dopr_outch(buffer, currlen, maxlen, ' ');
497  		--spadlen;
498  	}
499  
500  	/* Sign */
501  	if (signvalue) 
502  		dopr_outch(buffer, currlen, maxlen, signvalue);
503  
504  	/* Zeros */
505  	if (zpadlen > 0) {
506  		while (zpadlen > 0) {
507  			dopr_outch(buffer, currlen, maxlen, '0');
508  			--zpadlen;
509  		}
510  	}
511  
512  	/* Digits */
513  	while (place > 0) 
514  		dopr_outch(buffer, currlen, maxlen, convert[--place]);
515    
516  	/* Left Justified spaces */
517  	while (spadlen < 0) {
518  		dopr_outch (buffer, currlen, maxlen, ' ');
519  		++spadlen;
520  	}
521  }
522  
523  static long double 
524  pow10(int exp)
525  {
526  	long double result = 1;
527  
528  	while (exp) {
529  		result *= 10;
530  		exp--;
531  	}
532    
533  	return result;
534  }
535  
536  static long 
537  round(long double value)
538  {
539  	long intpart = value;
540  
541  	value -= intpart;
542  	if (value >= 0.5)
543  		intpart++;
544  
545  	return intpart;
546  }
547  
548  static void 
549  fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
550        int min, int max, int flags)
551  {
552  	char iconvert[20];
553  	char fconvert[20];
554  	int signvalue = 0;
555  	int iplace = 0;
556  	int fplace = 0;
557  	int padlen = 0; /* amount to pad */
558  	int zpadlen = 0; 
559  	int caps = 0;
560  	long intpart;
561  	long fracpart;
562  	long double ufvalue;
563    
564  	/* 
565  	 * AIX manpage says the default is 0, but Solaris says the default
566  	 * is 6, and sprintf on AIX defaults to 6
567  	 */
568  	if (max < 0)
569  		max = 6;
570  
571  	ufvalue = abs_val(fvalue);
572  
573  	if (fvalue < 0)
574  		signvalue = '-';
575  	else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
576  		signvalue = '+';
577  	else if (flags & DP_F_SPACE)
578  		signvalue = ' ';
579  
580  	intpart = ufvalue;
581  
582  	/* 
583  	 * Sorry, we only support 9 digits past the decimal because of our 
584  	 * conversion method
585  	 */
586  	if (max > 9)
587  		max = 9;
588  
589  	/* We "cheat" by converting the fractional part to integer by
590  	 * multiplying by a factor of 10
591  	 */
592  	fracpart = round((pow10 (max)) * (ufvalue - intpart));
593  
594  	if (fracpart >= pow10 (max)) {
595  		intpart++;
596  		fracpart -= pow10 (max);
597  	}
598  
599  	/* Convert integer part */
600  	do {
601  		iconvert[iplace++] =
602  		  (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
603  		intpart = (intpart / 10);
604  	} while(intpart && (iplace < 20));
605  	if (iplace == 20) 
606  		iplace--;
607  	iconvert[iplace] = 0;
608  
609  	/* Convert fractional part */
610  	do {
611  		fconvert[fplace++] =
612  		  (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
613  		fracpart = (fracpart / 10);
614  	} while(fracpart && (fplace < 20));
615  	if (fplace == 20) 
616  		fplace--;
617  	fconvert[fplace] = 0;
618  
619  	/* -1 for decimal point, another -1 if we are printing a sign */
620  	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
621  	zpadlen = max - fplace;
622  	if (zpadlen < 0)
623  		zpadlen = 0;
624  	if (padlen < 0) 
625  		padlen = 0;
626  	if (flags & DP_F_MINUS) 
627  		padlen = -padlen; /* Left Justifty */
628  
629  	if ((flags & DP_F_ZERO) && (padlen > 0)) {
630  		if (signvalue) {
631  			dopr_outch(buffer, currlen, maxlen, signvalue);
632  			--padlen;
633  			signvalue = 0;
634  		}
635  		while (padlen > 0) {
636  			dopr_outch(buffer, currlen, maxlen, '0');
637  			--padlen;
638  		}
639  	}
640  	while (padlen > 0) {
641  		dopr_outch(buffer, currlen, maxlen, ' ');
642  		--padlen;
643  	}
644  	if (signvalue) 
645  		dopr_outch(buffer, currlen, maxlen, signvalue);
646  
647  	while (iplace > 0) 
648  		dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
649  
650  	/*
651  	 * Decimal point.  This should probably use locale to find the correct
652  	 * char to print out.
653  	 */
654  	dopr_outch(buffer, currlen, maxlen, '.');
655  
656  	while (fplace > 0) 
657  		dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
658  
659  	while (zpadlen > 0) {
660  		dopr_outch(buffer, currlen, maxlen, '0');
661  		--zpadlen;
662  	}
663  
664  	while (padlen < 0) {
665  		dopr_outch(buffer, currlen, maxlen, ' ');
666  		++padlen;
667  	}
668  }
669  
670  static void 
671  dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
672  {
673  	if (*currlen < maxlen)
674  		buffer[(*currlen)++] = c;
675  }
676  #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
677  
678  #ifndef HAVE_VSNPRINTF
679  int 
680  vsnprintf(char *str, size_t count, const char *fmt, va_list args)
681  {
682  	str[0] = 0;
683  	dopr(str, count, fmt, args);
684  
685  	return(strlen(str));
686  }
687  #endif /* !HAVE_VSNPRINTF */
688  
689  #ifndef HAVE_SNPRINTF
690  int 
691  snprintf(char *str,size_t count,const char *fmt,...)
692  {
693  	va_list ap;
694  
695  	va_start(ap, fmt);
696  	(void) vsnprintf(str, count, fmt, ap);
697  	va_end(ap);
698  
699  	return(strlen(str));
700  }
701  
702  #ifdef TEST_SNPRINTF
703  int 
704  main(void)
705  {
706  #define LONG_STRING 1024
707  	char buf1[LONG_STRING];
708  	char buf2[LONG_STRING];
709  	char *fp_fmt[] = {
710  		"%-1.5f",
711  		"%1.5f",
712  		"%123.9f",
713  		"%10.5f",
714  		"% 10.5f",
715  		"%+22.9f",
716  		"%+4.9f",
717  		"%01.3f",
718  		"%4f",
719  		"%3.1f",
720  		"%3.2f",
721  		NULL
722  	};
723  	double fp_nums[] = { 
724  		-1.5, 
725  		134.21, 
726  		91340.2, 
727  		341.1234, 
728  		0203.9, 
729  		0.96, 
730  		0.996, 
731  		0.9996, 
732  		1.996, 
733  		4.136, 
734  		0
735  	};
736  	char *int_fmt[] = {
737  		"%-1.5d",
738  		"%1.5d",
739  		"%123.9d",
740  		"%5.5d",
741  		"%10.5d",
742  		"% 10.5d",
743  		"%+22.33d",
744  		"%01.3d",
745  		"%4d",
746  		"%lld",
747  		"%qd",
748  		NULL
749  	};
750  	long long int_nums[] = { -1, 134, 91340, 341, 0203, 0, 9999999 };
751  	int x, y;
752  	int fail = 0;
753  	int num = 0;
754  
755  	printf("Testing snprintf format codes against system sprintf...\n");
756  
757  	for (x = 0; fp_fmt[x] != NULL ; x++) {
758  		for (y = 0; fp_nums[y] != 0 ; y++) {
759  			snprintf(buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
760  			sprintf (buf2, fp_fmt[x], fp_nums[y]);
761  			if (strcmp (buf1, buf2)) {
762  				printf("snprintf doesn't match Format: %s\n\t"
763                                         "snprintf = %s\n\tsprintf  = %s\n", 
764  					fp_fmt[x], buf1, buf2);
765  				fail++;
766  			}
767  			num++;
768  		}
769  	}
770  	for (x = 0; int_fmt[x] != NULL ; x++) {
771  		for (y = 0; int_nums[y] != 0 ; y++) {
772  			snprintf(buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
773  			sprintf(buf2, int_fmt[x], int_nums[y]);
774  			if (strcmp (buf1, buf2)) {
775  				printf("snprintf doesn't match Format: %s\n\t"
776  				       "snprintf = %s\n\tsprintf  = %s\n", 
777  					int_fmt[x], buf1, buf2);
778  				fail++;
779  			}
780  			num++;
781  		}
782  	}
783  	printf("%d tests failed out of %d.\n", fail, num);
784  	return(0);
785  }
786  #endif /* SNPRINTF_TEST */
787  
788  #endif /* !HAVE_SNPRINTF */