Made it 2.0.0, and removed the changes that are in 1.1.x, as
[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_SNPRINTF and HAVE_VSNPRINTF
28    1.3:
29       *  add #include <config.h> ifdef HAVE_CONFIG_H
30       *  cosmetic change, when exponent is 0 print xxxE+00
31          instead of xxxE-00
32    1.2:
33       *  put the program under LGPL.
34    1.1:
35       *  added changes from Miles Bader
36       *  corrected a bug with %f
37       *  added support for %#g
38       *  added more comments :-)
39    1.0:
40       *  supporting must ANSI syntaxic_sugars
41    0.0:
42       *  suppot %s %c %d
43
44  THANKS(for the patches and ideas):
45      Miles Bader
46      Cyrille Rustom
47      Jacek Slabocewiz
48      Mike Parker(mouse)
49
50 */
51
52 #include <freeradius-devel/autoconf.h>
53 #include "snprintf.h"
54
55 #ifndef HAVE_VSNPRINTF
56
57 /*
58  * Find the nth power of 10
59  */
60 PRIVATE double
61 #ifdef __STDC__
62 pow_10(int n)
63 #else
64 pow_10(n)
65 int n;
66 #endif
67 {
68   int i;
69   double P;
70
71   if (n < 0)
72     for (i = 1, P = 1., n = -n ; i <= n ; i++) {P *= .1;}
73   else
74     for (i = 1, P = 1. ; i <= n ; i++) {P *= 10.0;}
75   return P;
76 }
77
78 /*
79  * Find the integral part of the log in base 10
80  * Note: this not a real log10()
81          I just need and approximation(integerpart) of x in:
82           10^x ~= r
83  * log_10(200) = 2;
84  * log_10(250) = 2;
85  */
86 PRIVATE int
87 #ifdef __STDC__
88 log_10(double r)
89 #else
90 log_10(r)
91 double r;
92 #endif
93 {
94   int i = 0;
95   double result = 1.;
96
97   if (r < 0.)
98     r = -r;
99
100   if (r < 1.) {
101     while (result >= r) {result *= .1; i++;}
102     return (-i);
103   } else {
104     while (result <= r) {result *= 10.; i++;}
105     return (i - 1);
106   }
107 }
108
109 /*
110  * This function return the fraction part of a double
111  * and set in ip the integral part.
112  * In many ways it resemble the modf() found on most Un*x
113  */
114 PRIVATE double
115 #ifdef __STDC__
116 integral(double real, double * ip)
117 #else
118 integral(real, ip)
119 double real;
120 double * ip;
121 #endif
122 {
123   int j;
124   double i, s, p;
125   double real_integral = 0.;
126
127 /* take care of the obvious */
128 /* equal to zero ? */
129   if (real == 0.) {
130     *ip = 0.;
131     return (0.);
132   }
133
134 /* negative number ? */
135   if (real < 0.)
136     real = -real;
137
138 /* a fraction ? */
139   if ( real < 1.) {
140     *ip = 0.;
141     return real;
142   }
143 /* the real work :-) */
144   for (j = log_10(real); j >= 0; j--) {
145     p = pow_10(j);
146     s = (real - real_integral)/p;
147     i = 0.;
148     while (i + 1. <= s) {i++;}
149     real_integral += i*p;
150   }
151   *ip = real_integral;
152   return (real - real_integral);
153 }
154
155 #define PRECISION 1.e-6
156 /*
157  * return an ascii representation of the integral part of the number
158  * and set fract to be an ascii representation of the fraction part
159  * the container for the fraction and the integral part or staticly
160  * declare with fix size
161  */
162 PRIVATE char *
163 #ifdef __STDC__
164 numtoa(double number, int base, int precision, char ** fract)
165 #else
166 numtoa(number, base, precision, fract)
167 double number;
168 int base;
169 int precision;
170 char ** fract;
171 #endif
172 {
173   register int i, j;
174   double ip, fp; /* integer and fraction part */
175   double fraction;
176   int digits = MAX_INT - 1;
177   static char integral_part[MAX_INT];
178   static char fraction_part[MAX_FRACT];
179   double sign;
180   int ch;
181
182 /* taking care of the obvious case: 0.0 */
183   if (number == 0.) {
184     integral_part[0] = '0';
185     integral_part[1] = '\0';
186     fraction_part[0] = '0';
187     fraction_part[1] = '\0';
188     return integral_part;
189   }
190
191 /* for negative numbers */
192   if ((sign = number) < 0.) {
193     number = -number;
194     digits--; /* sign consume one digit */
195   }
196
197   fraction = integral(number, &ip);
198   number = ip;
199 /* do the integral part */
200   if ( ip == 0.) {
201     integral_part[0] = '0';
202     i = 1;
203   } else {
204     for ( i = 0; i < digits && number != 0.; ++i) {
205       number /= base;
206       fp = integral(number, &ip);
207       ch = (int)((fp + PRECISION)*base); /* force to round */
208       integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10;
209       if (! isxdigit(integral_part[i])) /* bail out overflow !! */
210         break;
211       number = ip;
212      }
213   }
214
215 /* Oh No !! out of bound, ho well fill it up ! */
216   if (number != 0.)
217     for (i = 0; i < digits; ++i)
218       integral_part[i] = '9';
219
220 /* put the sign ? */
221   if (sign < 0.)
222     integral_part[i++] = '-';
223
224   integral_part[i] = '\0';
225
226 /* reverse every thing */
227   for ( i--, j = 0; j < i; j++, i--)
228     SWAP_INT(integral_part[i], integral_part[j]);
229
230 /* the fractionnal part */
231   for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision--      ) {
232     fraction_part[i] = (int)((fp + PRECISION)*10. + '0');
233     if (! isdigit(fraction_part[i])) /* underflow ? */
234       break;
235     fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.);
236   }
237   fraction_part[i] = '\0';
238
239   if (fract != (char **)0)
240     *fract = fraction_part;
241
242   return integral_part;
243
244 }
245
246 /* for %d and friends, it puts in holder
247  * the representation with the right padding
248  */
249 PRIVATE void
250 #ifdef __STDC__
251 decimal(struct DATA *p, double d)
252 #else
253 decimal(p, d)
254 struct DATA *p;
255 double d;
256 #endif
257 {
258   char *tmp;
259
260   tmp = itoa(d);
261   p->width -= strlen(tmp);
262   PAD_RIGHT(p);
263   PUT_PLUS(d, p);
264   PUT_SPACE(d, p);
265   while (*tmp) { /* the integral */
266     PUT_CHAR(*tmp, p);
267     tmp++;
268   }
269   PAD_LEFT(p);
270 }
271
272 /* for %o octal representation */
273 PRIVATE void
274 #ifdef __STDC__
275 octal(struct DATA *p, double d)
276 #else
277 octal(p, d)
278 struct DATA *p;
279 double d;
280 #endif
281 {
282   char *tmp;
283
284   tmp = otoa(d);
285   p->width -= strlen(tmp);
286   PAD_RIGHT(p);
287   if (p->square == FOUND) /* had prefix '0' for octal */
288     PUT_CHAR('0', p);
289   while (*tmp) { /* octal */
290     PUT_CHAR(*tmp, p);
291     tmp++;
292   }
293   PAD_LEFT(p);
294 }
295
296 /* for %x %X hexadecimal representation */
297 PRIVATE void
298 #ifdef __STDC__
299 hexa(struct DATA *p, double d)
300 #else
301 hexa(p, d)
302 struct DATA *p;
303 double d;
304 #endif
305 {
306   char *tmp;
307
308   tmp = htoa(d);
309   p->width -= strlen(tmp);
310   PAD_RIGHT(p);
311   if (p->square == FOUND) { /* prefix '0x' for hexa */
312     PUT_CHAR('0', p); PUT_CHAR(*p->pf, p);
313   }
314   while (*tmp) { /* hexa */
315     PUT_CHAR((*p->pf == 'X' ? toupper(*tmp) : *tmp), p);
316     tmp++;
317   }
318   PAD_LEFT(p);
319 }
320
321 /* %s strings */
322 PRIVATE void
323 #ifdef __STDC__
324 strings(struct DATA *p, char *tmp)
325 #else
326 strings(p, tmp)
327 struct DATA *p;
328 char *tmp;
329 #endif
330 {
331   int i;
332
333   i = strlen(tmp);
334   if (p->precision != NOT_FOUND) /* the smallest number */
335     i = (i < p->precision ? i : p->precision);
336   p->width -= i;
337   PAD_RIGHT(p);
338   while (i-- > 0) { /* put the sting */
339     PUT_CHAR(*tmp, p);
340     tmp++;
341   }
342   PAD_LEFT(p);
343 }
344
345 /* %f or %g  floating point representation */
346 PRIVATE void
347 #ifdef __STDC__
348 floating(struct DATA *p, double d)
349 #else
350 floating(p, d)
351 struct DATA *p;
352 double d;
353 #endif
354 {
355   char *tmp, *tmp2;
356   int i;
357
358   DEF_PREC(p);
359   d = ROUND(d, p);
360   tmp = dtoa(d, p->precision, &tmp2);
361   /* calculate the padding. 1 for the dot */
362   p->width = p->width -
363             ((d > 0. && p->justify == RIGHT) ? 1:0) -
364             ((p->space == FOUND) ? 1:0) -
365             strlen(tmp) - p->precision - 1;
366   PAD_RIGHT(p);
367   PUT_PLUS(d, p);
368   PUT_SPACE(d, p);
369   while (*tmp) { /* the integral */
370     PUT_CHAR(*tmp, p);
371     tmp++;
372   }
373   if (p->precision != 0 || p->square == FOUND)
374     PUT_CHAR('.', p);  /* put the '.' */
375   if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
376     for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
377        tmp2[i] = '\0';
378   for (; *tmp2; tmp2++)
379     PUT_CHAR(*tmp2, p); /* the fraction */
380
381   PAD_LEFT(p);
382 }
383
384 /* %e %E %g exponent representation */
385 PRIVATE void
386 #ifdef __STDC__
387 exponent(struct DATA *p, double d)
388 #else
389 exponent(p, d)
390 struct DATA *p;
391 double d;
392 #endif
393 {
394   char *tmp, *tmp2;
395   int j, i;
396
397   DEF_PREC(p);
398   j = log_10(d);
399   d = d / pow_10(j);  /* get the Mantissa */
400   d = ROUND(d, p);
401   tmp = dtoa(d, p->precision, &tmp2);
402   /* 1 for unit, 1 for the '.', 1 for 'e|E',
403    * 1 for '+|-', 3 for 'exp' */
404   /* calculate how much padding need */
405   p->width = p->width -
406              ((d > 0. && p->justify == RIGHT) ? 1:0) -
407              ((p->space == FOUND) ? 1:0) - p->precision - 7;
408   PAD_RIGHT(p);
409   PUT_PLUS(d, p);
410   PUT_SPACE(d, p);
411   while (*tmp) {/* the integral */
412     PUT_CHAR(*tmp, p);
413     tmp++;
414   }
415   if (p->precision != 0 || p->square == FOUND)
416     PUT_CHAR('.', p);  /* the '.' */
417   if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
418     for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
419        tmp2[i] = '\0';
420   for (; *tmp2; tmp2++)
421     PUT_CHAR(*tmp2, p); /* the fraction */
422
423   if (*p->pf == 'g' || *p->pf == 'e') { /* the exponent put the 'e|E' */
424     PUT_CHAR('e', p);
425   } else
426     PUT_CHAR('E', p);
427   if (j >= 0) {  /* the sign of the exp */
428     PUT_CHAR('+', p);
429   } else {
430     PUT_CHAR('-', p);
431     j = -j;
432   }
433   tmp = itoa((double)j);
434   if (j < 9) {  /* need to pad the exponent with 0 '000' */
435     PUT_CHAR('0', p); PUT_CHAR('0', p);
436   } else if (j < 99)
437     PUT_CHAR('0', p);
438   while (*tmp) { /* the exponent */
439     PUT_CHAR(*tmp, p);
440     tmp++;
441   }
442   PAD_LEFT(p);
443 }
444
445 /* initialize the conversion specifiers */
446 PRIVATE void
447 #ifdef __STDC__
448 conv_flag(char * s, struct DATA * p)
449 #else
450 conv_flag(s, p)
451 char * s;
452 struct DATA * p;
453 #endif
454 {
455   char number[MAX_FIELD/2];
456   int i;
457
458   /* reset the flags.  */
459   p->precision = p->width = NOT_FOUND;
460   p->star_w = p->star_p = NOT_FOUND;
461   p->square = p->space = NOT_FOUND;
462   p->a_long = p->justify = NOT_FOUND;
463   p->a_longlong = NOT_FOUND;
464   p->pad = ' ';
465
466   for(;s && *s ;s++) {
467     switch(*s) {
468       case ' ': p->space = FOUND; break;
469       case '#': p->square = FOUND; break;
470       case '*': if (p->width == NOT_FOUND)
471                   p->width = p->star_w = FOUND;
472                 else
473                   p->precision = p->star_p = FOUND;
474                 break;
475       case '+': p->justify = RIGHT; break;
476       case '-': p->justify = LEFT; break;
477       case '.': if (p->width == NOT_FOUND)
478                   p->width = 0;
479                 break;
480       case '0': p->pad = '0'; break;
481       case '1': case '2': case '3':
482       case '4': case '5': case '6':
483       case '7': case '8': case '9':     /* gob all the digits */
484         for (i = 0; isdigit(*s); i++, s++)
485           if (i < MAX_FIELD/2 - 1)
486             number[i] = *s;
487         number[i] = '\0';
488         if (p->width == NOT_FOUND)
489           p->width = atoi(number);
490         else
491           p->precision = atoi(number);
492         s--;   /* went to far go back */
493         break;
494     }
495   }
496 }
497
498 PUBLIC int
499 #ifdef __STDC__
500 vsnprintf(char *string, size_t length, const char * format, va_list args)
501 #else
502 vsnprintf(string, length, format, args)
503 char *string;
504 size_t length;
505 char * format;
506 va_list args;
507 #endif
508 {
509   struct DATA data;
510   char conv_field[MAX_FIELD];
511   double d; /* temporary holder */
512   int state;
513   int i;
514
515   data.length = length - 1; /* leave room for '\0' */
516   data.holder = string;
517   data.pf = format;
518   data.counter = 0;
519
520
521 /* sanity check, the string must be > 1 */
522   if (length < 1)
523     return -1;
524
525
526   for (; *data.pf && (data.counter < data.length); data.pf++) {
527     if ( *data.pf == '%' ) { /* we got a magic % cookie */
528       conv_flag((char *)0, &data); /* initialise format flags */
529       for (state = 1; *data.pf && state;) {
530         switch (*(++data.pf)) {
531           case '\0': /* a NULL here ? ? bail out */
532             *data.holder = '\0';
533             return data.counter;
534             break;
535           case 'f':  /* float, double */
536             STAR_ARGS(&data);
537             if (data.a_long == FOUND)
538                d = va_arg(args, LONG_DOUBLE);
539             else
540                d = va_arg(args, double);
541             floating(&data, d);
542             state = 0;
543             break;
544           case 'g':
545           case 'G':
546             STAR_ARGS(&data);
547             DEF_PREC(&data);
548             if (data.a_long == FOUND)
549                d = va_arg(args, LONG_DOUBLE);
550             else
551                d = va_arg(args, double);
552             i = log_10(d);
553             /*
554              * for '%g|%G' ANSI: use f if exponent
555              * is in the range or [-4,p] exclusively
556              * else use %e|%E
557              */
558             if (-4 < i && i < data.precision)
559               floating(&data, d);
560             else
561               exponent(&data, d);
562             state = 0;
563             break;
564           case 'e':
565           case 'E':  /* Exponent double */
566             STAR_ARGS(&data);
567             if (data.a_long == FOUND)
568                d = va_arg(args, LONG_DOUBLE);
569             else
570                d = va_arg(args, double);
571             exponent(&data, d);
572             state = 0;
573             break;
574           case 'u':  /* unsigned decimal */
575             STAR_ARGS(&data);
576             if (data.a_longlong == FOUND)
577               d = va_arg(args, unsigned LONG_LONG);
578             else if (data.a_long == FOUND)
579               d = va_arg(args, unsigned long);
580             else
581               d = va_arg(args, unsigned int);
582             decimal(&data, d);
583             state = 0;
584             break;
585           case 'd':  /* decimal */
586             STAR_ARGS(&data);
587             if (data.a_longlong == FOUND)
588               d = va_arg(args, LONG_LONG);
589             else if (data.a_long == FOUND)
590               d = va_arg(args, long);
591             else
592               d = va_arg(args, int);
593             decimal(&data, d);
594             state = 0;
595             break;
596           case 'o':  /* octal */
597             STAR_ARGS(&data);
598             if (data.a_longlong == FOUND)
599               d = va_arg(args, LONG_LONG);
600             else if (data.a_long == FOUND)
601               d = va_arg(args, long);
602             else
603               d = va_arg(args, int);
604             octal(&data, d);
605             state = 0;
606             break;
607           case 'x':
608           case 'X':  /* hexadecimal */
609             STAR_ARGS(&data);
610             if (data.a_longlong == FOUND)
611               d = va_arg(args, LONG_LONG);
612             else if (data.a_long == FOUND)
613               d = va_arg(args, long);
614             else
615               d = va_arg(args, int);
616             hexa(&data, d);
617             state = 0;
618             break;
619           case 'c': /* character */
620             d = va_arg(args, int);
621             PUT_CHAR(d, &data);
622             state = 0;
623             break;
624           case 's':  /* string */
625             STAR_ARGS(&data);
626             strings(&data, va_arg(args, char *));
627             state = 0;
628             break;
629           case 'n':
630             *(va_arg(args, int *)) = data.counter; /* what's the count ? */
631             state = 0;
632             break;
633           case 'q':
634             data.a_longlong = FOUND;
635             break;
636           case 'L':
637           case 'l':
638             if (data.a_long == FOUND)
639               data.a_longlong = FOUND;
640             else
641               data.a_long = FOUND;
642             break;
643           case 'h':
644             break;
645           case '%':  /* nothing just % */
646             PUT_CHAR('%', &data);
647             state = 0;
648             break;
649           case '#': case ' ': case '+': case '*':
650           case '-': case '.': case '0': case '1':
651           case '2': case '3': case '4': case '5':
652           case '6': case '7': case '8': case '9':
653            /* initialize width and precision */
654             for (i = 0; isflag(*data.pf); i++, data.pf++)
655               if (i < MAX_FIELD - 1)
656                 conv_field[i] = *data.pf;
657             conv_field[i] = '\0';
658             conv_flag(conv_field, &data);
659             data.pf--;   /* went to far go back */
660             break;
661           default:
662             /* is this an error ? maybe bail out */
663             state = 0;
664             break;
665         } /* end switch */
666       } /* end of for state */
667     } else { /* not % */
668       PUT_CHAR(*data.pf, &data);  /* add the char the string */
669     }
670   }
671
672   *data.holder = '\0'; /* the end ye ! */
673
674   return data.counter;
675 }
676
677 #endif /* HAVE_VSNPRINTF */
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 /* !DRIVER */