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