]>
Commit | Line | Data |
---|---|---|
1f2f436a A |
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 <wchar.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 | int width; /* width from format (%8d), or 0 */ | |
252 | struct typetable types; /* table of types */ | |
253 | ||
254 | fmt = (char *)fmt0; | |
255 | inittypes(&types); | |
256 | error = 0; | |
257 | ||
258 | /* | |
259 | * Scan the format for conversions (`%' character). | |
260 | */ | |
261 | for (;;) { | |
262 | while ((ch = *fmt) != '\0' && ch != '%') | |
263 | fmt++; | |
264 | if (ch == '\0') | |
265 | goto done; | |
266 | fmt++; /* skip over '%' */ | |
267 | ||
268 | flags = 0; | |
269 | width = 0; | |
270 | ||
271 | rflag: ch = *fmt++; | |
272 | reswitch: switch (ch) { | |
273 | case ' ': | |
274 | case '#': | |
275 | goto rflag; | |
276 | case '*': | |
277 | if ((error = addaster(&types, &fmt))) | |
278 | goto error; | |
279 | goto rflag; | |
280 | case '-': | |
281 | case '+': | |
282 | case '\'': | |
283 | goto rflag; | |
284 | case '.': | |
285 | if ((ch = *fmt++) == '*') { | |
286 | if ((error = addaster(&types, &fmt))) | |
287 | goto error; | |
288 | goto rflag; | |
289 | } | |
290 | while (is_digit(ch)) { | |
291 | ch = *fmt++; | |
292 | } | |
293 | goto reswitch; | |
294 | case '0': | |
295 | goto rflag; | |
296 | case '1': case '2': case '3': case '4': | |
297 | case '5': case '6': case '7': case '8': case '9': | |
298 | n = 0; | |
299 | do { | |
300 | n = 10 * n + to_digit(ch); | |
301 | ch = *fmt++; | |
302 | } while (is_digit(ch)); | |
303 | if (ch == '$') { | |
304 | types.nextarg = n; | |
305 | goto rflag; | |
306 | } | |
307 | width = n; | |
308 | goto reswitch; | |
309 | #ifndef NO_FLOATING_POINT | |
310 | case 'L': | |
311 | flags |= LONGDBL; | |
312 | goto rflag; | |
313 | #endif | |
314 | case 'h': | |
315 | if (flags & SHORTINT) { | |
316 | flags &= ~SHORTINT; | |
317 | flags |= CHARINT; | |
318 | } else | |
319 | flags |= SHORTINT; | |
320 | goto rflag; | |
321 | case 'j': | |
322 | flags |= INTMAXT; | |
323 | goto rflag; | |
324 | case 'l': | |
325 | if (flags & LONGINT) { | |
326 | flags &= ~LONGINT; | |
327 | flags |= LLONGINT; | |
328 | } else | |
329 | flags |= LONGINT; | |
330 | goto rflag; | |
331 | case 'q': | |
332 | flags |= LLONGINT; /* not necessarily */ | |
333 | goto rflag; | |
334 | case 't': | |
335 | flags |= PTRDIFFT; | |
336 | goto rflag; | |
337 | case 'z': | |
338 | flags |= SIZET; | |
339 | goto rflag; | |
340 | case 'C': | |
341 | flags |= LONGINT; | |
342 | /*FALLTHROUGH*/ | |
343 | case 'c': | |
344 | error = addtype(&types, | |
345 | (flags & LONGINT) ? T_WINT : T_INT); | |
346 | if (error) | |
347 | goto error; | |
348 | break; | |
349 | case 'D': | |
350 | flags |= LONGINT; | |
351 | /*FALLTHROUGH*/ | |
352 | case 'd': | |
353 | case 'i': | |
354 | if ((error = addsarg(&types, flags))) | |
355 | goto error; | |
356 | break; | |
357 | #ifndef NO_FLOATING_POINT | |
358 | case 'a': | |
359 | case 'A': | |
360 | case 'e': | |
361 | case 'E': | |
362 | case 'f': | |
363 | case 'g': | |
364 | case 'G': | |
365 | error = addtype(&types, | |
366 | (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE); | |
367 | if (error) | |
368 | goto error; | |
369 | break; | |
370 | #endif /* !NO_FLOATING_POINT */ | |
371 | case 'n': | |
372 | if (flags & INTMAXT) | |
373 | error = addtype(&types, TP_INTMAXT); | |
374 | else if (flags & PTRDIFFT) | |
375 | error = addtype(&types, TP_PTRDIFFT); | |
376 | else if (flags & SIZET) | |
377 | error = addtype(&types, TP_SSIZET); | |
378 | else if (flags & LLONGINT) | |
379 | error = addtype(&types, TP_LLONG); | |
380 | else if (flags & LONGINT) | |
381 | error = addtype(&types, TP_LONG); | |
382 | else if (flags & SHORTINT) | |
383 | error = addtype(&types, TP_SHORT); | |
384 | else if (flags & CHARINT) | |
385 | error = addtype(&types, TP_SCHAR); | |
386 | else | |
387 | error = addtype(&types, TP_INT); | |
388 | if (error) | |
389 | goto error; | |
390 | continue; /* no output */ | |
391 | case 'O': | |
392 | flags |= LONGINT; | |
393 | /*FALLTHROUGH*/ | |
394 | case 'o': | |
395 | if ((error = adduarg(&types, flags))) | |
396 | goto error; | |
397 | break; | |
398 | case 'p': | |
399 | if ((error = addtype(&types, TP_VOID))) | |
400 | goto error; | |
401 | break; | |
402 | case 'S': | |
403 | flags |= LONGINT; | |
404 | /*FALLTHROUGH*/ | |
405 | case 's': | |
406 | error = addtype(&types, | |
407 | (flags & LONGINT) ? TP_WCHAR : TP_CHAR); | |
408 | if (error) | |
409 | goto error; | |
410 | break; | |
411 | case 'U': | |
412 | flags |= LONGINT; | |
413 | /*FALLTHROUGH*/ | |
414 | case 'u': | |
415 | case 'X': | |
416 | case 'x': | |
417 | if ((error = adduarg(&types, flags))) | |
418 | goto error; | |
419 | break; | |
420 | default: /* "%?" prints ?, unless ? is NUL */ | |
421 | if (ch == '\0') | |
422 | goto done; | |
423 | break; | |
424 | } | |
425 | } | |
426 | done: | |
427 | build_arg_table(&types, ap, argtable); | |
428 | error: | |
429 | freetypes(&types); | |
430 | return (error || *argtable == NULL); | |
431 | } | |
432 | ||
433 | /* wchar version of __find_arguments. */ | |
434 | int | |
435 | __find_warguments (const wchar_t *fmt0, va_list ap, union arg **argtable) | |
436 | { | |
437 | wchar_t *fmt; /* format string */ | |
438 | wchar_t ch; /* character from fmt */ | |
439 | int n; /* handy integer (short term usage) */ | |
440 | int error; | |
441 | int flags; /* flags as above */ | |
442 | int width; /* width from format (%8d), or 0 */ | |
443 | struct typetable types; /* table of types */ | |
444 | ||
445 | fmt = (wchar_t *)fmt0; | |
446 | inittypes(&types); | |
447 | error = 0; | |
448 | ||
449 | /* | |
450 | * Scan the format for conversions (`%' character). | |
451 | */ | |
452 | for (;;) { | |
453 | while ((ch = *fmt) != '\0' && ch != '%') | |
454 | fmt++; | |
455 | if (ch == '\0') | |
456 | goto done; | |
457 | fmt++; /* skip over '%' */ | |
458 | ||
459 | flags = 0; | |
460 | width = 0; | |
461 | ||
462 | rflag: ch = *fmt++; | |
463 | reswitch: switch (ch) { | |
464 | case ' ': | |
465 | case '#': | |
466 | goto rflag; | |
467 | case '*': | |
468 | if ((error = addwaster(&types, &fmt))) | |
469 | goto error; | |
470 | goto rflag; | |
471 | case '-': | |
472 | case '+': | |
473 | case '\'': | |
474 | goto rflag; | |
475 | case '.': | |
476 | if ((ch = *fmt++) == '*') { | |
477 | if ((error = addwaster(&types, &fmt))) | |
478 | goto error; | |
479 | goto rflag; | |
480 | } | |
481 | while (is_digit(ch)) { | |
482 | ch = *fmt++; | |
483 | } | |
484 | goto reswitch; | |
485 | case '0': | |
486 | goto rflag; | |
487 | case '1': case '2': case '3': case '4': | |
488 | case '5': case '6': case '7': case '8': case '9': | |
489 | n = 0; | |
490 | do { | |
491 | n = 10 * n + to_digit(ch); | |
492 | ch = *fmt++; | |
493 | } while (is_digit(ch)); | |
494 | if (ch == '$') { | |
495 | types.nextarg = n; | |
496 | goto rflag; | |
497 | } | |
498 | width = n; | |
499 | goto reswitch; | |
500 | #ifndef NO_FLOATING_POINT | |
501 | case 'L': | |
502 | flags |= LONGDBL; | |
503 | goto rflag; | |
504 | #endif | |
505 | case 'h': | |
506 | if (flags & SHORTINT) { | |
507 | flags &= ~SHORTINT; | |
508 | flags |= CHARINT; | |
509 | } else | |
510 | flags |= SHORTINT; | |
511 | goto rflag; | |
512 | case 'j': | |
513 | flags |= INTMAXT; | |
514 | goto rflag; | |
515 | case 'l': | |
516 | if (flags & LONGINT) { | |
517 | flags &= ~LONGINT; | |
518 | flags |= LLONGINT; | |
519 | } else | |
520 | flags |= LONGINT; | |
521 | goto rflag; | |
522 | case 'q': | |
523 | flags |= LLONGINT; /* not necessarily */ | |
524 | goto rflag; | |
525 | case 't': | |
526 | flags |= PTRDIFFT; | |
527 | goto rflag; | |
528 | case 'z': | |
529 | flags |= SIZET; | |
530 | goto rflag; | |
531 | case 'C': | |
532 | flags |= LONGINT; | |
533 | /*FALLTHROUGH*/ | |
534 | case 'c': | |
535 | error = addtype(&types, | |
536 | (flags & LONGINT) ? T_WINT : T_INT); | |
537 | if (error) | |
538 | goto error; | |
539 | break; | |
540 | case 'D': | |
541 | flags |= LONGINT; | |
542 | /*FALLTHROUGH*/ | |
543 | case 'd': | |
544 | case 'i': | |
545 | if ((error = addsarg(&types, flags))) | |
546 | goto error; | |
547 | break; | |
548 | #ifndef NO_FLOATING_POINT | |
549 | case 'a': | |
550 | case 'A': | |
551 | case 'e': | |
552 | case 'E': | |
553 | case 'f': | |
554 | case 'g': | |
555 | case 'G': | |
556 | error = addtype(&types, | |
557 | (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE); | |
558 | if (error) | |
559 | goto error; | |
560 | break; | |
561 | #endif /* !NO_FLOATING_POINT */ | |
562 | case 'n': | |
563 | if (flags & INTMAXT) | |
564 | error = addtype(&types, TP_INTMAXT); | |
565 | else if (flags & PTRDIFFT) | |
566 | error = addtype(&types, TP_PTRDIFFT); | |
567 | else if (flags & SIZET) | |
568 | error = addtype(&types, TP_SSIZET); | |
569 | else if (flags & LLONGINT) | |
570 | error = addtype(&types, TP_LLONG); | |
571 | else if (flags & LONGINT) | |
572 | error = addtype(&types, TP_LONG); | |
573 | else if (flags & SHORTINT) | |
574 | error = addtype(&types, TP_SHORT); | |
575 | else if (flags & CHARINT) | |
576 | error = addtype(&types, TP_SCHAR); | |
577 | else | |
578 | error = addtype(&types, TP_INT); | |
579 | if (error) | |
580 | goto error; | |
581 | continue; /* no output */ | |
582 | case 'O': | |
583 | flags |= LONGINT; | |
584 | /*FALLTHROUGH*/ | |
585 | case 'o': | |
586 | if ((error = adduarg(&types, flags))) | |
587 | goto error; | |
588 | break; | |
589 | case 'p': | |
590 | if ((error = addtype(&types, TP_VOID))) | |
591 | goto error; | |
592 | break; | |
593 | case 'S': | |
594 | flags |= LONGINT; | |
595 | /*FALLTHROUGH*/ | |
596 | case 's': | |
597 | error = addtype(&types, | |
598 | (flags & LONGINT) ? TP_WCHAR : TP_CHAR); | |
599 | if (error) | |
600 | goto error; | |
601 | break; | |
602 | case 'U': | |
603 | flags |= LONGINT; | |
604 | /*FALLTHROUGH*/ | |
605 | case 'u': | |
606 | case 'X': | |
607 | case 'x': | |
608 | if ((error = adduarg(&types, flags))) | |
609 | goto error; | |
610 | break; | |
611 | default: /* "%?" prints ?, unless ? is NUL */ | |
612 | if (ch == '\0') | |
613 | goto done; | |
614 | break; | |
615 | } | |
616 | } | |
617 | done: | |
618 | build_arg_table(&types, ap, argtable); | |
619 | error: | |
620 | freetypes(&types); | |
621 | return (error || *argtable == NULL); | |
622 | } | |
623 | ||
624 | /* | |
625 | * Increase the size of the type table. Returns 0 on success. | |
626 | */ | |
627 | static int | |
628 | __grow_type_table(struct typetable *types) | |
629 | { | |
630 | enum typeid *const oldtable = types->table; | |
631 | const int oldsize = types->tablesize; | |
632 | enum typeid *newtable; | |
633 | int n, newsize = oldsize * 2; | |
634 | ||
635 | if (newsize < types->nextarg + 1) | |
636 | newsize = types->nextarg + 1; | |
637 | if (oldsize == STATIC_ARG_TBL_SIZE) { | |
638 | if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) | |
639 | return (-1); | |
640 | bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); | |
641 | } else { | |
642 | newtable = realloc(oldtable, newsize * sizeof(enum typeid)); | |
643 | if (newtable == NULL) | |
644 | return (-1); | |
645 | } | |
646 | for (n = oldsize; n < newsize; n++) | |
647 | newtable[n] = T_UNUSED; | |
648 | ||
649 | types->table = newtable; | |
650 | types->tablesize = newsize; | |
651 | ||
652 | return (0); | |
653 | } | |
654 | ||
655 | /* | |
656 | * Build the argument table from the completed type table. | |
657 | * On malloc failure, *argtable is set to NULL. | |
658 | */ | |
659 | static void | |
660 | build_arg_table(struct typetable *types, va_list ap, union arg **argtable) | |
661 | { | |
662 | int n; | |
663 | ||
664 | if (types->tablemax >= STATIC_ARG_TBL_SIZE) { | |
665 | *argtable = (union arg *) | |
666 | malloc (sizeof (union arg) * (types->tablemax + 1)); | |
667 | if (*argtable == NULL) | |
668 | return; | |
669 | } | |
670 | ||
671 | (*argtable) [0].intarg = 0; | |
672 | for (n = 1; n <= types->tablemax; n++) { | |
673 | switch (types->table[n]) { | |
674 | case T_UNUSED: /* whoops! */ | |
675 | (*argtable) [n].intarg = va_arg (ap, int); | |
676 | break; | |
677 | case TP_SCHAR: | |
678 | (*argtable) [n].pschararg = va_arg (ap, signed char *); | |
679 | break; | |
680 | case TP_SHORT: | |
681 | (*argtable) [n].pshortarg = va_arg (ap, short *); | |
682 | break; | |
683 | case T_INT: | |
684 | (*argtable) [n].intarg = va_arg (ap, int); | |
685 | break; | |
686 | case T_U_INT: | |
687 | (*argtable) [n].uintarg = va_arg (ap, unsigned int); | |
688 | break; | |
689 | case TP_INT: | |
690 | (*argtable) [n].pintarg = va_arg (ap, int *); | |
691 | break; | |
692 | case T_LONG: | |
693 | (*argtable) [n].longarg = va_arg (ap, long); | |
694 | break; | |
695 | case T_U_LONG: | |
696 | (*argtable) [n].ulongarg = va_arg (ap, unsigned long); | |
697 | break; | |
698 | case TP_LONG: | |
699 | (*argtable) [n].plongarg = va_arg (ap, long *); | |
700 | break; | |
701 | case T_LLONG: | |
702 | (*argtable) [n].longlongarg = va_arg (ap, long long); | |
703 | break; | |
704 | case T_U_LLONG: | |
705 | (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); | |
706 | break; | |
707 | case TP_LLONG: | |
708 | (*argtable) [n].plonglongarg = va_arg (ap, long long *); | |
709 | break; | |
710 | case T_PTRDIFFT: | |
711 | (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); | |
712 | break; | |
713 | case TP_PTRDIFFT: | |
714 | (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); | |
715 | break; | |
716 | case T_SIZET: | |
717 | (*argtable) [n].sizearg = va_arg (ap, size_t); | |
718 | break; | |
719 | case T_SSIZET: | |
720 | (*argtable) [n].sizearg = va_arg (ap, ssize_t); | |
721 | break; | |
722 | case TP_SSIZET: | |
723 | (*argtable) [n].pssizearg = va_arg (ap, ssize_t *); | |
724 | break; | |
725 | case T_INTMAXT: | |
726 | (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); | |
727 | break; | |
728 | case T_UINTMAXT: | |
729 | (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); | |
730 | break; | |
731 | case TP_INTMAXT: | |
732 | (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); | |
733 | break; | |
734 | case T_DOUBLE: | |
735 | #ifndef NO_FLOATING_POINT | |
736 | (*argtable) [n].doublearg = va_arg (ap, double); | |
737 | #endif | |
738 | break; | |
739 | case T_LONG_DOUBLE: | |
740 | #ifndef NO_FLOATING_POINT | |
741 | (*argtable) [n].longdoublearg = va_arg (ap, long double); | |
742 | #endif | |
743 | break; | |
744 | case TP_CHAR: | |
745 | (*argtable) [n].pchararg = va_arg (ap, char *); | |
746 | break; | |
747 | case TP_VOID: | |
748 | (*argtable) [n].pvoidarg = va_arg (ap, void *); | |
749 | break; | |
750 | case T_WINT: | |
751 | (*argtable) [n].wintarg = va_arg (ap, wint_t); | |
752 | break; | |
753 | case TP_WCHAR: | |
754 | (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); | |
755 | break; | |
756 | } | |
757 | } | |
758 | } |