Include <time.h> to declare "gmtime()".
[obnox/wireshark/wip.git] / snprintf-imp.h
1 /*
2  Unix snprintf implementation.
3  Version 1.2
4    
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    It can be redistribute also under the terms of GNU Library General
10    Public Lincense.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21    Revision History:
22
23    1.2:
24       * put under LGPL.
25    1.1:
26       *  added changes from Miles Bader
27       *  corrected a bug with %f
28       *  added support for %#g
29       *  added more comments :-)
30    1.0:
31       *  supporting must ANSI syntaxic_sugars(see below)
32    0.0:
33       *  suppot %s %c %d
34
35     it understands:
36       Integer:
37         %lu %lu %u
38         %hd %ld %d     decimal
39         %ho %lo %o     octal
40         %hx %lx %x %X  hexa
41       Floating points:
42         %g %G %e %E %f  double
43       Strings:
44         %s %c  string
45         %%   %
46
47     Formating conversion flags:
48       - justify left
49       + Justify right or put a plus if number
50       # prefix 0x, 0X for hexa and 0 for octal
51       * precision/witdth is specify as an (int) in the arguments
52     ' ' leave a blank for number with no sign
53       l the later should be a long
54       h the later should be a short
55
56 format:
57   snprintf(holder, sizeof_holder, format, ...)
58
59 Return values:
60   (sizeof_holder - 1)
61
62
63  THANKS(for the patches and ideas):
64      Miles Bader
65      Cyrille Rustom
66      Jacek Slabocewiz
67      Mike Parker(mouse)
68
69 Alain Magloire: alainm@rcsm.ee.mcgill.ca
70 */
71
72 #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
73 #include <stdarg.h>
74 #else
75 #include <varargs.h>
76 #endif
77
78 #include <stdlib.h>    /* for atoi() */
79 #include <ctype.h>
80
81
82 /* 
83  * For the FLOATING POINT FORMAT :
84  *  the challenge was finding a way to
85  *  manipulate the Real numbers without having
86  *  to resort to mathematical function(it
87  *  would require to link with -lm) and not
88  *  going down to the bit pattern(not portable)
89  *
90  *  so a number, a real is:
91
92       real = integral + fraction
93
94       integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0
95       fraction = b(1)*10^-1 + b(2)*10^-2 + ...
96
97       where:
98        0 <= a(i) => 9 
99        0 <= b(i) => 9 
100  
101     from then it was simple math
102  */
103
104 /*
105  * size of the buffer for the integral part
106  * and the fraction part 
107  */
108 #define MAX_INT  99 + 1 /* 1 for the null */
109 #define MAX_FRACT 29 + 1
110
111 /* 
112  * numtoa() uses PRIVATE buffers to store the results,
113  * So this function is not reentrant
114  */
115 #define itoa(n) numtoa(n, 10, 0, (char **)0) 
116 #define otoa(n) numtoa(n, 8, 0, (char **)0)
117 #define htoa(n) numtoa(n, 16, 0, (char **)0)
118 #define dtoa(n, p, f) numtoa(n, 10, p, f)
119
120 #define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;}
121
122 /* this struct holds everything we need */
123 struct DATA {
124   int length;
125   char *holder;
126   int counter;
127 #ifdef __STDC__
128   const char *pf;
129 #else
130   char *pf;
131 #endif
132 /* FLAGS */
133   int width, precision;
134   int justify; char pad;
135   int square, space, star_w, star_p, a_long ;
136 };
137
138 #define PRIVATE static
139 #define PUBLIC
140 /* signature of the functions */
141 #ifdef __STDC__
142 /* the floating point stuff */
143   PRIVATE double pow_10(int);
144   PRIVATE int log_10(double);
145   PRIVATE double integral(double, double *);
146   PRIVATE char * numtoa(double, int, int, char **);
147
148 /* for the format */
149   PRIVATE void conv_flag(char *, struct DATA *);
150   PRIVATE void floating(struct DATA *, double);
151   PRIVATE void exponent(struct DATA *, double);
152   PRIVATE void decimal(struct DATA *, double);
153   PRIVATE void octal(struct DATA *, double);
154   PRIVATE void hexa(struct DATA *, double);
155   PRIVATE void strings(struct DATA *, char *);
156
157 #else
158 /* the floating point stuff */
159   PRIVATE double pow_10();
160   PRIVATE int log_10();
161   PRIVATE double integral();
162   PRIVATE char * numtoa();
163
164 /* for the format */
165   PRIVATE void conv_flag();
166   PRIVATE void floating();
167   PRIVATE void exponent();
168   PRIVATE void decimal();
169   PRIVATE void octal();
170   PRIVATE void hexa();
171   PRIVATE void strings();
172 #endif
173
174 /* those are defines specific to snprintf to hopefully
175  * make the code clearer :-)
176  */
177 #define RIGHT 1
178 #define LEFT  0
179 #define NOT_FOUND -1
180 #define FOUND 1
181 #define MAX_FIELD 15
182
183 /* the conversion flags */
184 #define isflag(c) ((c) == '#' || (c) == ' ' || \
185                    (c) == '*' || (c) == '+' || \
186                    (c) == '-' || (c) == '.' || \
187                    isdigit(c))
188
189 /* round off to the precision */
190 #define ROUND(d, p) \
191             (d < 0.) ? \
192              d - pow_10(-(p)->precision) * 0.5 : \
193              d + pow_10(-(p)->precision) * 0.5
194
195 /* set default precision */
196 #define DEF_PREC(p) \
197             if ((p)->precision == NOT_FOUND) \
198               (p)->precision = 6
199
200 /* put a char */
201 #define PUT_CHAR(c, p) \
202             if ((p)->counter < (p)->length) { \
203               *(p)->holder++ = (c); \
204               (p)->counter++; \
205             }
206
207 #define PUT_PLUS(d, p) \
208             if ((d) > 0. && (p)->justify == RIGHT) \
209               PUT_CHAR('+', p)
210
211 #define PUT_SPACE(d, p) \
212             if ((p)->space == FOUND && (d) > 0.) \
213               PUT_CHAR(' ', p)
214
215 /* pad right */ 
216 #define PAD_RIGHT(p) \
217             if ((p)->width > 0 && (p)->justify != LEFT) \
218               for (; (p)->width > 0; (p)->width--) \
219                  PUT_CHAR((p)->pad, p)
220
221 /* pad left */
222 #define PAD_LEFT(p) \
223             if ((p)->width > 0 && (p)->justify == LEFT) \
224               for (; (p)->width > 0; (p)->width--) \
225                  PUT_CHAR((p)->pad, p)
226
227 /* if width and prec. in the args */
228 #define STAR_ARGS(p) \
229             if ((p)->star_w == FOUND) \
230               (p)->width = va_arg(args, int); \
231             if ((p)->star_p == FOUND) \
232               (p)->precision = va_arg(args, int)