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