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