2 Unix snprintf implementation.
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
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.
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.
26 * added changes from Miles Bader
27 * corrected a bug with %f
28 * added support for %#g
29 * added more comments :-)
31 * supporting must ANSI syntaxic_sugars(see below)
47 Formating conversion flags:
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
57 snprintf(holder, sizeof_holder, format, ...)
63 THANKS(for the patches and ideas):
69 Alain Magloire: alainm@rcsm.ee.mcgill.ca
72 #if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__
78 #include <stdlib.h> /* for atoi() */
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)
90 * so a number, a real is:
92 real = integral + fraction
94 integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0
95 fraction = b(1)*10^-1 + b(2)*10^-2 + ...
101 from then it was simple math
105 * size of the buffer for the integral part
106 * and the fraction part
108 #define MAX_INT 99 + 1 /* 1 for the null */
109 #define MAX_FRACT 29 + 1
112 * numtoa() uses PRIVATE buffers to store the results,
113 * So this function is not reentrant
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)
120 #define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;}
122 /* this struct holds everything we need */
133 int width, precision;
134 int justify; char pad;
135 int square, space, star_w, star_p, a_long ;
138 #define PRIVATE static
140 /* signature of the functions */
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 **);
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 *);
158 /* the floating point stuff */
159 PRIVATE double pow_10();
160 PRIVATE int log_10();
161 PRIVATE double integral();
162 PRIVATE char * numtoa();
165 PRIVATE void conv_flag();
166 PRIVATE void floating();
167 PRIVATE void exponent();
168 PRIVATE void decimal();
169 PRIVATE void octal();
171 PRIVATE void strings();
174 /* those are defines specific to snprintf to hopefully
175 * make the code clearer :-)
183 /* the conversion flags */
184 #define isflag(c) ((c) == '#' || (c) == ' ' || \
185 (c) == '*' || (c) == '+' || \
186 (c) == '-' || (c) == '.' || \
189 /* round off to the precision */
190 #define ROUND(d, p) \
192 d - pow_10(-(p)->precision) * 0.5 : \
193 d + pow_10(-(p)->precision) * 0.5
195 /* set default precision */
196 #define DEF_PREC(p) \
197 if ((p)->precision == NOT_FOUND) \
201 #define PUT_CHAR(c, p) \
202 if ((p)->counter < (p)->length) { \
203 *(p)->holder++ = (c); \
207 #define PUT_PLUS(d, p) \
208 if ((d) > 0. && (p)->justify == RIGHT) \
211 #define PUT_SPACE(d, p) \
212 if ((p)->space == FOUND && (d) > 0.) \
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)
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)
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)