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