import from HEAD
[freeradius.git] / src / lib / snprintf.c
1
2 /*
3    Unix snprintf implementation.
4    Version 1.4
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU Library General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20    Revision History:
21
22    1.4:
23       *  integrate in FreeRADIUS's libradius:
24           *  Fetched from: http://savannah.gnu.org/cgi-bin/viewcvs/mailutils/mailutils/lib/snprintf.c?rev=1.4
25           *  Fetched from: http://savannah.gnu.org/cgi-bin/viewcvs/mailutils/mailutils/lib/snprintf.h?rev=1.4
26           *  Replace config.h with autoconf.h
27           *  Protect with HAVE_LOCAL_SNPRINTF
28   
29    1.3:
30       *  add #include <config.h> ifdef HAVE_CONFIG_H
31       *  cosmetic change, when exponent is 0 print xxxE+00
32          instead of xxxE-00
33    1.2:
34       *  put the program under LGPL.
35    1.1:
36       *  added changes from Miles Bader
37       *  corrected a bug with %f
38       *  added support for %#g
39       *  added more comments :-)
40    1.0:
41       *  supporting must ANSI syntaxic_sugars
42    0.0:
43       *  suppot %s %c %d
44
45  THANKS(for the patches and ideas):
46      Miles Bader
47      Cyrille Rustom
48      Jacek Slabocewiz
49      Mike Parker(mouse)
50
51 */
52
53 #include "autoconf.h"
54
55 #ifdef HAVE_LOCAL_SNPRINTF
56
57 #include "snprintf.h"
58
59 /*
60  * Find the nth power of 10
61  */
62 PRIVATE double
63 #ifdef __STDC__
64 pow_10(int n)
65 #else
66 pow_10(n)
67 int n;
68 #endif
69 {
70   int i;
71   double P;
72
73   if (n < 0)
74     for (i = 1, P = 1., n = -n ; i <= n ; i++) {P *= .1;}
75   else
76     for (i = 1, P = 1. ; i <= n ; i++) {P *= 10.0;}
77   return P;
78 }
79
80 /*
81  * Find the integral part of the log in base 10
82  * Note: this not a real log10()
83          I just need and approximation(integerpart) of x in:
84           10^x ~= r
85  * log_10(200) = 2;
86  * log_10(250) = 2;
87  */
88 PRIVATE int
89 #ifdef __STDC__
90 log_10(double r)
91 #else
92 log_10(r)
93 double r;
94 #endif
95 {
96   int i = 0;
97   double result = 1.;
98
99   if (r < 0.)
100     r = -r;
101
102   if (r < 1.) {
103     while (result >= r) {result *= .1; i++;}
104     return (-i);
105   } else {
106     while (result <= r) {result *= 10.; i++;}
107     return (i - 1);
108   }
109 }
110
111 /*
112  * This function return the fraction part of a double
113  * and set in ip the integral part.
114  * In many ways it resemble the modf() found on most Un*x
115  */
116 PRIVATE double
117 #ifdef __STDC__
118 integral(double real, double * ip)
119 #else
120 integral(real, ip)
121 double real;
122 double * ip;
123 #endif
124 {
125   int j;
126   double i, s, p;
127   double real_integral = 0.;
128
129 /* take care of the obvious */
130 /* equal to zero ? */
131   if (real == 0.) {
132     *ip = 0.;
133     return (0.);
134   }
135
136 /* negative number ? */
137   if (real < 0.)
138     real = -real;
139
140 /* a fraction ? */
141   if ( real < 1.) {
142     *ip = 0.;
143     return real;
144   }
145 /* the real work :-) */
146   for (j = log_10(real); j >= 0; j--) {
147     p = pow_10(j);
148     s = (real - real_integral)/p;
149     i = 0.;
150     while (i + 1. <= s) {i++;}
151     real_integral += i*p;
152   }
153   *ip = real_integral;
154   return (real - real_integral);
155 }
156
157 #define PRECISION 1.e-6
158 /*
159  * return an ascii representation of the integral part of the number
160  * and set fract to be an ascii representation of the fraction part
161  * the container for the fraction and the integral part or staticly
162  * declare with fix size
163  */
164 PRIVATE char *
165 #ifdef __STDC__
166 numtoa(double number, int base, int precision, char ** fract)
167 #else
168 numtoa(number, base, precision, fract)
169 double number;
170 int base;
171 int precision;
172 char ** fract;
173 #endif
174 {
175   register int i, j;
176   double ip, fp; /* integer and fraction part */
177   double fraction;
178   int digits = MAX_INT - 1;
179   static char integral_part[MAX_INT];
180   static char fraction_part[MAX_FRACT];
181   double sign;
182   int ch;
183
184 /* taking care of the obvious case: 0.0 */
185   if (number == 0.) {
186     integral_part[0] = '0';
187     integral_part[1] = '\0';
188     fraction_part[0] = '0';
189     fraction_part[1] = '\0';
190     return integral_part;
191   }
192
193 /* for negative numbers */
194   if ((sign = number) < 0.) {
195     number = -number;
196     digits--; /* sign consume one digit */
197   }
198
199   fraction = integral(number, &ip);
200   number = ip;
201 /* do the integral part */
202   if ( ip == 0.) {
203     integral_part[0] = '0';
204     i = 1;
205   } else {
206     for ( i = 0; i < digits && number != 0.; ++i) {
207       number /= base;
208       fp = integral(number, &ip);
209       ch = (int)((fp + PRECISION)*base); /* force to round */
210       integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10;
211       if (! isxdigit(integral_part[i])) /* bail out overflow !! */
212         break;
213       number = ip;
214      }
215   }
216
217 /* Oh No !! out of bound, ho well fill it up ! */
218   if (number != 0.)
219     for (i = 0; i < digits; ++i)
220       integral_part[i] = '9';
221
222 /* put the sign ? */
223   if (sign < 0.)
224     integral_part[i++] = '-';
225
226   integral_part[i] = '\0';
227
228 /* reverse every thing */
229   for ( i--, j = 0; j < i; j++, i--)
230     SWAP_INT(integral_part[i], integral_part[j]);
231
232 /* the fractionnal part */
233   for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision--      ) {
234     fraction_part[i] = (int)((fp + PRECISION)*10. + '0');
235     if (! isdigit(fraction_part[i])) /* underflow ? */
236       break;
237     fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.);
238   }
239   fraction_part[i] = '\0';
240
241   if (fract != (char **)0)
242     *fract = fraction_part;
243
244   return integral_part;
245
246 }
247
248 /* for %d and friends, it puts in holder
249  * the representation with the right padding
250  */
251 PRIVATE void
252 #ifdef __STDC__
253 decimal(struct DATA *p, double d)
254 #else
255 decimal(p, d)
256 struct DATA *p;
257 double d;
258 #endif
259 {
260   char *tmp;
261
262   tmp = itoa(d);
263   p->width -= strlen(tmp);
264   PAD_RIGHT(p);
265   PUT_PLUS(d, p);
266   PUT_SPACE(d, p);
267   while (*tmp) { /* the integral */
268     PUT_CHAR(*tmp, p);
269     tmp++;
270   }
271   PAD_LEFT(p);
272 }
273
274 /* for %o octal representation */
275 PRIVATE void
276 #ifdef __STDC__
277 octal(struct DATA *p, double d)
278 #else
279 octal(p, d)
280 struct DATA *p;
281 double d;
282 #endif
283 {
284   char *tmp;
285
286   tmp = otoa(d);
287   p->width -= strlen(tmp);
288   PAD_RIGHT(p);
289   if (p->square == FOUND) /* had prefix '0' for octal */
290     PUT_CHAR('0', p);
291   while (*tmp) { /* octal */
292     PUT_CHAR(*tmp, p);
293     tmp++;
294   }
295   PAD_LEFT(p);
296 }
297
298 /* for %x %X hexadecimal representation */
299 PRIVATE void
300 #ifdef __STDC__
301 hexa(struct DATA *p, double d)
302 #else
303 hexa(p, d)
304 struct DATA *p;
305 double d;
306 #endif
307 {
308   char *tmp;
309
310   tmp = htoa(d);
311   p->width -= strlen(tmp);
312   PAD_RIGHT(p);
313   if (p->square == FOUND) { /* prefix '0x' for hexa */
314     PUT_CHAR('0', p); PUT_CHAR(*p->pf, p);
315   }
316   while (*tmp) { /* hexa */
317     PUT_CHAR((*p->pf == 'X' ? toupper(*tmp) : *tmp), p);
318     tmp++;
319   }
320   PAD_LEFT(p);
321 }
322
323 /* %s strings */
324 PRIVATE void
325 #ifdef __STDC__
326 strings(struct DATA *p, char *tmp)
327 #else
328 strings(p, tmp)
329 struct DATA *p;
330 char *tmp;
331 #endif
332 {
333   int i;
334
335   i = strlen(tmp);
336   if (p->precision != NOT_FOUND) /* the smallest number */
337     i = (i < p->precision ? i : p->precision);
338   p->width -= i;
339   PAD_RIGHT(p);
340   while (i-- > 0) { /* put the sting */
341     PUT_CHAR(*tmp, p);
342     tmp++;
343   }
344   PAD_LEFT(p);
345 }
346
347 /* %f or %g  floating point representation */
348 PRIVATE void
349 #ifdef __STDC__
350 floating(struct DATA *p, double d)
351 #else
352 floating(p, d)
353 struct DATA *p;
354 double d;
355 #endif
356 {
357   char *tmp, *tmp2;
358   int i;
359
360   DEF_PREC(p);
361   d = ROUND(d, p);
362   tmp = dtoa(d, p->precision, &tmp2);
363   /* calculate the padding. 1 for the dot */
364   p->width = p->width -
365             ((d > 0. && p->justify == RIGHT) ? 1:0) -
366             ((p->space == FOUND) ? 1:0) -
367             strlen(tmp) - p->precision - 1;
368   PAD_RIGHT(p);
369   PUT_PLUS(d, p);
370   PUT_SPACE(d, p);
371   while (*tmp) { /* the integral */
372     PUT_CHAR(*tmp, p);
373     tmp++;
374   }
375   if (p->precision != 0 || p->square == FOUND)
376     PUT_CHAR('.', p);  /* put the '.' */
377   if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
378     for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
379        tmp2[i] = '\0';
380   for (; *tmp2; tmp2++)
381     PUT_CHAR(*tmp2, p); /* the fraction */
382
383   PAD_LEFT(p);
384 }
385
386 /* %e %E %g exponent representation */
387 PRIVATE void
388 #ifdef __STDC__
389 exponent(struct DATA *p, double d)
390 #else
391 exponent(p, d)
392 struct DATA *p;
393 double d;
394 #endif
395 {
396   char *tmp, *tmp2;
397   int j, i;
398
399   DEF_PREC(p);
400   j = log_10(d);
401   d = d / pow_10(j);  /* get the Mantissa */
402   d = ROUND(d, p);
403   tmp = dtoa(d, p->precision, &tmp2);
404   /* 1 for unit, 1 for the '.', 1 for 'e|E',
405    * 1 for '+|-', 3 for 'exp' */
406   /* calculate how much padding need */
407   p->width = p->width -
408              ((d > 0. && p->justify == RIGHT) ? 1:0) -
409              ((p->space == FOUND) ? 1:0) - p->precision - 7;
410   PAD_RIGHT(p);
411   PUT_PLUS(d, p);
412   PUT_SPACE(d, p);
413   while (*tmp) {/* the integral */
414     PUT_CHAR(*tmp, p);
415     tmp++;
416   }
417   if (p->precision != 0 || p->square == FOUND)
418     PUT_CHAR('.', p);  /* the '.' */
419   if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
420     for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
421        tmp2[i] = '\0';
422   for (; *tmp2; tmp2++)
423     PUT_CHAR(*tmp2, p); /* the fraction */
424
425   if (*p->pf == 'g' || *p->pf == 'e') { /* the exponent put the 'e|E' */
426     PUT_CHAR('e', p);
427   } else
428     PUT_CHAR('E', p);
429   if (j >= 0) {  /* the sign of the exp */
430     PUT_CHAR('+', p);
431   } else {
432     PUT_CHAR('-', p);
433     j = -j;
434   }
435   tmp = itoa((double)j);
436   if (j < 9) {  /* need to pad the exponent with 0 '000' */
437     PUT_CHAR('0', p); PUT_CHAR('0', p);
438   } else if (j < 99)
439     PUT_CHAR('0', p);
440   while (*tmp) { /* the exponent */
441     PUT_CHAR(*tmp, p);
442     tmp++;
443   }
444   PAD_LEFT(p);
445 }
446
447 /* initialize the conversion specifiers */
448 PRIVATE void
449 #ifdef __STDC__
450 conv_flag(char * s, struct DATA * p)
451 #else
452 conv_flag(s, p)
453 char * s;
454 struct DATA * p;
455 #endif
456 {
457   char number[MAX_FIELD/2];
458   int i;
459
460   /* reset the flags.  */
461   p->precision = p->width = NOT_FOUND;
462   p->star_w = p->star_p = NOT_FOUND;
463   p->square = p->space = NOT_FOUND;
464   p->a_long = p->justify = NOT_FOUND;
465   p->a_longlong = NOT_FOUND;
466   p->pad = ' ';
467
468   for(;s && *s ;s++) {
469     switch(*s) {
470       case ' ': p->space = FOUND; break;
471       case '#': p->square = FOUND; break;
472       case '*': if (p->width == NOT_FOUND)
473                   p->width = p->star_w = FOUND;
474                 else
475                   p->precision = p->star_p = FOUND;
476                 break;
477       case '+': p->justify = RIGHT; break;
478       case '-': p->justify = LEFT; break;
479       case '.': if (p->width == NOT_FOUND)
480                   p->width = 0;
481                 break;
482       case '0': p->pad = '0'; break;
483       case '1': case '2': case '3':
484       case '4': case '5': case '6':
485       case '7': case '8': case '9':     /* gob all the digits */
486         for (i = 0; isdigit(*s); i++, s++)
487           if (i < MAX_FIELD/2 - 1)
488             number[i] = *s;
489         number[i] = '\0';
490         if (p->width == NOT_FOUND)
491           p->width = atoi(number);
492         else
493           p->precision = atoi(number);
494         s--;   /* went to far go back */
495         break;
496     }
497   }
498 }
499
500 PUBLIC int
501 #ifdef __STDC__
502 vsnprintf(char *string, size_t length, const char * format, va_list args)
503 #else
504 vsnprintf(string, length, format, args)
505 char *string;
506 size_t length;
507 char * format;
508 va_list args;
509 #endif
510 {
511   struct DATA data;
512   char conv_field[MAX_FIELD];
513   double d; /* temporary holder */
514   int state;
515   int i;
516
517   data.length = length - 1; /* leave room for '\0' */
518   data.holder = string;
519   data.pf = format;
520   data.counter = 0;
521
522
523 /* sanity check, the string must be > 1 */
524   if (length < 1)
525     return -1;
526
527
528   for (; *data.pf && (data.counter < data.length); data.pf++) {
529     if ( *data.pf == '%' ) { /* we got a magic % cookie */
530       conv_flag((char *)0, &data); /* initialise format flags */
531       for (state = 1; *data.pf && state;) {
532         switch (*(++data.pf)) {
533           case '\0': /* a NULL here ? ? bail out */
534             *data.holder = '\0';
535             return data.counter;
536             break;
537           case 'f':  /* float, double */
538             STAR_ARGS(&data);
539             if (data.a_long == FOUND)
540                d = va_arg(args, LONG_DOUBLE);
541             else
542                d = va_arg(args, double);
543             floating(&data, d);
544             state = 0;
545             break;
546           case 'g':
547           case 'G':
548             STAR_ARGS(&data);
549             DEF_PREC(&data);
550             if (data.a_long == FOUND)
551                d = va_arg(args, LONG_DOUBLE);
552             else
553                d = va_arg(args, double);
554             i = log_10(d);
555             /*
556              * for '%g|%G' ANSI: use f if exponent
557              * is in the range or [-4,p] exclusively
558              * else use %e|%E
559              */
560             if (-4 < i && i < data.precision)
561               floating(&data, d);
562             else
563               exponent(&data, d);
564             state = 0;
565             break;
566           case 'e':
567           case 'E':  /* Exponent double */
568             STAR_ARGS(&data);
569             if (data.a_long == FOUND)
570                d = va_arg(args, LONG_DOUBLE);
571             else
572                d = va_arg(args, double);
573             exponent(&data, d);
574             state = 0;
575             break;
576           case 'u':  /* unsigned decimal */
577             STAR_ARGS(&data);
578             if (data.a_longlong == FOUND)
579               d = va_arg(args, unsigned LONG_LONG);
580             else if (data.a_long == FOUND)
581               d = va_arg(args, unsigned long);
582             else
583               d = va_arg(args, unsigned int);
584             decimal(&data, d);
585             state = 0;
586             break;
587           case 'd':  /* decimal */
588             STAR_ARGS(&data);
589             if (data.a_longlong == FOUND)
590               d = va_arg(args, LONG_LONG);
591             else if (data.a_long == FOUND)
592               d = va_arg(args, long);
593             else
594               d = va_arg(args, int);
595             decimal(&data, d);
596             state = 0;
597             break;
598           case 'o':  /* octal */
599             STAR_ARGS(&data);
600             if (data.a_longlong == FOUND)
601               d = va_arg(args, LONG_LONG);
602             else if (data.a_long == FOUND)
603               d = va_arg(args, long);
604             else
605               d = va_arg(args, int);
606             octal(&data, d);
607             state = 0;
608             break;
609           case 'x':
610           case 'X':  /* hexadecimal */
611             STAR_ARGS(&data);
612             if (data.a_longlong == FOUND)
613               d = va_arg(args, LONG_LONG);
614             else if (data.a_long == FOUND)
615               d = va_arg(args, long);
616             else
617               d = va_arg(args, int);
618             hexa(&data, d);
619             state = 0;
620             break;
621           case 'c': /* character */
622             d = va_arg(args, int);
623             PUT_CHAR(d, &data);
624             state = 0;
625             break;
626           case 's':  /* string */
627             STAR_ARGS(&data);
628             strings(&data, va_arg(args, char *));
629             state = 0;
630             break;
631           case 'n':
632             *(va_arg(args, int *)) = data.counter; /* what's the count ? */
633             state = 0;
634             break;
635           case 'q':
636             data.a_longlong = FOUND;
637             break;
638           case 'L':
639           case 'l':
640             if (data.a_long == FOUND)
641               data.a_longlong = FOUND;
642             else
643               data.a_long = FOUND;
644             break;
645           case 'h':
646             break;
647           case '%':  /* nothing just % */
648             PUT_CHAR('%', &data);
649             state = 0;
650             break;
651           case '#': case ' ': case '+': case '*':
652           case '-': case '.': case '0': case '1':
653           case '2': case '3': case '4': case '5':
654           case '6': case '7': case '8': case '9':
655            /* initialize width and precision */
656             for (i = 0; isflag(*data.pf); i++, data.pf++)
657               if (i < MAX_FIELD - 1)
658                 conv_field[i] = *data.pf;
659             conv_field[i] = '\0';
660             conv_flag(conv_field, &data);
661             data.pf--;   /* went to far go back */
662             break;
663           default:
664             /* is this an error ? maybe bail out */
665             state = 0;
666             break;
667         } /* end switch */
668       } /* end of for state */
669     } else { /* not % */
670       PUT_CHAR(*data.pf, &data);  /* add the char the string */
671     }
672   }
673
674   *data.holder = '\0'; /* the end ye ! */
675
676   return data.counter;
677 }
678
679 #ifndef HAVE_SNPRINTF
680
681 PUBLIC int
682 #if __STDC__
683 snprintf(char *string, size_t length, const char * format, ...)
684 #else
685 snprintf(string, length, format, va_alist)
686 char *string;
687 size_t length;
688 char * format;
689 va_dcl
690 #endif
691 {
692   int rval;
693   va_list args;
694
695 #if __STDC__
696   va_start(args, format);
697 #else
698   va_start(args);
699 #endif
700
701   rval = vsnprintf (string, length, format, args);
702
703   va_end(args);
704
705   return rval;
706 }
707
708 #endif /* HAVE_SNPRINTF */
709
710
711 #ifdef DRIVER
712
713 #include <stdio.h>
714
715 /* set of small tests for snprintf() */
716 int main()
717 {
718   char holder[100];
719   int i;
720
721 /*
722   printf("Suite of test for snprintf:\n");
723   printf("a_format\n");
724   printf("printf() format\n");
725   printf("snprintf() format\n\n");
726 */
727 /* Checking the field widths */
728
729   printf("/%%d/, 336\n");
730   snprintf(holder, sizeof holder, "/%d/\n", 336);
731   printf("/%d/\n", 336);
732   printf("%s\n", holder);
733
734   printf("/%%2d/, 336\n");
735   snprintf(holder, sizeof holder, "/%2d/\n", 336);
736   printf("/%2d/\n", 336);
737   printf("%s\n", holder);
738
739   printf("/%%10d/, 336\n");
740   snprintf(holder, sizeof holder, "/%10d/\n", 336);
741   printf("/%10d/\n", 336);
742   printf("%s\n", holder);
743
744   printf("/%%-10d/, 336\n");
745   snprintf(holder, sizeof holder, "/%-10d/\n", 336);
746   printf("/%-10d/\n", 336);
747   printf("%s\n", holder);
748
749 /* long long  */
750
751   printf("/%%lld/, 336\n");
752   snprintf(holder, sizeof holder, "/%lld/\n", (LONG_LONG)336);
753   printf("/%lld/\n", (LONG_LONG)336);
754   printf("%s\n", holder);
755
756   printf("/%%2qd/, 336\n");
757   snprintf(holder, sizeof holder, "/%2qd/\n", (LONG_LONG)336);
758   printf("/%2qd/\n", (LONG_LONG)336);
759   printf("%s\n", holder);
760
761 /* floating points */
762
763   printf("/%%f/, 1234.56\n");
764   snprintf(holder, sizeof holder, "/%f/\n", 1234.56);
765   printf("/%f/\n", 1234.56);
766   printf("%s\n", holder);
767
768   printf("/%%e/, 1234.56\n");
769   snprintf(holder, sizeof holder, "/%e/\n", 1234.56);
770   printf("/%e/\n", 1234.56);
771   printf("%s\n", holder);
772
773   printf("/%%4.2f/, 1234.56\n");
774   snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56);
775   printf("/%4.2f/\n", 1234.56);
776   printf("%s\n", holder);
777
778   printf("/%%3.1f/, 1234.56\n");
779   snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56);
780   printf("/%3.1f/\n", 1234.56);
781   printf("%s\n", holder);
782
783   printf("/%%10.3f/, 1234.56\n");
784   snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56);
785   printf("/%10.3f/\n", 1234.56);
786   printf("%s\n", holder);
787
788   printf("/%%10.3e/, 1234.56\n");
789   snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56);
790   printf("/%10.3e/\n", 1234.56);
791   printf("%s\n", holder);
792
793   printf("/%%+4.2f/, 1234.56\n");
794   snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56);
795   printf("/%+4.2f/\n", 1234.56);
796   printf("%s\n", holder);
797
798   printf("/%%010.2f/, 1234.56\n");
799   snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56);
800   printf("/%010.2f/\n", 1234.56);
801   printf("%s\n", holder);
802
803 #define BLURB "Outstanding acting !"
804 /* strings precisions */
805
806   printf("/%%2s/, \"%s\"\n", BLURB);
807   snprintf(holder, sizeof holder, "/%2s/\n", BLURB);
808   printf("/%2s/\n", BLURB);
809   printf("%s\n", holder);
810
811   printf("/%%22s/ %s\n", BLURB);
812   snprintf(holder, sizeof holder, "/%22s/\n", BLURB);
813   printf("/%22s/\n", BLURB);
814   printf("%s\n", holder);
815
816   printf("/%%22.5s/ %s\n", BLURB);
817   snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB);
818   printf("/%22.5s/\n", BLURB);
819   printf("%s\n", holder);
820
821   printf("/%%-22.5s/ %s\n", BLURB);
822   snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB);
823   printf("/%-22.5s/\n", BLURB);
824   printf("%s\n", holder);
825
826 /* see some flags */
827
828   printf("%%x %%X %%#x, 31, 31, 31\n");
829   snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31);
830   printf("%x %X %#x\n", 31, 31, 31);
831   printf("%s\n", holder);
832
833   printf("**%%d**%% d**%% d**, 42, 42, -42\n");
834   snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42);
835   printf("**%d**% d**% d**\n", 42, 42, -42);
836   printf("%s\n", holder);
837
838 /* other flags */
839
840   printf("/%%g/, 31.4\n");
841   snprintf(holder, sizeof holder, "/%g/\n", 31.4);
842   printf("/%g/\n", 31.4);
843   printf("%s\n", holder);
844
845   printf("/%%.6g/, 31.4\n");
846   snprintf(holder, sizeof holder, "/%.6g/\n", 31.4);
847   printf("/%.6g/\n", 31.4);
848   printf("%s\n", holder);
849
850   printf("/%%.1G/, 31.4\n");
851   snprintf(holder, sizeof holder, "/%.1G/\n", 31.4);
852   printf("/%.1G/\n", 31.4);
853   printf("%s\n", holder);
854
855   printf("abc%%n\n");
856   printf("abc%n", &i); printf("%d\n", i);
857   snprintf(holder, sizeof holder, "abc%n", &i);
858   printf("%s", holder); printf("%d\n\n", i);
859
860   printf("%%*.*s --> 10.10\n");
861   snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB);
862   printf("%*.*s\n", 10, 10, BLURB);
863   printf("%s\n", holder);
864
865   printf("%%%%%%%%\n");
866   snprintf(holder, sizeof holder, "%%%%\n");
867   printf("%%%%\n");
868   printf("%s\n", holder);
869
870 #define BIG "Hello this is a too big string for the buffer"
871 /*  printf("A buffer to small of 10, trying to put this:\n");*/
872   printf("<%%>, %s\n", BIG);
873   i = snprintf(holder, 10, "%s\n", BIG);
874   printf("<%s>\n", BIG);
875   printf("<%s>\n", holder);
876
877   return 0;
878 }
879 #endif
880
881 #endif /* !HAVE_LOCAL_SNPRINTF */