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