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