http://bugs.ethereal.com/bugzilla/show_bug.cgi?id=377
[obnox/wireshark/wip.git] / snprintf-imp.h
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 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(see below)
36    0.0:
37       *  suppot %s %c %d
38
39     it understands:
40       Integer:
41         %lu %lu %u
42         %hd %ld %d     decimal
43         %ho %lo %o     octal
44         %hx %lx %x %X  hexa
45       Floating points:
46         %g %G %e %E %f  double
47       Strings:
48         %s %c  string
49         %%   %
50
51     Formating conversion flags:
52       - justify left
53       + Justify right or put a plus if number
54       # prefix 0x, 0X for hexa and 0 for octal
55       * precision/witdth is specify as an (int) in the arguments
56     ' ' leave a blank for number with no sign
57       l the later should be a long
58       h the later should be a short
59
60 format:
61   snprintf(holder, sizeof_holder, format, ...)
62
63 Return values:
64   (sizeof_holder - 1)
65
66
67  THANKS(for the patches and ideas):
68      Miles Bader
69      Cyrille Rustom
70      Jacek Slabocewiz
71      Mike Parker(mouse)
72
73 Alain Magloire: alainm@rcsm.ee.mcgill.ca
74 */
75
76
77 /*
78  * For the FLOATING POINT FORMAT :
79  *  the challenge was finding a way to
80  *  manipulate the Real numbers without having
81  *  to resort to mathematical function(it
82  *  would require to link with -lm) and not
83  *  going down to the bit pattern(not portable)
84  *
85  *  so a number, a real is:
86
87       real = integral + fraction
88
89       integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0
90       fraction = b(1)*10^-1 + b(2)*10^-2 + ...
91
92       where:
93        0 <= a(i) => 9
94        0 <= b(i) => 9
95
96     from then it was simple math
97  */
98
99 /*
100  * size of the buffer for the integral part
101  * and the fraction part
102  */
103 #define MAX_INT  99 + 1 /* 1 for the null */
104 #define MAX_FRACT 29 + 1
105
106 /*
107  * numtoa() uses PRIVATE buffers to store the results,
108  * So this function is not reentrant
109  */
110 #define itoa(n) numtoa(n, 10, 0, (char **)0)
111 #define otoa(n) numtoa(n, 8, 0, (char **)0)
112 #define htoa(n) numtoa(n, 16, 0, (char **)0)
113 #define dtoa(n, p, f) numtoa(n, 10, p, f)
114
115 #define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;}
116
117 /* this struct holds everything we need */
118 struct DATA {
119   int length;
120   char *holder;
121   int counter;
122 #ifdef __STDC__
123   const char *pf;
124 #else
125   char *pf;
126 #endif
127 /* FLAGS */
128   int width, precision;
129   int justify; char pad;
130   int square, space, star_w, star_p, a_long ;
131 };
132
133 #define PRIVATE static
134 #define PUBLIC
135 /* signature of the functions */
136 #ifdef __STDC__
137 /* the floating point stuff */
138   PRIVATE double pow_10(int);
139   PRIVATE int log_10(double);
140   PRIVATE double integral(double, double *);
141   PRIVATE char * numtoa(double, int, int, char **);
142
143 /* for the format */
144   PRIVATE void conv_flag(char *, struct DATA *);
145   PRIVATE void floating(struct DATA *, double);
146   PRIVATE void exponent(struct DATA *, double);
147   PRIVATE void decimal(struct DATA *, double);
148   PRIVATE void octal(struct DATA *, double);
149   PRIVATE void hexa(struct DATA *, double);
150   PRIVATE void strings(struct DATA *, char *);
151
152 #else
153 /* the floating point stuff */
154   PRIVATE double pow_10();
155   PRIVATE int log_10();
156   PRIVATE double integral();
157   PRIVATE char * numtoa();
158
159 /* for the format */
160   PRIVATE void conv_flag();
161   PRIVATE void floating();
162   PRIVATE void exponent();
163   PRIVATE void decimal();
164   PRIVATE void octal();
165   PRIVATE void hexa();
166   PRIVATE void strings();
167 #endif
168
169 /* those are defines specific to snprintf to hopefully
170  * make the code clearer :-)
171  */
172 #define RIGHT 1
173 #define LEFT  0
174 #define NOT_FOUND -1
175 #define FOUND 1
176 #define MAX_FIELD 15
177
178 /* the conversion flags */
179 #define isflag(c) ((c) == '#' || (c) == ' ' || \
180                    (c) == '*' || (c) == '+' || \
181                    (c) == '-' || (c) == '.' || \
182                    isdigit(c))
183
184 /* round off to the precision */
185 #define ROUND(d, p) \
186             (d < 0.) ? \
187              d - pow_10(-(p)->precision) * 0.5 : \
188              d + pow_10(-(p)->precision) * 0.5
189
190 /* set default precision */
191 #define DEF_PREC(p) \
192             if ((p)->precision == NOT_FOUND) \
193               (p)->precision = 6
194
195 /* put a char */
196 #define PUT_CHAR(c, p) \
197             if ((p)->counter < (p)->length) { \
198               *(p)->holder++ = (c); \
199               (p)->counter++; \
200             }
201
202 #define PUT_PLUS(d, p) \
203             if ((d) > 0. && (p)->justify == RIGHT) \
204               PUT_CHAR('+', p)
205
206 #define PUT_SPACE(d, p) \
207             if ((p)->space == FOUND && (d) > 0.) \
208               PUT_CHAR(' ', p)
209
210 /* pad right */
211 #define PAD_RIGHT(p) \
212             if ((p)->width > 0 && (p)->justify != LEFT) \
213               for (; (p)->width > 0; (p)->width--) \
214                  PUT_CHAR((p)->pad, p)
215
216 /* pad left */
217 #define PAD_LEFT(p) \
218             if ((p)->width > 0 && (p)->justify == LEFT) \
219               for (; (p)->width > 0; (p)->width--) \
220                  PUT_CHAR((p)->pad, p)
221
222 /* if width and prec. in the args */
223 #define STAR_ARGS(p) \
224             if ((p)->star_w == FOUND) \
225               (p)->width = va_arg(args, int); \
226             if ((p)->star_p == FOUND) \
227               (p)->precision = va_arg(args, int)