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