1 | /*-␊ |
2 | * Copyright (c) 1990, 1993␊ |
3 | *␉The Regents of the University of California. All rights reserved.␊ |
4 | *␊ |
5 | * This code is derived from software contributed to Berkeley by␊ |
6 | * Chris Torek.␊ |
7 | *␊ |
8 | * Redistribution and use in source and binary forms, with or without␊ |
9 | * modification, are permitted provided that the following conditions␊ |
10 | * are met:␊ |
11 | * 1. Redistributions of source code must retain the above copyright␊ |
12 | * notice, this list of conditions and the following disclaimer.␊ |
13 | * 2. Redistributions in binary form must reproduce the above copyright␊ |
14 | * notice, this list of conditions and the following disclaimer in the␊ |
15 | * documentation and/or other materials provided with the distribution.␊ |
16 | * 4. Neither the name of the University nor the names of its contributors␊ |
17 | * may be used to endorse or promote products derived from this software␊ |
18 | * without specific prior written permission.␊ |
19 | *␊ |
20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND␊ |
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE␊ |
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE␊ |
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE␊ |
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL␊ |
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS␊ |
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)␊ |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT␊ |
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY␊ |
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF␊ |
30 | * SUCH DAMAGE.␊ |
31 | */␊ |
32 | ␊ |
33 | #if defined(LIBC_SCCS) && !defined(lint)␊ |
34 | static char sccsid[] = "@(#)vfprintf.c␉8.1 (Berkeley) 6/4/93";␊ |
35 | #endif /* LIBC_SCCS and not lint */␊ |
36 | #include <sys/cdefs.h>␊ |
37 | __FBSDID("$FreeBSD: src/lib/libc/stdio/printf-pos.c,v 1.6 2009/03/02 04:07:58 das Exp $");␊ |
38 | ␊ |
39 | /*␊ |
40 | * This is the code responsible for handling positional arguments␊ |
41 | * (%m$ and %m$.n$) for vfprintf() and vfwprintf().␊ |
42 | */␊ |
43 | ␊ |
44 | #include "namespace.h"␊ |
45 | #include <sys/types.h>␊ |
46 | ␊ |
47 | #include <stdarg.h>␊ |
48 | #include <stddef.h>␊ |
49 | #include <stdint.h>␊ |
50 | #include <stdio.h>␊ |
51 | #include <stdlib.h>␊ |
52 | #include <string.h>␊ |
53 | #include <strings.h>␊ |
54 | ␊ |
55 | #include "un-namespace.h"␊ |
56 | #include "printflocal.h"␊ |
57 | ␊ |
58 | /*␊ |
59 | * Type ids for argument type table.␊ |
60 | */␊ |
61 | enum typeid {␊ |
62 | ␉T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,␊ |
63 | ␉T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,␊ |
64 | ␉T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SSIZET,␊ |
65 | ␉T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,␊ |
66 | ␉T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR␊ |
67 | };␊ |
68 | ␊ |
69 | /* An expandable array of types. */␊ |
70 | struct typetable {␊ |
71 | ␉enum typeid *table; /* table of types */␊ |
72 | ␉enum typeid stattable[STATIC_ARG_TBL_SIZE];␊ |
73 | ␉int tablesize;␉␉/* current size of type table */␊ |
74 | ␉int tablemax;␉␉/* largest used index in table */␊ |
75 | ␉int nextarg;␉␉/* 1-based argument index */␊ |
76 | };␊ |
77 | ␊ |
78 | static int␉__grow_type_table(struct typetable *);␊ |
79 | static void␉build_arg_table (struct typetable *, va_list, union arg **);␊ |
80 | ␊ |
81 | /*␊ |
82 | * Initialize a struct typetable.␊ |
83 | */␊ |
84 | static inline void␊ |
85 | inittypes(struct typetable *types)␊ |
86 | {␊ |
87 | ␉int n;␊ |
88 | ␊ |
89 | ␉types->table = types->stattable;␊ |
90 | ␉types->tablesize = STATIC_ARG_TBL_SIZE;␊ |
91 | ␉types->tablemax = 0; ␊ |
92 | ␉types->nextarg = 1;␊ |
93 | ␉for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)␊ |
94 | ␉␉types->table[n] = T_UNUSED;␊ |
95 | }␊ |
96 | ␊ |
97 | /*␊ |
98 | * struct typetable destructor.␊ |
99 | */ ␊ |
100 | static inline void␊ |
101 | freetypes(struct typetable *types)␊ |
102 | {␊ |
103 | ␊ |
104 | ␉if (types->table != types->stattable)␊ |
105 | ␉␉free (types->table);␊ |
106 | }␊ |
107 | ␊ |
108 | /*␊ |
109 | * Ensure that there is space to add a new argument type to the type table.␊ |
110 | * Expand the table if necessary. Returns 0 on success.␊ |
111 | */␊ |
112 | static inline int␊ |
113 | _ensurespace(struct typetable *types)␊ |
114 | {␊ |
115 | ␊ |
116 | ␉if (types->nextarg >= types->tablesize) {␊ |
117 | ␉␉if (__grow_type_table(types))␊ |
118 | ␉␉␉return (-1);␊ |
119 | ␉}␊ |
120 | ␉if (types->nextarg > types->tablemax)␊ |
121 | ␉␉types->tablemax = types->nextarg;␊ |
122 | ␉return (0);␊ |
123 | }␊ |
124 | ␊ |
125 | /*␊ |
126 | * Add an argument type to the table, expanding if necessary.␊ |
127 | * Returns 0 on success.␊ |
128 | */␊ |
129 | static inline int␊ |
130 | addtype(struct typetable *types, enum typeid type)␊ |
131 | {␊ |
132 | ␊ |
133 | ␉if (_ensurespace(types))␊ |
134 | ␉␉return (-1);␊ |
135 | ␉types->table[types->nextarg++] = type;␊ |
136 | ␉return (0);␊ |
137 | }␊ |
138 | ␊ |
139 | static inline int␊ |
140 | addsarg(struct typetable *types, int flags)␊ |
141 | {␊ |
142 | ␊ |
143 | ␉if (_ensurespace(types))␊ |
144 | ␉␉return (-1);␊ |
145 | ␉if (flags & INTMAXT)␊ |
146 | ␉␉types->table[types->nextarg++] = T_INTMAXT;␊ |
147 | ␉else if (flags & SIZET)␊ |
148 | ␉␉types->table[types->nextarg++] = T_SSIZET;␊ |
149 | ␉else if (flags & PTRDIFFT)␊ |
150 | ␉␉types->table[types->nextarg++] = T_PTRDIFFT;␊ |
151 | ␉else if (flags & LLONGINT)␊ |
152 | ␉␉types->table[types->nextarg++] = T_LLONG;␊ |
153 | ␉else if (flags & LONGINT)␊ |
154 | ␉␉types->table[types->nextarg++] = T_LONG;␊ |
155 | ␉else␊ |
156 | ␉␉types->table[types->nextarg++] = T_INT;␊ |
157 | ␉return (0);␊ |
158 | }␊ |
159 | ␊ |
160 | static inline int␊ |
161 | adduarg(struct typetable *types, int flags)␊ |
162 | {␊ |
163 | ␊ |
164 | ␉if (_ensurespace(types))␊ |
165 | ␉␉return (-1);␊ |
166 | ␉if (flags & INTMAXT)␊ |
167 | ␉␉types->table[types->nextarg++] = T_UINTMAXT;␊ |
168 | ␉else if (flags & SIZET)␊ |
169 | ␉␉types->table[types->nextarg++] = T_SIZET;␊ |
170 | ␉else if (flags & PTRDIFFT)␊ |
171 | ␉␉types->table[types->nextarg++] = T_SIZET;␊ |
172 | ␉else if (flags & LLONGINT)␊ |
173 | ␉␉types->table[types->nextarg++] = T_U_LLONG;␊ |
174 | ␉else if (flags & LONGINT)␊ |
175 | ␉␉types->table[types->nextarg++] = T_U_LONG;␊ |
176 | ␉else␊ |
177 | ␉␉types->table[types->nextarg++] = T_U_INT;␊ |
178 | ␉return (0);␊ |
179 | }␊ |
180 | ␊ |
181 | /*␊ |
182 | * Add * arguments to the type array.␊ |
183 | */␊ |
184 | static inline int␊ |
185 | addaster(struct typetable *types, char **fmtp)␊ |
186 | {␊ |
187 | ␉char *cp;␊ |
188 | ␉int n2;␊ |
189 | ␊ |
190 | ␉n2 = 0;␊ |
191 | ␉cp = *fmtp;␊ |
192 | ␉while (is_digit(*cp)) {␊ |
193 | ␉␉n2 = 10 * n2 + to_digit(*cp);␊ |
194 | ␉␉cp++;␊ |
195 | ␉}␊ |
196 | ␉if (*cp == '$') {␊ |
197 | ␉␉int hold = types->nextarg;␊ |
198 | ␉␉types->nextarg = n2;␊ |
199 | ␉␉if (addtype(types, T_INT))␊ |
200 | ␉␉␉return (-1);␊ |
201 | ␉␉types->nextarg = hold;␊ |
202 | ␉␉*fmtp = ++cp;␊ |
203 | ␉} else {␊ |
204 | ␉␉if (addtype(types, T_INT))␊ |
205 | ␉␉␉return (-1);␊ |
206 | ␉}␊ |
207 | ␉return (0);␊ |
208 | }␊ |
209 | ␊ |
210 | static inline int␊ |
211 | addwaster(struct typetable *types, wchar_t **fmtp)␊ |
212 | {␊ |
213 | ␉wchar_t *cp;␊ |
214 | ␉int n2;␊ |
215 | ␊ |
216 | ␉n2 = 0;␊ |
217 | ␉cp = *fmtp;␊ |
218 | ␉while (is_digit(*cp)) {␊ |
219 | ␉␉n2 = 10 * n2 + to_digit(*cp);␊ |
220 | ␉␉cp++;␊ |
221 | ␉}␊ |
222 | ␉if (*cp == '$') {␊ |
223 | ␉␉int hold = types->nextarg;␊ |
224 | ␉␉types->nextarg = n2;␊ |
225 | ␉␉if (addtype(types, T_INT))␊ |
226 | ␉␉␉return (-1);␊ |
227 | ␉␉types->nextarg = hold;␊ |
228 | ␉␉*fmtp = ++cp;␊ |
229 | ␉} else {␊ |
230 | ␉␉if (addtype(types, T_INT))␊ |
231 | ␉␉␉return (-1);␊ |
232 | ␉}␊ |
233 | ␉return (0);␊ |
234 | }␊ |
235 | ␊ |
236 | /*␊ |
237 | * Find all arguments when a positional parameter is encountered. Returns a␊ |
238 | * table, indexed by argument number, of pointers to each arguments. The␊ |
239 | * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.␊ |
240 | * It will be replaces with a malloc-ed one if it overflows.␊ |
241 | * Returns 0 on success. On failure, returns nonzero and sets errno.␊ |
242 | */ ␊ |
243 | int␊ |
244 | __find_arguments (const char *fmt0, va_list ap, union arg **argtable)␊ |
245 | {␊ |
246 | ␉char *fmt;␉␉/* format string */␊ |
247 | ␉int ch;␉␉␉/* character from fmt */␊ |
248 | ␉int n;␉␉␉/* handy integer (short term usage) */␊ |
249 | ␉int error;␊ |
250 | ␉int flags;␉␉/* flags as above */␊ |
251 | ␉struct typetable types;␉/* table of types */␊ |
252 | ␊ |
253 | ␉fmt = (char *)fmt0;␊ |
254 | ␉inittypes(&types);␊ |
255 | ␉error = 0;␊ |
256 | ␊ |
257 | ␉/*␊ |
258 | ␉ * Scan the format for conversions (`%' character).␊ |
259 | ␉ */␊ |
260 | ␉for (;;) {␊ |
261 | ␉␉while ((ch = *fmt) != '\0' && ch != '%')␊ |
262 | ␉␉␉fmt++;␊ |
263 | ␉␉if (ch == '\0')␊ |
264 | ␉␉␉goto done;␊ |
265 | ␉␉fmt++;␉␉/* skip over '%' */␊ |
266 | ␊ |
267 | ␉␉flags = 0;␊ |
268 | ␊ |
269 | rflag:␉␉ch = *fmt++;␊ |
270 | reswitch:␉switch (ch) {␊ |
271 | ␉␉case ' ':␊ |
272 | ␉␉case '#':␊ |
273 | ␉␉␉goto rflag;␊ |
274 | ␉␉case '*':␊ |
275 | ␉␉␉if ((error = addaster(&types, &fmt)))␊ |
276 | ␉␉␉␉goto error;␊ |
277 | ␉␉␉goto rflag;␊ |
278 | ␉␉case '-':␊ |
279 | ␉␉case '+':␊ |
280 | ␉␉case '\'':␊ |
281 | ␉␉␉goto rflag;␊ |
282 | ␉␉case '.':␊ |
283 | ␉␉␉if ((ch = *fmt++) == '*') {␊ |
284 | ␉␉␉␉if ((error = addaster(&types, &fmt)))␊ |
285 | ␉␉␉␉␉goto error;␊ |
286 | ␉␉␉␉goto rflag;␊ |
287 | ␉␉␉}␊ |
288 | ␉␉␉while (is_digit(ch)) {␊ |
289 | ␉␉␉␉ch = *fmt++;␊ |
290 | ␉␉␉}␊ |
291 | ␉␉␉goto reswitch;␊ |
292 | ␉␉case '0':␊ |
293 | ␉␉␉goto rflag;␊ |
294 | ␉␉case '1': case '2': case '3': case '4':␊ |
295 | ␉␉case '5': case '6': case '7': case '8': case '9':␊ |
296 | ␉␉␉n = 0;␊ |
297 | ␉␉␉do {␊ |
298 | ␉␉␉␉n = 10 * n + to_digit(ch);␊ |
299 | ␉␉␉␉ch = *fmt++;␊ |
300 | ␉␉␉} while (is_digit(ch));␊ |
301 | ␉␉␉if (ch == '$') {␊ |
302 | ␉␉␉␉types.nextarg = n;␊ |
303 | ␉␉␉␉goto rflag;␊ |
304 | ␉␉␉}␊ |
305 | ␉␉␉goto reswitch;␊ |
306 | #ifndef NO_FLOATING_POINT␊ |
307 | ␉␉case 'L':␊ |
308 | ␉␉␉flags |= LONGDBL;␊ |
309 | ␉␉␉goto rflag;␊ |
310 | #endif␊ |
311 | ␉␉case 'h':␊ |
312 | ␉␉␉if (flags & SHORTINT) {␊ |
313 | ␉␉␉␉flags &= ~SHORTINT;␊ |
314 | ␉␉␉␉flags |= CHARINT;␊ |
315 | ␉␉␉} else␊ |
316 | ␉␉␉␉flags |= SHORTINT;␊ |
317 | ␉␉␉goto rflag;␊ |
318 | ␉␉case 'j':␊ |
319 | ␉␉␉flags |= INTMAXT;␊ |
320 | ␉␉␉goto rflag;␊ |
321 | ␉␉case 'l':␊ |
322 | ␉␉␉if (flags & LONGINT) {␊ |
323 | ␉␉␉␉flags &= ~LONGINT;␊ |
324 | ␉␉␉␉flags |= LLONGINT;␊ |
325 | ␉␉␉} else␊ |
326 | ␉␉␉␉flags |= LONGINT;␊ |
327 | ␉␉␉goto rflag;␊ |
328 | ␉␉case 'q':␊ |
329 | ␉␉␉flags |= LLONGINT;␉/* not necessarily */␊ |
330 | ␉␉␉goto rflag;␊ |
331 | ␉␉case 't':␊ |
332 | ␉␉␉flags |= PTRDIFFT;␊ |
333 | ␉␉␉goto rflag;␊ |
334 | ␉␉case 'z':␊ |
335 | ␉␉␉flags |= SIZET;␊ |
336 | ␉␉␉goto rflag;␊ |
337 | ␉␉case 'C':␊ |
338 | ␉␉␉flags |= LONGINT;␊ |
339 | ␉␉␉/*FALLTHROUGH*/␊ |
340 | ␉␉case 'c':␊ |
341 | ␉␉␉error = addtype(&types,␊ |
342 | ␉␉␉␉␉(flags & LONGINT) ? T_WINT : T_INT);␊ |
343 | ␉␉␉if (error)␊ |
344 | ␉␉␉␉goto error;␊ |
345 | ␉␉␉break;␊ |
346 | ␉␉case 'D':␊ |
347 | ␉␉␉flags |= LONGINT;␊ |
348 | ␉␉␉/*FALLTHROUGH*/␊ |
349 | ␉␉case 'd':␊ |
350 | ␉␉case 'i':␊ |
351 | ␉␉␉if ((error = addsarg(&types, flags)))␊ |
352 | ␉␉␉␉goto error;␊ |
353 | ␉␉␉break;␊ |
354 | #ifndef NO_FLOATING_POINT␊ |
355 | ␉␉case 'a':␊ |
356 | ␉␉case 'A':␊ |
357 | ␉␉case 'e':␊ |
358 | ␉␉case 'E':␊ |
359 | ␉␉case 'f':␊ |
360 | ␉␉case 'g':␊ |
361 | ␉␉case 'G':␊ |
362 | ␉␉␉error = addtype(&types,␊ |
363 | ␉␉␉ (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);␊ |
364 | ␉␉␉if (error)␊ |
365 | ␉␉␉␉goto error;␊ |
366 | ␉␉␉break;␊ |
367 | #endif /* !NO_FLOATING_POINT */␊ |
368 | ␉␉case 'n':␊ |
369 | ␉␉␉if (flags & INTMAXT)␊ |
370 | ␉␉␉␉error = addtype(&types, TP_INTMAXT);␊ |
371 | ␉␉␉else if (flags & PTRDIFFT)␊ |
372 | ␉␉␉␉error = addtype(&types, TP_PTRDIFFT);␊ |
373 | ␉␉␉else if (flags & SIZET)␊ |
374 | ␉␉␉␉error = addtype(&types, TP_SSIZET);␊ |
375 | ␉␉␉else if (flags & LLONGINT)␊ |
376 | ␉␉␉␉error = addtype(&types, TP_LLONG);␊ |
377 | ␉␉␉else if (flags & LONGINT)␊ |
378 | ␉␉␉␉error = addtype(&types, TP_LONG);␊ |
379 | ␉␉␉else if (flags & SHORTINT)␊ |
380 | ␉␉␉␉error = addtype(&types, TP_SHORT);␊ |
381 | ␉␉␉else if (flags & CHARINT)␊ |
382 | ␉␉␉␉error = addtype(&types, TP_SCHAR);␊ |
383 | ␉␉␉else␊ |
384 | ␉␉␉␉error = addtype(&types, TP_INT);␊ |
385 | ␉␉␉if (error)␊ |
386 | ␉␉␉␉goto error;␊ |
387 | ␉␉␉continue;␉/* no output */␊ |
388 | ␉␉case 'O':␊ |
389 | ␉␉␉flags |= LONGINT;␊ |
390 | ␉␉␉/*FALLTHROUGH*/␊ |
391 | ␉␉case 'o':␊ |
392 | ␉␉␉if ((error = adduarg(&types, flags)))␊ |
393 | ␉␉␉␉goto error;␊ |
394 | ␉␉␉break;␊ |
395 | ␉␉case 'p':␊ |
396 | ␉␉␉if ((error = addtype(&types, TP_VOID)))␊ |
397 | ␉␉␉␉goto error;␊ |
398 | ␉␉␉break;␊ |
399 | ␉␉case 'S':␊ |
400 | ␉␉␉flags |= LONGINT;␊ |
401 | ␉␉␉/*FALLTHROUGH*/␊ |
402 | ␉␉case 's':␊ |
403 | ␉␉␉error = addtype(&types,␊ |
404 | ␉␉␉␉␉(flags & LONGINT) ? TP_WCHAR : TP_CHAR);␊ |
405 | ␉␉␉if (error)␊ |
406 | ␉␉␉␉goto error;␊ |
407 | ␉␉␉break;␊ |
408 | ␉␉case 'U':␊ |
409 | ␉␉␉flags |= LONGINT;␊ |
410 | ␉␉␉/*FALLTHROUGH*/␊ |
411 | ␉␉case 'u':␊ |
412 | ␉␉case 'X':␊ |
413 | ␉␉case 'x':␊ |
414 | ␉␉␉if ((error = adduarg(&types, flags)))␊ |
415 | ␉␉␉␉goto error;␊ |
416 | ␉␉␉break;␊ |
417 | ␉␉default:␉/* "%?" prints ?, unless ? is NUL */␊ |
418 | ␉␉␉if (ch == '\0')␊ |
419 | ␉␉␉␉goto done;␊ |
420 | ␉␉␉break;␊ |
421 | ␉␉}␊ |
422 | ␉}␊ |
423 | done:␊ |
424 | ␉build_arg_table(&types, ap, argtable);␊ |
425 | error:␊ |
426 | ␉freetypes(&types);␊ |
427 | ␉return (error || *argtable == NULL);␊ |
428 | }␊ |
429 | ␊ |
430 | /* wchar version of __find_arguments. */␊ |
431 | int␊ |
432 | __find_warguments (const wchar_t *fmt0, va_list ap, union arg **argtable)␊ |
433 | {␊ |
434 | ␉wchar_t *fmt;␉␉/* format string */␊ |
435 | ␉wchar_t ch;␉␉/* character from fmt */␊ |
436 | ␉int n;␉␉␉/* handy integer (short term usage) */␊ |
437 | ␉int error;␊ |
438 | ␉int flags;␉␉/* flags as above */␊ |
439 | ␉struct typetable types;␉/* table of types */␊ |
440 | ␊ |
441 | ␉fmt = (wchar_t *)fmt0;␊ |
442 | ␉inittypes(&types);␊ |
443 | ␉error = 0;␊ |
444 | ␊ |
445 | ␉/*␊ |
446 | ␉ * Scan the format for conversions (`%' character).␊ |
447 | ␉ */␊ |
448 | ␉for (;;) {␊ |
449 | ␉␉while ((ch = *fmt) != '\0' && ch != '%')␊ |
450 | ␉␉␉fmt++;␊ |
451 | ␉␉if (ch == '\0')␊ |
452 | ␉␉␉goto done;␊ |
453 | ␉␉fmt++;␉␉/* skip over '%' */␊ |
454 | ␊ |
455 | ␉␉flags = 0;␊ |
456 | ␊ |
457 | rflag:␉␉ch = *fmt++;␊ |
458 | reswitch:␉switch (ch) {␊ |
459 | ␉␉case ' ':␊ |
460 | ␉␉case '#':␊ |
461 | ␉␉␉goto rflag;␊ |
462 | ␉␉case '*':␊ |
463 | ␉␉␉if ((error = addwaster(&types, &fmt)))␊ |
464 | ␉␉␉␉goto error;␊ |
465 | ␉␉␉goto rflag;␊ |
466 | ␉␉case '-':␊ |
467 | ␉␉case '+':␊ |
468 | ␉␉case '\'':␊ |
469 | ␉␉␉goto rflag;␊ |
470 | ␉␉case '.':␊ |
471 | ␉␉␉if ((ch = *fmt++) == '*') {␊ |
472 | ␉␉␉␉if ((error = addwaster(&types, &fmt)))␊ |
473 | ␉␉␉␉␉goto error;␊ |
474 | ␉␉␉␉goto rflag;␊ |
475 | ␉␉␉}␊ |
476 | ␉␉␉while (is_digit(ch)) {␊ |
477 | ␉␉␉␉ch = *fmt++;␊ |
478 | ␉␉␉}␊ |
479 | ␉␉␉goto reswitch;␊ |
480 | ␉␉case '0':␊ |
481 | ␉␉␉goto rflag;␊ |
482 | ␉␉case '1': case '2': case '3': case '4':␊ |
483 | ␉␉case '5': case '6': case '7': case '8': case '9':␊ |
484 | ␉␉␉n = 0;␊ |
485 | ␉␉␉do {␊ |
486 | ␉␉␉␉n = 10 * n + to_digit(ch);␊ |
487 | ␉␉␉␉ch = *fmt++;␊ |
488 | ␉␉␉} while (is_digit(ch));␊ |
489 | ␉␉␉if (ch == '$') {␊ |
490 | ␉␉␉␉types.nextarg = n;␊ |
491 | ␉␉␉␉goto rflag;␊ |
492 | ␉␉␉}␊ |
493 | ␉␉␉goto reswitch;␊ |
494 | #ifndef NO_FLOATING_POINT␊ |
495 | ␉␉case 'L':␊ |
496 | ␉␉␉flags |= LONGDBL;␊ |
497 | ␉␉␉goto rflag;␊ |
498 | #endif␊ |
499 | ␉␉case 'h':␊ |
500 | ␉␉␉if (flags & SHORTINT) {␊ |
501 | ␉␉␉␉flags &= ~SHORTINT;␊ |
502 | ␉␉␉␉flags |= CHARINT;␊ |
503 | ␉␉␉} else␊ |
504 | ␉␉␉␉flags |= SHORTINT;␊ |
505 | ␉␉␉goto rflag;␊ |
506 | ␉␉case 'j':␊ |
507 | ␉␉␉flags |= INTMAXT;␊ |
508 | ␉␉␉goto rflag;␊ |
509 | ␉␉case 'l':␊ |
510 | ␉␉␉if (flags & LONGINT) {␊ |
511 | ␉␉␉␉flags &= ~LONGINT;␊ |
512 | ␉␉␉␉flags |= LLONGINT;␊ |
513 | ␉␉␉} else␊ |
514 | ␉␉␉␉flags |= LONGINT;␊ |
515 | ␉␉␉goto rflag;␊ |
516 | ␉␉case 'q':␊ |
517 | ␉␉␉flags |= LLONGINT;␉/* not necessarily */␊ |
518 | ␉␉␉goto rflag;␊ |
519 | ␉␉case 't':␊ |
520 | ␉␉␉flags |= PTRDIFFT;␊ |
521 | ␉␉␉goto rflag;␊ |
522 | ␉␉case 'z':␊ |
523 | ␉␉␉flags |= SIZET;␊ |
524 | ␉␉␉goto rflag;␊ |
525 | ␉␉case 'C':␊ |
526 | ␉␉␉flags |= LONGINT;␊ |
527 | ␉␉␉/*FALLTHROUGH*/␊ |
528 | ␉␉case 'c':␊ |
529 | ␉␉␉error = addtype(&types,␊ |
530 | ␉␉␉␉␉(flags & LONGINT) ? T_WINT : T_INT);␊ |
531 | ␉␉␉if (error)␊ |
532 | ␉␉␉␉goto error;␊ |
533 | ␉␉␉break;␊ |
534 | ␉␉case 'D':␊ |
535 | ␉␉␉flags |= LONGINT;␊ |
536 | ␉␉␉/*FALLTHROUGH*/␊ |
537 | ␉␉case 'd':␊ |
538 | ␉␉case 'i':␊ |
539 | ␉␉␉if ((error = addsarg(&types, flags)))␊ |
540 | ␉␉␉␉goto error;␊ |
541 | ␉␉␉break;␊ |
542 | #ifndef NO_FLOATING_POINT␊ |
543 | ␉␉case 'a':␊ |
544 | ␉␉case 'A':␊ |
545 | ␉␉case 'e':␊ |
546 | ␉␉case 'E':␊ |
547 | ␉␉case 'f':␊ |
548 | ␉␉case 'g':␊ |
549 | ␉␉case 'G':␊ |
550 | ␉␉␉error = addtype(&types,␊ |
551 | ␉␉␉ (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);␊ |
552 | ␉␉␉if (error)␊ |
553 | ␉␉␉␉goto error;␊ |
554 | ␉␉␉break;␊ |
555 | #endif /* !NO_FLOATING_POINT */␊ |
556 | ␉␉case 'n':␊ |
557 | ␉␉␉if (flags & INTMAXT)␊ |
558 | ␉␉␉␉error = addtype(&types, TP_INTMAXT);␊ |
559 | ␉␉␉else if (flags & PTRDIFFT)␊ |
560 | ␉␉␉␉error = addtype(&types, TP_PTRDIFFT);␊ |
561 | ␉␉␉else if (flags & SIZET)␊ |
562 | ␉␉␉␉error = addtype(&types, TP_SSIZET);␊ |
563 | ␉␉␉else if (flags & LLONGINT)␊ |
564 | ␉␉␉␉error = addtype(&types, TP_LLONG);␊ |
565 | ␉␉␉else if (flags & LONGINT)␊ |
566 | ␉␉␉␉error = addtype(&types, TP_LONG);␊ |
567 | ␉␉␉else if (flags & SHORTINT)␊ |
568 | ␉␉␉␉error = addtype(&types, TP_SHORT);␊ |
569 | ␉␉␉else if (flags & CHARINT)␊ |
570 | ␉␉␉␉error = addtype(&types, TP_SCHAR);␊ |
571 | ␉␉␉else␊ |
572 | ␉␉␉␉error = addtype(&types, TP_INT);␊ |
573 | ␉␉␉if (error)␊ |
574 | ␉␉␉␉goto error;␊ |
575 | ␉␉␉continue;␉/* no output */␊ |
576 | ␉␉case 'O':␊ |
577 | ␉␉␉flags |= LONGINT;␊ |
578 | ␉␉␉/*FALLTHROUGH*/␊ |
579 | ␉␉case 'o':␊ |
580 | ␉␉␉if ((error = adduarg(&types, flags)))␊ |
581 | ␉␉␉␉goto error;␊ |
582 | ␉␉␉break;␊ |
583 | ␉␉case 'p':␊ |
584 | ␉␉␉if ((error = addtype(&types, TP_VOID)))␊ |
585 | ␉␉␉␉goto error;␊ |
586 | ␉␉␉break;␊ |
587 | ␉␉case 'S':␊ |
588 | ␉␉␉flags |= LONGINT;␊ |
589 | ␉␉␉/*FALLTHROUGH*/␊ |
590 | ␉␉case 's':␊ |
591 | ␉␉␉error = addtype(&types,␊ |
592 | ␉␉␉ (flags & LONGINT) ? TP_WCHAR : TP_CHAR);␊ |
593 | ␉␉␉if (error)␊ |
594 | ␉␉␉␉goto error;␊ |
595 | ␉␉␉break;␊ |
596 | ␉␉case 'U':␊ |
597 | ␉␉␉flags |= LONGINT;␊ |
598 | ␉␉␉/*FALLTHROUGH*/␊ |
599 | ␉␉case 'u':␊ |
600 | ␉␉case 'X':␊ |
601 | ␉␉case 'x':␊ |
602 | ␉␉␉if ((error = adduarg(&types, flags)))␊ |
603 | ␉␉␉␉goto error;␊ |
604 | ␉␉␉break;␊ |
605 | ␉␉default:␉/* "%?" prints ?, unless ? is NUL */␊ |
606 | ␉␉␉if (ch == '\0')␊ |
607 | ␉␉␉␉goto done;␊ |
608 | ␉␉␉break;␊ |
609 | ␉␉}␊ |
610 | ␉}␊ |
611 | done:␊ |
612 | ␉build_arg_table(&types, ap, argtable);␊ |
613 | error:␊ |
614 | ␉freetypes(&types);␊ |
615 | ␉return (error || *argtable == NULL);␊ |
616 | }␊ |
617 | ␊ |
618 | /*␊ |
619 | * Increase the size of the type table. Returns 0 on success.␊ |
620 | */␊ |
621 | static int␊ |
622 | __grow_type_table(struct typetable *types)␊ |
623 | {␊ |
624 | ␉enum typeid *const oldtable = types->table;␊ |
625 | ␉const int oldsize = types->tablesize;␊ |
626 | ␉enum typeid *newtable;␊ |
627 | ␉int n, newsize = oldsize * 2;␊ |
628 | ␊ |
629 | ␉if (newsize < types->nextarg + 1)␊ |
630 | ␉␉newsize = types->nextarg + 1;␊ |
631 | ␉if (oldsize == STATIC_ARG_TBL_SIZE) {␊ |
632 | ␉␉if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)␊ |
633 | ␉␉␉return (-1);␊ |
634 | ␉␉bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));␊ |
635 | ␉} else {␊ |
636 | ␉␉newtable = realloc(oldtable, newsize * sizeof(enum typeid));␊ |
637 | ␉␉if (newtable == NULL)␊ |
638 | ␉␉␉return (-1);␊ |
639 | ␉}␊ |
640 | ␉for (n = oldsize; n < newsize; n++)␊ |
641 | ␉␉newtable[n] = T_UNUSED;␊ |
642 | ␊ |
643 | ␉types->table = newtable;␊ |
644 | ␉types->tablesize = newsize;␊ |
645 | ␊ |
646 | ␉return (0);␊ |
647 | }␊ |
648 | ␊ |
649 | /*␊ |
650 | * Build the argument table from the completed type table.␊ |
651 | * On malloc failure, *argtable is set to NULL.␊ |
652 | */␊ |
653 | static void␊ |
654 | build_arg_table(struct typetable *types, va_list ap, union arg **argtable)␊ |
655 | {␊ |
656 | ␉int n;␊ |
657 | ␊ |
658 | ␉if (types->tablemax >= STATIC_ARG_TBL_SIZE) {␊ |
659 | ␉␉*argtable = (union arg *)␊ |
660 | ␉␉ malloc (sizeof (union arg) * (types->tablemax + 1));␊ |
661 | ␉␉if (*argtable == NULL)␊ |
662 | ␉␉␉return;␊ |
663 | ␉}␊ |
664 | ␊ |
665 | ␉(*argtable) [0].intarg = 0;␊ |
666 | ␉for (n = 1; n <= types->tablemax; n++) {␊ |
667 | ␉␉switch (types->table[n]) {␊ |
668 | ␉␉ case T_UNUSED: /* whoops! */␊ |
669 | ␉␉␉(*argtable) [n].intarg = va_arg (ap, int);␊ |
670 | ␉␉␉break;␊ |
671 | ␉␉ case TP_SCHAR:␊ |
672 | ␉␉␉(*argtable) [n].pschararg = va_arg (ap, signed char *);␊ |
673 | ␉␉␉break;␊ |
674 | ␉␉ case TP_SHORT:␊ |
675 | ␉␉␉(*argtable) [n].pshortarg = va_arg (ap, short *);␊ |
676 | ␉␉␉break;␊ |
677 | ␉␉ case T_INT:␊ |
678 | ␉␉␉(*argtable) [n].intarg = va_arg (ap, int);␊ |
679 | ␉␉␉break;␊ |
680 | ␉␉ case T_U_INT:␊ |
681 | ␉␉␉(*argtable) [n].uintarg = va_arg (ap, unsigned int);␊ |
682 | ␉␉␉break;␊ |
683 | ␉␉ case TP_INT:␊ |
684 | ␉␉␉(*argtable) [n].pintarg = va_arg (ap, int *);␊ |
685 | ␉␉␉break;␊ |
686 | ␉␉ case T_LONG:␊ |
687 | ␉␉␉(*argtable) [n].longarg = va_arg (ap, long);␊ |
688 | ␉␉␉break;␊ |
689 | ␉␉ case T_U_LONG:␊ |
690 | ␉␉␉(*argtable) [n].ulongarg = va_arg (ap, unsigned long);␊ |
691 | ␉␉␉break;␊ |
692 | ␉␉ case TP_LONG:␊ |
693 | ␉␉␉(*argtable) [n].plongarg = va_arg (ap, long *);␊ |
694 | ␉␉␉break;␊ |
695 | ␉␉ case T_LLONG:␊ |
696 | ␉␉␉(*argtable) [n].longlongarg = va_arg (ap, long long);␊ |
697 | ␉␉␉break;␊ |
698 | ␉␉ case T_U_LLONG:␊ |
699 | ␉␉␉(*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);␊ |
700 | ␉␉␉break;␊ |
701 | ␉␉ case TP_LLONG:␊ |
702 | ␉␉␉(*argtable) [n].plonglongarg = va_arg (ap, long long *);␊ |
703 | ␉␉␉break;␊ |
704 | ␉␉ case T_PTRDIFFT:␊ |
705 | ␉␉␉(*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);␊ |
706 | ␉␉␉break;␊ |
707 | ␉␉ case TP_PTRDIFFT:␊ |
708 | ␉␉␉(*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);␊ |
709 | ␉␉␉break;␊ |
710 | ␉␉ case T_SIZET:␊ |
711 | ␉␉␉(*argtable) [n].sizearg = va_arg (ap, size_t);␊ |
712 | ␉␉␉break;␊ |
713 | ␉␉ case T_SSIZET:␊ |
714 | ␉␉␉(*argtable) [n].sizearg = va_arg (ap, ssize_t);␊ |
715 | ␉␉␉break;␊ |
716 | ␉␉ case TP_SSIZET:␊ |
717 | ␉␉␉(*argtable) [n].pssizearg = va_arg (ap, ssize_t *);␊ |
718 | ␉␉␉break;␊ |
719 | ␉␉ case T_INTMAXT:␊ |
720 | ␉␉␉(*argtable) [n].intmaxarg = va_arg (ap, intmax_t);␊ |
721 | ␉␉␉break;␊ |
722 | ␉␉ case T_UINTMAXT:␊ |
723 | ␉␉␉(*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);␊ |
724 | ␉␉␉break;␊ |
725 | ␉␉ case TP_INTMAXT:␊ |
726 | ␉␉␉(*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);␊ |
727 | ␉␉␉break;␊ |
728 | ␉␉ case T_DOUBLE:␊ |
729 | #ifndef NO_FLOATING_POINT␊ |
730 | ␉␉␉(*argtable) [n].doublearg = va_arg (ap, double);␊ |
731 | #endif␊ |
732 | ␉␉␉break;␊ |
733 | ␉␉ case T_LONG_DOUBLE:␊ |
734 | #ifndef NO_FLOATING_POINT␊ |
735 | ␉␉␉(*argtable) [n].longdoublearg = va_arg (ap, long double);␊ |
736 | #endif␊ |
737 | ␉␉␉break;␊ |
738 | ␉␉ case TP_CHAR:␊ |
739 | ␉␉␉(*argtable) [n].pchararg = va_arg (ap, char *);␊ |
740 | ␉␉␉break;␊ |
741 | ␉␉ case TP_VOID:␊ |
742 | ␉␉␉(*argtable) [n].pvoidarg = va_arg (ap, void *);␊ |
743 | ␉␉␉break;␊ |
744 | ␉␉ case T_WINT:␊ |
745 | ␉␉␉(*argtable) [n].wintarg = va_arg (ap, wint_t);␊ |
746 | ␉␉␉break;␊ |
747 | ␉␉ case TP_WCHAR:␊ |
748 | ␉␉␉(*argtable) [n].pwchararg = va_arg (ap, wchar_t *);␊ |
749 | ␉␉␉break;␊ |
750 | ␉␉}␊ |
751 | ␉}␊ |
752 | }␊ |
753 | |