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