]>
Commit | Line | Data |
---|---|---|
24acd898 | 1 | /* Provide a version of _doprnt in terms of fprintf. |
cc096b71 | 2 | Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. |
24acd898 DD |
3 | Contributed by Kaveh Ghazi ([email protected]) 3/29/98 |
4 | ||
5 | This program is free software; you can redistribute it and/or modify it | |
6 | under the terms of the GNU General Public License as published by the | |
7 | Free Software Foundation; either version 2, or (at your option) any | |
8 | 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 General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
18 | ||
19 | #include "config.h" | |
20 | #include "ansidecl.h" | |
21 | #include "safe-ctype.h" | |
22 | ||
23 | #include <stdio.h> | |
24 | #ifdef ANSI_PROTOTYPES | |
25 | #include <stdarg.h> | |
26 | #else | |
27 | #include <varargs.h> | |
28 | #endif | |
29 | #ifdef HAVE_STRING_H | |
30 | #include <string.h> | |
31 | #endif | |
cc096b71 DD |
32 | #ifdef HAVE_STDLIB_H |
33 | #include <stdlib.h> | |
34 | #endif | |
24acd898 DD |
35 | |
36 | #undef _doprnt | |
37 | ||
cc096b71 DD |
38 | #ifdef HAVE__DOPRNT |
39 | #define TEST | |
40 | #endif | |
41 | ||
24acd898 DD |
42 | #ifdef TEST /* Make sure to use the internal one. */ |
43 | #define _doprnt my_doprnt | |
44 | #endif | |
45 | ||
46 | #define COPY_VA_INT \ | |
47 | do { \ | |
48 | const int value = abs (va_arg (ap, int)); \ | |
49 | char buf[32]; \ | |
50 | ptr++; /* Go past the asterisk. */ \ | |
51 | *sptr = '\0'; /* NULL terminate sptr. */ \ | |
52 | sprintf(buf, "%d", value); \ | |
53 | strcat(sptr, buf); \ | |
54 | while (*sptr) sptr++; \ | |
55 | } while (0) | |
56 | ||
57 | #define PRINT_CHAR(CHAR) \ | |
58 | do { \ | |
59 | putc(CHAR, stream); \ | |
60 | ptr++; \ | |
61 | total_printed++; \ | |
62 | continue; \ | |
63 | } while (0) | |
64 | ||
65 | #define PRINT_TYPE(TYPE) \ | |
66 | do { \ | |
67 | int result; \ | |
68 | TYPE value = va_arg (ap, TYPE); \ | |
69 | *sptr++ = *ptr++; /* Copy the type specifier. */ \ | |
70 | *sptr = '\0'; /* NULL terminate sptr. */ \ | |
71 | result = fprintf(stream, specifier, value); \ | |
72 | if (result == -1) \ | |
73 | return -1; \ | |
74 | else \ | |
75 | { \ | |
76 | total_printed += result; \ | |
77 | continue; \ | |
78 | } \ | |
79 | } while (0) | |
80 | ||
81 | int | |
82 | _doprnt (format, ap, stream) | |
83 | const char * format; | |
84 | va_list ap; | |
85 | FILE * stream; | |
86 | { | |
87 | const char * ptr = format; | |
88 | char specifier[128]; | |
89 | int total_printed = 0; | |
90 | ||
91 | while (*ptr != '\0') | |
92 | { | |
93 | if (*ptr != '%') /* While we have regular characters, print them. */ | |
94 | PRINT_CHAR(*ptr); | |
95 | else /* We got a format specifier! */ | |
96 | { | |
97 | char * sptr = specifier; | |
98 | int wide_width = 0, short_width = 0; | |
99 | ||
100 | *sptr++ = *ptr++; /* Copy the % and move forward. */ | |
101 | ||
102 | while (strchr ("-+ #0", *ptr)) /* Move past flags. */ | |
103 | *sptr++ = *ptr++; | |
104 | ||
105 | if (*ptr == '*') | |
106 | COPY_VA_INT; | |
107 | else | |
108 | while (ISDIGIT(*ptr)) /* Handle explicit numeric value. */ | |
109 | *sptr++ = *ptr++; | |
110 | ||
111 | if (*ptr == '.') | |
112 | { | |
113 | *sptr++ = *ptr++; /* Copy and go past the period. */ | |
114 | if (*ptr == '*') | |
115 | COPY_VA_INT; | |
116 | else | |
117 | while (ISDIGIT(*ptr)) /* Handle explicit numeric value. */ | |
118 | *sptr++ = *ptr++; | |
119 | } | |
120 | while (strchr ("hlL", *ptr)) | |
121 | { | |
122 | switch (*ptr) | |
123 | { | |
124 | case 'h': | |
125 | short_width = 1; | |
126 | break; | |
127 | case 'l': | |
128 | wide_width++; | |
129 | break; | |
130 | case 'L': | |
131 | wide_width = 2; | |
132 | break; | |
133 | default: | |
134 | abort(); | |
135 | } | |
136 | *sptr++ = *ptr++; | |
137 | } | |
138 | ||
139 | switch (*ptr) | |
140 | { | |
141 | case 'd': | |
142 | case 'i': | |
143 | case 'o': | |
144 | case 'u': | |
145 | case 'x': | |
146 | case 'X': | |
147 | case 'c': | |
148 | { | |
149 | /* Short values are promoted to int, so just copy it | |
150 | as an int and trust the C library printf to cast it | |
151 | to the right width. */ | |
152 | if (short_width) | |
153 | PRINT_TYPE(int); | |
154 | else | |
155 | { | |
156 | switch (wide_width) | |
157 | { | |
158 | case 0: | |
159 | PRINT_TYPE(int); | |
160 | break; | |
161 | case 1: | |
162 | PRINT_TYPE(long); | |
163 | break; | |
164 | case 2: | |
165 | default: | |
166 | #if defined(__GNUC__) || defined(HAVE_LONG_LONG) | |
167 | PRINT_TYPE(long long); | |
168 | #else | |
169 | PRINT_TYPE(long); /* Fake it and hope for the best. */ | |
170 | #endif | |
171 | break; | |
172 | } /* End of switch (wide_width) */ | |
173 | } /* End of else statement */ | |
174 | } /* End of integer case */ | |
175 | break; | |
176 | case 'f': | |
177 | case 'e': | |
178 | case 'E': | |
179 | case 'g': | |
180 | case 'G': | |
181 | { | |
182 | if (wide_width == 0) | |
183 | PRINT_TYPE(double); | |
184 | else | |
185 | { | |
186 | #if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE) | |
187 | PRINT_TYPE(long double); | |
188 | #else | |
189 | PRINT_TYPE(double); /* Fake it and hope for the best. */ | |
190 | #endif | |
191 | } | |
192 | } | |
193 | break; | |
194 | case 's': | |
195 | PRINT_TYPE(char *); | |
196 | break; | |
197 | case 'p': | |
198 | PRINT_TYPE(void *); | |
199 | break; | |
200 | case '%': | |
201 | PRINT_CHAR('%'); | |
202 | break; | |
203 | default: | |
204 | abort(); | |
205 | } /* End of switch (*ptr) */ | |
206 | } /* End of else statement */ | |
207 | } | |
208 | ||
209 | return total_printed; | |
210 | } | |
211 | ||
212 | #ifdef TEST | |
213 | ||
214 | #include <math.h> | |
215 | #ifndef M_PI | |
216 | #define M_PI (3.1415926535897932385) | |
217 | #endif | |
218 | ||
219 | #define RESULT(x) do \ | |
220 | { \ | |
221 | int i = (x); \ | |
222 | printf ("printed %d characters\n", i); \ | |
223 | fflush(stdin); \ | |
224 | } while (0) | |
225 | ||
226 | static int checkit PARAMS ((const char * format, ...)) ATTRIBUTE_PRINTF_1; | |
227 | ||
228 | static int | |
229 | checkit VPARAMS ((const char* format, ...)) | |
230 | { | |
231 | int result; | |
232 | VA_OPEN (args, format); | |
233 | VA_FIXEDARG (args, char *, format); | |
234 | ||
235 | result = _doprnt (format, args, stdout); | |
236 | VA_CLOSE (args); | |
237 | ||
238 | return result; | |
239 | } | |
240 | ||
241 | int | |
242 | main () | |
243 | { | |
244 | RESULT(checkit ("<%d>\n", 0x12345678)); | |
245 | RESULT(printf ("<%d>\n", 0x12345678)); | |
246 | ||
247 | RESULT(checkit ("<%200d>\n", 5)); | |
248 | RESULT(printf ("<%200d>\n", 5)); | |
249 | ||
250 | RESULT(checkit ("<%.300d>\n", 6)); | |
251 | RESULT(printf ("<%.300d>\n", 6)); | |
252 | ||
253 | RESULT(checkit ("<%100.150d>\n", 7)); | |
254 | RESULT(printf ("<%100.150d>\n", 7)); | |
255 | ||
256 | RESULT(checkit ("<%s>\n", | |
257 | "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ | |
258 | 777777777777777777333333333333366666666666622222222222777777777777733333")); | |
259 | RESULT(printf ("<%s>\n", | |
260 | "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ | |
261 | 777777777777777777333333333333366666666666622222222222777777777777733333")); | |
262 | ||
263 | RESULT(checkit ("<%f><%0+#f>%s%d%s>\n", | |
264 | 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); | |
265 | RESULT(printf ("<%f><%0+#f>%s%d%s>\n", | |
266 | 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); | |
267 | ||
268 | RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); | |
269 | RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); | |
270 | ||
271 | RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); | |
272 | RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); | |
273 | ||
274 | RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", | |
275 | 75, 75, 75, 75, 75, 75, 75)); | |
276 | RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", | |
277 | 75, 75, 75, 75, 75, 75, 75)); | |
278 | ||
279 | RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", | |
280 | 75, 75, 75, 75, 75, 75, 75)); | |
281 | RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", | |
282 | 75, 75, 75, 75, 75, 75, 75)); | |
283 | ||
284 | RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); | |
285 | RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); | |
286 | ||
287 | #if defined(__GNUC__) || defined (HAVE_LONG_LONG) | |
288 | RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); | |
289 | RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); | |
290 | RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); | |
291 | RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); | |
292 | #endif | |
293 | ||
294 | #if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE) | |
295 | RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", | |
296 | 1.23456, 1.234567890123456789L, 1.23456)); | |
297 | RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", | |
298 | 1.23456, 1.234567890123456789L, 1.23456)); | |
299 | #endif | |
300 | ||
301 | return 0; | |
302 | } | |
303 | #endif /* TEST */ |