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