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