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