Annotation of ircnowd/src/portab/vsnprintf.c, Revision 1.1.1.1
1.1 tomglok 1: /*
2: * ngIRCd -- The Next Generation IRC Daemon
3: * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
4: *
5: * This program is free software; you can redistribute it and/or modify
6: * it under the terms of the GNU General Public License as published by
7: * the Free Software Foundation; either version 2 of the License, or
8: * (at your option) any later version.
9: * Please read the file COPYING, README and AUTHORS for more information.
10: */
11:
12: #include "portab.h"
13:
14: /**
15: * @file
16: * snprintf() and vsnprintf() replacement functions
17: */
18:
19: /*
20: * snprintf.c: Copyright Patrick Powell 1995
21: * This code is based on code written by Patrick Powell (papowell@astart.com)
22: * It may be used for any purpose as long as this notice remains intact
23: * on all source code distributions
24: *
25: * Original: Patrick Powell Tue Apr 11 09:48:21 PDT 1995
26: * A bombproof version of doprnt (dopr) included.
27: * Sigh. This sort of thing is always nasty do deal with. Note that
28: * the version here does not include floating point...
29: *
30: * snprintf() is used instead of sprintf() as it does limit checks
31: * for string length. This covers a nasty loophole.
32: *
33: * The other functions are there to prevent NULL pointers from
34: * causing nast effects.
35: *
36: * More Recently:
37: * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
38: * This was ugly. It is still ugly. I opted out of floating point
39: * numbers, but the formatter understands just about everything
40: * from the normal C string format, at least as far as I can tell from
41: * the Solaris 2.5 printf(3S) man page.
42: *
43: * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
44: * Ok, added some minimal floating point support, which means this
45: * probably requires libm on most operating systems. Don't yet
46: * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
47: * was pretty badly broken, it just wasn't being exercised in ways
48: * which showed it, so that's been fixed. Also, formated the code
49: * to mutt conventions, and removed dead code left over from the
50: * original. Also, there is now a builtin-test, just compile with:
51: * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
52: * and run snprintf for results.
53: *
54: * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
55: * The PGP code was using unsigned hexadecimal formats.
56: * Unfortunately, unsigned formats simply didn't work.
57: *
58: * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
59: * The original code assumed that both snprintf() and vsnprintf() were
60: * missing. Some systems only have snprintf() but not vsnprintf(), so
61: * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
62: *
63: * Andrew Tridgell <tridge@samba.org>, October 1998
64: * fixed handling of %.0f
65: * added test for HAVE_LONG_DOUBLE
66: *
67: * tridge@samba.org, idra@samba.org, April 2001
68: * got rid of fcvt code (twas buggy and made testing harder)
69: * added C99 semantics
70: *
71: * Alexander Barton, <alex@barton.de>, 2002-05-19
72: * removed [v]asprintf() and C99 tests: not needed by ngIRCd.
73: */
74:
75: #ifdef HAVE_STRING_H
76: #include <string.h>
77: #endif
78: #ifdef HAVE_STRINGS_H
79: #include <strings.h>
80: #endif
81: #ifdef HAVE_CTYPE_H
82: #include <ctype.h>
83: #endif
84: #include <sys/types.h>
85: #include <stdarg.h>
86: #ifdef HAVE_STDLIB_H
87: #include <stdlib.h>
88: #endif
89:
90: #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF)
91: /* only include stdio.h if we are not re-defining snprintf or vsnprintf */
92: #include <stdio.h>
93: /* make the compiler happy with an empty file */
94: void dummy_snprintf PARAMS(( void ));
95: void dummy_snprintf PARAMS(( void )) { }
96: #else
97:
98: #ifdef HAVE_LONG_DOUBLE
99: #define LDOUBLE long double
100: #else
101: #define LDOUBLE double
102: #endif
103:
104: #ifdef HAVE_LONG_LONG
105: #define LLONG long long
106: #else
107: #define LLONG long
108: #endif
109:
110: static size_t dopr PARAMS((char *buffer, size_t maxlen, const char *format,
111: va_list args));
112: static void fmtstr PARAMS((char *buffer, size_t *currlen, size_t maxlen,
113: char *value, int flags, int min, int max));
114: static void fmtint PARAMS((char *buffer, size_t *currlen, size_t maxlen,
115: long value, int base, int min, int max, int flags));
116: static void fmtfp PARAMS((char *buffer, size_t *currlen, size_t maxlen,
117: LDOUBLE fvalue, int min, int max, int flags));
118: static void dopr_outch PARAMS((char *buffer, size_t *currlen, size_t maxlen,
119: char c));
120:
121: /*
122: * dopr(): poor man's version of doprintf
123: */
124:
125: /* format read states */
126: #define DP_S_DEFAULT 0
127: #define DP_S_FLAGS 1
128: #define DP_S_MIN 2
129: #define DP_S_DOT 3
130: #define DP_S_MAX 4
131: #define DP_S_MOD 5
132: #define DP_S_CONV 6
133: #define DP_S_DONE 7
134:
135: /* format flags - Bits */
136: #define DP_F_MINUS (1 << 0)
137: #define DP_F_PLUS (1 << 1)
138: #define DP_F_SPACE (1 << 2)
139: #define DP_F_NUM (1 << 3)
140: #define DP_F_ZERO (1 << 4)
141: #define DP_F_UP (1 << 5)
142: #define DP_F_UNSIGNED (1 << 6)
143:
144: /* Conversion Flags */
145: #define DP_C_SHORT 1
146: #define DP_C_LONG 2
147: #define DP_C_LDOUBLE 3
148: #define DP_C_LLONG 4
149:
150: #define char_to_int(p) ((p)- '0')
151: #ifndef MAX
152: #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
153: #endif
154:
155: static size_t
156: dopr(char *buffer, size_t maxlen, const char *format, va_list args)
157: {
158: char ch;
159: LLONG value;
160: LDOUBLE fvalue;
161: char *strvalue;
162: int min;
163: int max;
164: int state;
165: int flags;
166: int cflags;
167: size_t currlen;
168:
169: state = DP_S_DEFAULT;
170: currlen = flags = cflags = min = 0;
171: max = -1;
172: ch = *format++;
173:
174: while (state != DP_S_DONE) {
175: if (ch == '\0')
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: }
224: break;
225: case DP_S_DOT:
226: if (ch == '.') {
227: state = DP_S_MAX;
228: ch = *format++;
229: } else {
230: state = DP_S_MOD;
231: }
232: break;
233: case DP_S_MAX:
234: if (isdigit((unsigned char)ch)) {
235: if (max < 0)
236: max = 0;
237: max = 10*max + char_to_int (ch);
238: ch = *format++;
239: } else if (ch == '*') {
240: max = va_arg (args, int);
241: ch = *format++;
242: state = DP_S_MOD;
243: } else {
244: state = DP_S_MOD;
245: }
246: break;
247: case DP_S_MOD:
248: switch (ch) {
249: case 'h':
250: cflags = DP_C_SHORT;
251: ch = *format++;
252: break;
253: case 'l':
254: cflags = DP_C_LONG;
255: ch = *format++;
256: if (ch == 'l') { /* It's a long long */
257: cflags = DP_C_LLONG;
258: ch = *format++;
259: }
260: break;
261: case 'L':
262: cflags = DP_C_LDOUBLE;
263: ch = *format++;
264: break;
265: default:
266: break;
267: }
268: state = DP_S_CONV;
269: break;
270: case DP_S_CONV:
271: switch (ch) {
272: case 'd':
273: case 'i':
274: if (cflags == DP_C_SHORT)
275: value = va_arg (args, int);
276: else if (cflags == DP_C_LONG)
277: value = va_arg (args, long int);
278: else if (cflags == DP_C_LLONG)
279: value = va_arg (args, LLONG);
280: else
281: value = va_arg (args, int);
282: fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
283: break;
284: case 'o':
285: flags |= DP_F_UNSIGNED;
286: if (cflags == DP_C_SHORT)
287: value = va_arg (args, unsigned int);
288: else if (cflags == DP_C_LONG)
289: value = (long)va_arg (args, unsigned long int);
290: else if (cflags == DP_C_LLONG)
291: value = (long)va_arg (args, unsigned LLONG);
292: else
293: value = (long)va_arg (args, unsigned int);
294: fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
295: break;
296: case 'u':
297: flags |= DP_F_UNSIGNED;
298: if (cflags == DP_C_SHORT)
299: value = va_arg (args, unsigned int);
300: else if (cflags == DP_C_LONG)
301: value = (long)va_arg (args, unsigned long int);
302: else if (cflags == DP_C_LLONG)
303: value = (LLONG)va_arg (args, unsigned LLONG);
304: else
305: value = (long)va_arg (args, unsigned int);
306: fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
307: break;
308: case 'X':
309: flags |= DP_F_UP;
310: case 'x':
311: flags |= DP_F_UNSIGNED;
312: if (cflags == DP_C_SHORT)
313: value = va_arg (args, unsigned int);
314: else if (cflags == DP_C_LONG)
315: value = (long)va_arg (args, unsigned long int);
316: else if (cflags == DP_C_LLONG)
317: value = (LLONG)va_arg (args, unsigned LLONG);
318: else
319: value = (long)va_arg (args, unsigned int);
320: fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
321: break;
322: case 'f':
323: if (cflags == DP_C_LDOUBLE)
324: fvalue = va_arg (args, LDOUBLE);
325: else
326: fvalue = va_arg (args, double);
327: /* um, floating point? */
328: fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
329: break;
330: case 'E':
331: flags |= DP_F_UP;
332: case 'e':
333: if (cflags == DP_C_LDOUBLE)
334: fvalue = va_arg (args, LDOUBLE);
335: else
336: fvalue = va_arg (args, double);
337: break;
338: case 'G':
339: flags |= DP_F_UP;
340: case 'g':
341: if (cflags == DP_C_LDOUBLE)
342: fvalue = va_arg (args, LDOUBLE);
343: else
344: fvalue = va_arg (args, double);
345: break;
346: case 'c':
347: dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
348: break;
349: case 's':
350: strvalue = va_arg (args, char *);
351: if (max == -1) {
352: max = strlen(strvalue);
353: }
354: if (min > 0 && max >= 0 && min > max) max = min;
355: fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
356: break;
357: case 'p':
358: strvalue = va_arg (args, void *);
359: fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
360: break;
361: case 'n':
362: if (cflags == DP_C_SHORT) {
363: short int *num;
364: num = va_arg (args, short int *);
365: *num = currlen;
366: } else if (cflags == DP_C_LONG) {
367: long int *num;
368: num = va_arg (args, long int *);
369: *num = (long int)currlen;
370: } else if (cflags == DP_C_LLONG) {
371: LLONG *num;
372: num = va_arg (args, LLONG *);
373: *num = (LLONG)currlen;
374: } else {
375: int *num;
376: num = va_arg (args, int *);
377: *num = currlen;
378: }
379: break;
380: case '%':
381: dopr_outch (buffer, &currlen, maxlen, ch);
382: break;
383: case 'w':
384: /* not supported yet, treat as next char */
385: ch = *format++;
386: break;
387: default:
388: /* Unknown, skip */
389: break;
390: }
391: ch = *format++;
392: state = DP_S_DEFAULT;
393: flags = cflags = min = 0;
394: max = -1;
395: break;
396: case DP_S_DONE:
397: break;
398: default:
399: /* hmm? */
400: break; /* some picky compilers need this */
401: }
402: }
403: if (maxlen != 0) {
404: if (currlen < maxlen - 1)
405: buffer[currlen] = '\0';
406: else if (maxlen > 0)
407: buffer[maxlen - 1] = '\0';
408: }
409:
410: return currlen;
411: }
412:
413: static void
414: fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags,
415: int min, int max)
416: {
417: int padlen, strln; /* amount to pad */
418: int cnt = 0;
419:
420: #ifdef DEBUG_SNPRINTF
421: printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
422: #endif
423: if (value == 0) {
424: value = "<NULL>";
425: }
426:
427: for (strln = 0; value[strln]; ++strln); /* strlen */
428: padlen = min - strln;
429: if (padlen < 0)
430: padlen = 0;
431: if (flags & DP_F_MINUS)
432: padlen = -padlen; /* Left Justify */
433:
434: while ((padlen > 0) && (cnt < max)) {
435: dopr_outch (buffer, currlen, maxlen, ' ');
436: --padlen;
437: ++cnt;
438: }
439: while (*value && (cnt < max)) {
440: dopr_outch (buffer, currlen, maxlen, *value++);
441: ++cnt;
442: }
443: while ((padlen < 0) && (cnt < max)) {
444: dopr_outch (buffer, currlen, maxlen, ' ');
445: ++padlen;
446: ++cnt;
447: }
448: }
449:
450: /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
451:
452: static void
453: fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base,
454: int min, int max, int flags)
455: {
456: int signvalue = 0;
457: unsigned long uvalue;
458: char convert[20];
459: int place = 0;
460: int spadlen = 0; /* amount to space pad */
461: int zpadlen = 0; /* amount to zero pad */
462: int caps = 0;
463:
464: if (max < 0)
465: max = 0;
466:
467: uvalue = value;
468:
469: if(!(flags & DP_F_UNSIGNED)) {
470: if( value < 0 ) {
471: signvalue = '-';
472: uvalue = -value;
473: } else {
474: if (flags & DP_F_PLUS) /* Do a sign (+/i) */
475: signvalue = '+';
476: else if (flags & DP_F_SPACE)
477: signvalue = ' ';
478: }
479: }
480:
481: if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
482:
483: do {
484: convert[place++] =
485: (caps? "0123456789ABCDEF":"0123456789abcdef")
486: [uvalue % (unsigned)base ];
487: uvalue = (uvalue / (unsigned)base );
488: } while(uvalue && (place < 20));
489: if (place == 20) place--;
490: convert[place] = 0;
491:
492: zpadlen = max - place;
493: spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
494: if (zpadlen < 0) zpadlen = 0;
495: if (spadlen < 0) spadlen = 0;
496: if (flags & DP_F_ZERO) {
497: zpadlen = MAX(zpadlen, spadlen);
498: spadlen = 0;
499: }
500: if (flags & DP_F_MINUS)
501: spadlen = -spadlen; /* Left Justifty */
502:
503: #ifdef DEBUG_SNPRINTF
504: printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
505: zpadlen, spadlen, min, max, place);
506: #endif
507:
508: /* Spaces */
509: while (spadlen > 0) {
510: dopr_outch (buffer, currlen, maxlen, ' ');
511: --spadlen;
512: }
513:
514: /* Sign */
515: if (signvalue)
516: dopr_outch (buffer, currlen, maxlen, signvalue);
517:
518: /* Zeros */
519: if (zpadlen > 0) {
520: while (zpadlen > 0) {
521: dopr_outch (buffer, currlen, maxlen, '0');
522: --zpadlen;
523: }
524: }
525:
526: /* Digits */
527: while (place > 0)
528: dopr_outch (buffer, currlen, maxlen, convert[--place]);
529:
530: /* Left Justified spaces */
531: while (spadlen < 0) {
532: dopr_outch (buffer, currlen, maxlen, ' ');
533: ++spadlen;
534: }
535: }
536:
537: static LDOUBLE
538: abs_val(LDOUBLE value)
539: {
540: LDOUBLE result = value;
541:
542: if (value < 0)
543: result = -value;
544:
545: return result;
546: }
547:
548: static LDOUBLE
549: POW10(int exp)
550: {
551: LDOUBLE result = 1;
552:
553: while (exp) {
554: result *= 10;
555: exp--;
556: }
557:
558: return result;
559: }
560:
561: static LLONG
562: ROUND(LDOUBLE value)
563: {
564: LLONG intpart;
565:
566: intpart = (LLONG)value;
567: value = value - intpart;
568: if (value >= 0.5) intpart++;
569:
570: return intpart;
571: }
572:
573: /* a replacement for modf that doesn't need the math library. Should
574: be portable, but slow */
575: static double
576: my_modf(double x0, double *iptr)
577: {
578: int i;
579: long l;
580: double x = x0;
581: double f = 1.0;
582:
583: for (i=0;i<100;i++) {
584: l = (long)x;
585: if (l <= (x+1) && l >= (x-1)) break;
586: x *= 0.1;
587: f *= 10.0;
588: }
589:
590: if (i == 100) {
591: /* yikes! the number is beyond what we can handle. What do we do? */
592: (*iptr) = 0;
593: return 0;
594: }
595:
596: if (i != 0) {
597: double i2;
598: double ret;
599:
600: ret = my_modf(x0-l*f, &i2);
601: (*iptr) = l*f + i2;
602: return ret;
603: }
604:
605: (*iptr) = l;
606: return x - (*iptr);
607: }
608:
609:
610: static void
611: fmtfp (char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue,
612: int min, int max, int flags)
613: {
614: int signvalue = 0;
615: double ufvalue;
616: char iconvert[311];
617: char fconvert[311];
618: int iplace = 0;
619: int fplace = 0;
620: int padlen = 0; /* amount to pad */
621: int zpadlen = 0;
622: int caps = 0;
623: int index;
624: double intpart;
625: double fracpart;
626: double temp;
627:
628: /*
629: * AIX manpage says the default is 0, but Solaris says the default
630: * is 6, and sprintf on AIX defaults to 6
631: */
632: if (max < 0)
633: max = 6;
634:
635: ufvalue = abs_val (fvalue);
636:
637: if (fvalue < 0) {
638: signvalue = '-';
639: } else {
640: if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
641: signvalue = '+';
642: } else {
643: if (flags & DP_F_SPACE)
644: signvalue = ' ';
645: }
646: }
647:
648: /*
649: * Sorry, we only support 16 digits past the decimal because of our
650: * conversion method
651: */
652: if (max > 16)
653: max = 16;
654:
655: /* We "cheat" by converting the fractional part to integer by
656: * multiplying by a factor of 10
657: */
658:
659: temp = ufvalue;
660: my_modf(temp, &intpart);
661:
662: fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
663:
664: if (fracpart >= POW10(max)) {
665: intpart++;
666: fracpart -= POW10(max);
667: }
668:
669:
670: /* Convert integer part */
671: do {
672: temp = intpart;
673: my_modf(intpart*0.1, &intpart);
674: temp = temp*0.1;
675: index = (int) ((temp -intpart +0.05)* 10.0);
676: /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
677: /* printf ("%llf, %f, %x\n", temp, intpart, index); */
678: iconvert[iplace++] =
679: (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
680: } while (intpart && (iplace < 311));
681: if (iplace == 311) iplace--;
682: iconvert[iplace] = 0;
683:
684: /* Convert fractional part */
685: if (fracpart)
686: {
687: do {
688: temp = fracpart;
689: my_modf(fracpart*0.1, &fracpart);
690: temp = temp*0.1;
691: index = (int) ((temp -fracpart +0.05)* 10.0);
692: /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */
693: /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */
694: fconvert[fplace++] =
695: (caps? "0123456789ABCDEF":"0123456789abcdef")[index];
696: } while(fracpart && (fplace < 311));
697: if (fplace == 311) fplace--;
698: }
699: fconvert[fplace] = 0;
700:
701: /* -1 for decimal point, another -1 if we are printing a sign */
702: padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
703: zpadlen = max - fplace;
704: if (zpadlen < 0) zpadlen = 0;
705: if (padlen < 0)
706: padlen = 0;
707: if (flags & DP_F_MINUS)
708: padlen = -padlen; /* Left Justifty */
709:
710: if ((flags & DP_F_ZERO) && (padlen > 0)) {
711: if (signvalue) {
712: dopr_outch (buffer, currlen, maxlen, signvalue);
713: --padlen;
714: signvalue = 0;
715: }
716: while (padlen > 0) {
717: dopr_outch (buffer, currlen, maxlen, '0');
718: --padlen;
719: }
720: }
721: while (padlen > 0) {
722: dopr_outch (buffer, currlen, maxlen, ' ');
723: --padlen;
724: }
725: if (signvalue)
726: dopr_outch (buffer, currlen, maxlen, signvalue);
727:
728: while (iplace > 0)
729: dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
730:
731: #ifdef DEBUG_SNPRINTF
732: printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
733: #endif
734:
735: /*
736: * Decimal point. This should probably use locale to find the correct
737: * char to print out.
738: */
739: if (max > 0) {
740: dopr_outch (buffer, currlen, maxlen, '.');
741:
742: while (fplace > 0)
743: dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
744: }
745:
746: while (zpadlen > 0) {
747: dopr_outch (buffer, currlen, maxlen, '0');
748: --zpadlen;
749: }
750:
751: while (padlen < 0) {
752: dopr_outch (buffer, currlen, maxlen, ' ');
753: ++padlen;
754: }
755: }
756:
757: static void
758: dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
759: {
760: if (*currlen < maxlen) {
761: buffer[(*currlen)] = c;
762: }
763: (*currlen)++;
764: }
765:
766: #if !defined(HAVE_VSNPRINTF)
767: int
768: vsnprintf (char *str, size_t count, const char *fmt, va_list args)
769: {
770: return dopr(str, count, fmt, args);
771: }
772: #endif
773:
774: #if !defined(HAVE_SNPRINTF)
775: #ifdef PROTOTYPES
776: int
777: snprintf(char *str, size_t count, const char *fmt, ...)
778: #else
779: int
780: snprintf(str, count, fmt, va_alist)
781: char *str;
782: size_t count;
783: const char *fmt;
784: va_dcl
785: #endif
786: {
787: size_t ret;
788: va_list ap;
789:
790: va_start(ap, fmt);
791: ret = vsnprintf(str, count, fmt, ap);
792: va_end(ap);
793: return ret;
794: }
795: #endif
796:
797: #endif
798:
799: /* -eof- */
CVSweb