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