import from HEAD:
[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 #if __STDC__
39 #include <stdarg.h>
40 #else
41 #include <varargs.h>
42 #endif
43
44 #include <stdlib.h>    /* for atoi() */
45 #include <ctype.h>
46
47
48 /*
49  * For the FLOATING POINT FORMAT :
50  *  the challenge was finding a way to
51  *  manipulate the Real numbers without having
52  *  to resort to mathematical function(it
53  *  would require to link with -lm) and not
54  *  going down to the bit pattern(not portable)
55  *
56  *  so a number, a real is:
57
58       real = integral + fraction
59
60       integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0
61       fraction = b(1)*10^-1 + b(2)*10^-2 + ...
62
63       where:
64        0 <= a(i) => 9
65        0 <= b(i) => 9
66
67     from then it was simple math
68  */
69
70 /*
71  * size of the buffer for the integral part
72  * and the fraction part
73  */
74 #define MAX_INT  99 + 1 /* 1 for the null */
75 #define MAX_FRACT 29 + 1
76
77 /*
78  * If the compiler supports (long long)
79  */
80 #ifndef LONG_LONG
81 # define LONG_LONG long long
82 /*# define LONG_LONG int64_t*/
83 #endif
84
85 /*
86  * If the compiler supports (long double)
87  */
88 #ifndef LONG_DOUBLE
89 # define LONG_DOUBLE long double
90 /*# define LONG_DOUBLE double*/
91 #endif
92
93 /*
94  * numtoa() uses PRIVATE buffers to store the results,
95  * So this function is not reentrant
96  */
97 #define itoa(n) numtoa(n, 10, 0, (char **)0)
98 #define otoa(n) numtoa(n, 8, 0, (char **)0)
99 #define htoa(n) numtoa(n, 16, 0, (char **)0)
100 #define dtoa(n, p, f) numtoa(n, 10, p, f)
101
102 #define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;}
103
104 /* this struct holds everything we need */
105 struct DATA {
106   int length;
107   char *holder;
108   int counter;
109 #ifdef __STDC__
110   const char *pf;
111 #else
112   char *pf;
113 #endif
114 /* FLAGS */
115   int width, precision;
116   int justify; char pad;
117   int square, space, star_w, star_p, a_long, a_longlong;
118 };
119
120 #define PRIVATE static
121 #define PUBLIC
122 /* signature of the functions */
123 #ifdef __STDC__
124 /* the floating point stuff */
125   PRIVATE double pow_10(int);
126   PRIVATE int log_10(double);
127   PRIVATE double integral(double, double *);
128   PRIVATE char * numtoa(double, int, int, char **);
129
130 /* for the format */
131   PRIVATE void conv_flag(char *, struct DATA *);
132   PRIVATE void floating(struct DATA *, double);
133   PRIVATE void exponent(struct DATA *, double);
134   PRIVATE void decimal(struct DATA *, double);
135   PRIVATE void octal(struct DATA *, double);
136   PRIVATE void hexa(struct DATA *, double);
137   PRIVATE void strings(struct DATA *, char *);
138
139 #else
140 /* the floating point stuff */
141   PRIVATE double pow_10();
142   PRIVATE int log_10();
143   PRIVATE double integral();
144   PRIVATE char * numtoa();
145
146 /* for the format */
147   PRIVATE void conv_flag();
148   PRIVATE void floating();
149   PRIVATE void exponent();
150   PRIVATE void decimal();
151   PRIVATE void octal();
152   PRIVATE void hexa();
153   PRIVATE void strings();
154 #endif
155
156 /* those are defines specific to snprintf to hopefully
157  * make the code clearer :-)
158  */
159 #define RIGHT 1
160 #define LEFT  0
161 #define NOT_FOUND -1
162 #define FOUND 1
163 #define MAX_FIELD 15
164
165 /* the conversion flags */
166 #define isflag(c) ((c) == '#' || (c) == ' ' || \
167                    (c) == '*' || (c) == '+' || \
168                    (c) == '-' || (c) == '.' || \
169                    isdigit(c))
170
171 /* round off to the precision */
172 #define ROUND(d, p) \
173             (d < 0.) ? \
174              d - pow_10(-(p)->precision) * 0.5 : \
175              d + pow_10(-(p)->precision) * 0.5
176
177 /* set default precision */
178 #define DEF_PREC(p) \
179             if ((p)->precision == NOT_FOUND) \
180               (p)->precision = 6
181
182 /* put a char */
183 #define PUT_CHAR(c, p) \
184             if ((p)->counter < (p)->length) { \
185               *(p)->holder++ = (c); \
186               (p)->counter++; \
187             }
188
189 #define PUT_PLUS(d, p) \
190             if ((d) > 0. && (p)->justify == RIGHT) \
191               PUT_CHAR('+', p)
192
193 #define PUT_SPACE(d, p) \
194             if ((p)->space == FOUND && (d) > 0.) \
195               PUT_CHAR(' ', p)
196
197 /* pad right */
198 #define PAD_RIGHT(p) \
199             if ((p)->width > 0 && (p)->justify != LEFT) \
200               for (; (p)->width > 0; (p)->width--) \
201                  PUT_CHAR((p)->pad, p)
202
203 /* pad left */
204 #define PAD_LEFT(p) \
205             if ((p)->width > 0 && (p)->justify == LEFT) \
206               for (; (p)->width > 0; (p)->width--) \
207                  PUT_CHAR((p)->pad, p)
208
209 /* if width and prec. in the args */
210 #define STAR_ARGS(p) \
211             if ((p)->star_w == FOUND) \
212               (p)->width = va_arg(args, int); \
213             if ((p)->star_p == FOUND) \
214               (p)->precision = va_arg(args, int)