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