xref: /illumos-gate/usr/src/cmd/sendmail/libsm/vfprintf.c (revision 49218d4f8e4d84d1c08aeb267bcf6e451f2056dc)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (c) 2000-2001, 2004 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate  *      All rights reserved.
47c478bd9Sstevel@tonic-gate  * Copyright (c) 1990
57c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  * This code is derived from software contributed to Berkeley by
87c478bd9Sstevel@tonic-gate  * Chris Torek.
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
117c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
127c478bd9Sstevel@tonic-gate  * the sendmail distribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #include <sm/gen.h>
18*49218d4fSjbeck SM_IDSTR(id, "@(#)$Id: vfprintf.c,v 1.54 2005/05/16 03:52:00 ca Exp $")
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate /*
217c478bd9Sstevel@tonic-gate **  Overall:
227c478bd9Sstevel@tonic-gate **  Actual printing innards.
237c478bd9Sstevel@tonic-gate **  This code is large and complicated...
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <stdlib.h>
287c478bd9Sstevel@tonic-gate #include <string.h>
297c478bd9Sstevel@tonic-gate #include <errno.h>
307c478bd9Sstevel@tonic-gate #include <sm/config.h>
317c478bd9Sstevel@tonic-gate #include <sm/varargs.h>
327c478bd9Sstevel@tonic-gate #include <sm/io.h>
337c478bd9Sstevel@tonic-gate #include <sm/heap.h>
347c478bd9Sstevel@tonic-gate #include <sm/conf.h>
357c478bd9Sstevel@tonic-gate #include "local.h"
367c478bd9Sstevel@tonic-gate #include "fvwrite.h"
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate static int	sm_bprintf __P((SM_FILE_T *, const char *, va_list));
397c478bd9Sstevel@tonic-gate static void	sm_find_arguments __P((const char *, va_list , va_list **));
407c478bd9Sstevel@tonic-gate static void	sm_grow_type_table_x __P((unsigned char **, int *));
417c478bd9Sstevel@tonic-gate static int	sm_print __P((SM_FILE_T *, int, struct sm_uio *));
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate **  SM_PRINT -- print/flush to the file
457c478bd9Sstevel@tonic-gate **
467c478bd9Sstevel@tonic-gate **  Flush out all the vectors defined by the given uio,
477c478bd9Sstevel@tonic-gate **  then reset it so that it can be reused.
487c478bd9Sstevel@tonic-gate **
497c478bd9Sstevel@tonic-gate **	Parameters:
507c478bd9Sstevel@tonic-gate **		fp -- file pointer
517c478bd9Sstevel@tonic-gate **		timeout -- time to complete operation (milliseconds)
527c478bd9Sstevel@tonic-gate **		uio -- vector list of memory locations of data for printing
537c478bd9Sstevel@tonic-gate **
547c478bd9Sstevel@tonic-gate **	Results:
557c478bd9Sstevel@tonic-gate **		Success: 0 (zero)
567c478bd9Sstevel@tonic-gate **		Failure:
577c478bd9Sstevel@tonic-gate */
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate static int
607c478bd9Sstevel@tonic-gate sm_print(fp, timeout, uio)
617c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
627c478bd9Sstevel@tonic-gate 	int timeout;
637c478bd9Sstevel@tonic-gate 	register struct sm_uio *uio;
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate 	register int err;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	if (uio->uio_resid == 0)
687c478bd9Sstevel@tonic-gate 	{
697c478bd9Sstevel@tonic-gate 		uio->uio_iovcnt = 0;
707c478bd9Sstevel@tonic-gate 		return 0;
717c478bd9Sstevel@tonic-gate 	}
727c478bd9Sstevel@tonic-gate 	err = sm_fvwrite(fp, timeout, uio);
737c478bd9Sstevel@tonic-gate 	uio->uio_resid = 0;
747c478bd9Sstevel@tonic-gate 	uio->uio_iovcnt = 0;
757c478bd9Sstevel@tonic-gate 	return err;
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate **  SM_BPRINTF -- allow formating to an unbuffered file.
807c478bd9Sstevel@tonic-gate **
817c478bd9Sstevel@tonic-gate **  Helper function for `fprintf to unbuffered unix file': creates a
827c478bd9Sstevel@tonic-gate **  temporary buffer (via a "fake" file pointer).
837c478bd9Sstevel@tonic-gate **  We only work on write-only files; this avoids
847c478bd9Sstevel@tonic-gate **  worries about ungetc buffers and so forth.
857c478bd9Sstevel@tonic-gate **
867c478bd9Sstevel@tonic-gate **	Parameters:
877c478bd9Sstevel@tonic-gate **		fp -- the file to send the o/p to
887c478bd9Sstevel@tonic-gate **		fmt -- format instructions for the o/p
897c478bd9Sstevel@tonic-gate **		ap -- vectors of data units used for formating
907c478bd9Sstevel@tonic-gate **
917c478bd9Sstevel@tonic-gate **	Results:
927c478bd9Sstevel@tonic-gate **		Failure: SM_IO_EOF and errno set
937c478bd9Sstevel@tonic-gate **		Success: number of data units used in the formating
947c478bd9Sstevel@tonic-gate **
957c478bd9Sstevel@tonic-gate **	Side effects:
967c478bd9Sstevel@tonic-gate **		formatted o/p can be SM_IO_BUFSIZ length maximum
977c478bd9Sstevel@tonic-gate */
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate static int
1007c478bd9Sstevel@tonic-gate sm_bprintf(fp, fmt, ap)
1017c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
1027c478bd9Sstevel@tonic-gate 	const char *fmt;
1037c478bd9Sstevel@tonic-gate 	SM_VA_LOCAL_DECL
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	int ret;
1067c478bd9Sstevel@tonic-gate 	SM_FILE_T fake;
1077c478bd9Sstevel@tonic-gate 	unsigned char buf[SM_IO_BUFSIZ];
1087c478bd9Sstevel@tonic-gate 	extern const char SmFileMagic[];
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	/* copy the important variables */
1117c478bd9Sstevel@tonic-gate 	fake.sm_magic = SmFileMagic;
1127c478bd9Sstevel@tonic-gate 	fake.f_timeout = SM_TIME_FOREVER;
1137c478bd9Sstevel@tonic-gate 	fake.f_timeoutstate = SM_TIME_BLOCK;
1147c478bd9Sstevel@tonic-gate 	fake.f_flags = fp->f_flags & ~SMNBF;
1157c478bd9Sstevel@tonic-gate 	fake.f_file = fp->f_file;
1167c478bd9Sstevel@tonic-gate 	fake.f_cookie = fp->f_cookie;
1177c478bd9Sstevel@tonic-gate 	fake.f_write = fp->f_write;
1187c478bd9Sstevel@tonic-gate 	fake.f_close = NULL;
1197c478bd9Sstevel@tonic-gate 	fake.f_open = NULL;
1207c478bd9Sstevel@tonic-gate 	fake.f_read = NULL;
1217c478bd9Sstevel@tonic-gate 	fake.f_seek = NULL;
1227c478bd9Sstevel@tonic-gate 	fake.f_setinfo = fake.f_getinfo = NULL;
1237c478bd9Sstevel@tonic-gate 	fake.f_type = "sm_bprintf:fake";
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	/* set up the buffer */
1267c478bd9Sstevel@tonic-gate 	fake.f_bf.smb_base = fake.f_p = buf;
1277c478bd9Sstevel@tonic-gate 	fake.f_bf.smb_size = fake.f_w = sizeof(buf);
1287c478bd9Sstevel@tonic-gate 	fake.f_lbfsize = 0;	/* not actually used, but Just In Case */
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	/* do the work, then copy any error status */
1317c478bd9Sstevel@tonic-gate 	ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap);
1327c478bd9Sstevel@tonic-gate 	if (ret >= 0 && sm_io_flush(&fake, SM_TIME_FOREVER))
1337c478bd9Sstevel@tonic-gate 		ret = SM_IO_EOF;	/* errno set by sm_io_flush */
1347c478bd9Sstevel@tonic-gate 	if (fake.f_flags & SMERR)
1357c478bd9Sstevel@tonic-gate 		fp->f_flags |= SMERR;
1367c478bd9Sstevel@tonic-gate 	return ret;
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate #define BUF		40
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate #define STATIC_ARG_TBL_SIZE 8	/* Size of static argument table. */
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate /* Macros for converting digits to letters and vice versa */
1467c478bd9Sstevel@tonic-gate #define to_digit(c)	((c) - '0')
1477c478bd9Sstevel@tonic-gate #define is_digit(c)	((unsigned) to_digit(c) <= 9)
1487c478bd9Sstevel@tonic-gate #define to_char(n)	((char) (n) + '0')
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate /* Flags used during conversion. */
1517c478bd9Sstevel@tonic-gate #define ALT		0x001		/* alternate form */
1527c478bd9Sstevel@tonic-gate #define HEXPREFIX	0x002		/* add 0x or 0X prefix */
1537c478bd9Sstevel@tonic-gate #define LADJUST		0x004		/* left adjustment */
1547c478bd9Sstevel@tonic-gate #define LONGINT		0x010		/* long integer */
1557c478bd9Sstevel@tonic-gate #define QUADINT		0x020		/* quad integer */
1567c478bd9Sstevel@tonic-gate #define SHORTINT	0x040		/* short integer */
1577c478bd9Sstevel@tonic-gate #define ZEROPAD		0x080		/* zero (as opposed to blank) pad */
1587c478bd9Sstevel@tonic-gate #define FPT		0x100		/* Floating point number */
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate /*
1617c478bd9Sstevel@tonic-gate **  SM_IO_VPRINTF -- performs actual formating for o/p
1627c478bd9Sstevel@tonic-gate **
1637c478bd9Sstevel@tonic-gate **	Parameters:
1647c478bd9Sstevel@tonic-gate **		fp -- file pointer for o/p
1657c478bd9Sstevel@tonic-gate **		timeout -- time to complete the print
1667c478bd9Sstevel@tonic-gate **		fmt0 -- formating directives
1677c478bd9Sstevel@tonic-gate **		ap -- vectors with data units for formating
1687c478bd9Sstevel@tonic-gate **
1697c478bd9Sstevel@tonic-gate **	Results:
1707c478bd9Sstevel@tonic-gate **		Success: number of data units used for formatting
1717c478bd9Sstevel@tonic-gate **		Failure: SM_IO_EOF and sets errno
1727c478bd9Sstevel@tonic-gate */
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate int
1757c478bd9Sstevel@tonic-gate sm_io_vfprintf(fp, timeout, fmt0, ap)
1767c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
1777c478bd9Sstevel@tonic-gate 	int timeout;
1787c478bd9Sstevel@tonic-gate 	const char *fmt0;
1797c478bd9Sstevel@tonic-gate 	SM_VA_LOCAL_DECL
1807c478bd9Sstevel@tonic-gate {
1817c478bd9Sstevel@tonic-gate 	register char *fmt;	/* format string */
1827c478bd9Sstevel@tonic-gate 	register int ch;	/* character from fmt */
1837c478bd9Sstevel@tonic-gate 	register int n, m, n2;	/* handy integers (short term usage) */
1847c478bd9Sstevel@tonic-gate 	register char *cp;	/* handy char pointer (short term usage) */
1857c478bd9Sstevel@tonic-gate 	register struct sm_iov *iovp;/* for PRINT macro */
1867c478bd9Sstevel@tonic-gate 	register int flags;	/* flags as above */
1877c478bd9Sstevel@tonic-gate 	int ret;		/* return value accumulator */
1887c478bd9Sstevel@tonic-gate 	int width;		/* width from format (%8d), or 0 */
1897c478bd9Sstevel@tonic-gate 	int prec;		/* precision from format (%.3d), or -1 */
1907c478bd9Sstevel@tonic-gate 	char sign;		/* sign prefix (' ', '+', '-', or \0) */
1917c478bd9Sstevel@tonic-gate 	wchar_t wc;
1927c478bd9Sstevel@tonic-gate 	ULONGLONG_T _uquad;	/* integer arguments %[diouxX] */
1937c478bd9Sstevel@tonic-gate 	enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
1947c478bd9Sstevel@tonic-gate 	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
1957c478bd9Sstevel@tonic-gate 	int realsz;		/* field size expanded by dprec */
1967c478bd9Sstevel@tonic-gate 	int size;		/* size of converted field or string */
1977c478bd9Sstevel@tonic-gate 	char *xdigs="0123456789abcdef"; /* digits for [xX] conversion */
1987c478bd9Sstevel@tonic-gate #define NIOV 8
1997c478bd9Sstevel@tonic-gate 	struct sm_uio uio;	/* output information: summary */
2007c478bd9Sstevel@tonic-gate 	struct sm_iov iov[NIOV];/* ... and individual io vectors */
2017c478bd9Sstevel@tonic-gate 	char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */
2027c478bd9Sstevel@tonic-gate 	char ox[2];		/* space for 0x hex-prefix */
2037c478bd9Sstevel@tonic-gate 	va_list *argtable;	/* args, built due to positional arg */
2047c478bd9Sstevel@tonic-gate 	va_list statargtable[STATIC_ARG_TBL_SIZE];
2057c478bd9Sstevel@tonic-gate 	int nextarg;		/* 1-based argument index */
2067c478bd9Sstevel@tonic-gate 	va_list orgap;		/* original argument pointer */
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	/*
2097c478bd9Sstevel@tonic-gate 	**  Choose PADSIZE to trade efficiency vs. size.  If larger printf
2107c478bd9Sstevel@tonic-gate 	**  fields occur frequently, increase PADSIZE and make the initialisers
2117c478bd9Sstevel@tonic-gate 	**  below longer.
2127c478bd9Sstevel@tonic-gate 	*/
2137c478bd9Sstevel@tonic-gate #define PADSIZE	16		/* pad chunk size */
2147c478bd9Sstevel@tonic-gate 	static char blanks[PADSIZE] =
2157c478bd9Sstevel@tonic-gate 	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
2167c478bd9Sstevel@tonic-gate 	static char zeroes[PADSIZE] =
2177c478bd9Sstevel@tonic-gate 	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/*
2207c478bd9Sstevel@tonic-gate 	**  BEWARE, these `goto error' on error, and PAD uses `n'.
2217c478bd9Sstevel@tonic-gate 	*/
2227c478bd9Sstevel@tonic-gate #define PRINT(ptr, len) do { \
2237c478bd9Sstevel@tonic-gate 	iovp->iov_base = (ptr); \
2247c478bd9Sstevel@tonic-gate 	iovp->iov_len = (len); \
2257c478bd9Sstevel@tonic-gate 	uio.uio_resid += (len); \
2267c478bd9Sstevel@tonic-gate 	iovp++; \
2277c478bd9Sstevel@tonic-gate 	if (++uio.uio_iovcnt >= NIOV) \
2287c478bd9Sstevel@tonic-gate 	{ \
2297c478bd9Sstevel@tonic-gate 		if (sm_print(fp, timeout, &uio)) \
2307c478bd9Sstevel@tonic-gate 			goto error; \
2317c478bd9Sstevel@tonic-gate 		iovp = iov; \
2327c478bd9Sstevel@tonic-gate 	} \
2337c478bd9Sstevel@tonic-gate } while (0)
2347c478bd9Sstevel@tonic-gate #define PAD(howmany, with) do \
2357c478bd9Sstevel@tonic-gate { \
2367c478bd9Sstevel@tonic-gate 	if ((n = (howmany)) > 0) \
2377c478bd9Sstevel@tonic-gate 	{ \
2387c478bd9Sstevel@tonic-gate 		while (n > PADSIZE) { \
2397c478bd9Sstevel@tonic-gate 			PRINT(with, PADSIZE); \
2407c478bd9Sstevel@tonic-gate 			n -= PADSIZE; \
2417c478bd9Sstevel@tonic-gate 		} \
2427c478bd9Sstevel@tonic-gate 		PRINT(with, n); \
2437c478bd9Sstevel@tonic-gate 	} \
2447c478bd9Sstevel@tonic-gate } while (0)
2457c478bd9Sstevel@tonic-gate #define FLUSH() do \
2467c478bd9Sstevel@tonic-gate { \
2477c478bd9Sstevel@tonic-gate 	if (uio.uio_resid && sm_print(fp, timeout, &uio)) \
2487c478bd9Sstevel@tonic-gate 		goto error; \
2497c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = 0; \
2507c478bd9Sstevel@tonic-gate 	iovp = iov; \
2517c478bd9Sstevel@tonic-gate } while (0)
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	/*
2547c478bd9Sstevel@tonic-gate 	**  To extend shorts properly, we need both signed and unsigned
2557c478bd9Sstevel@tonic-gate 	**  argument extraction methods.
2567c478bd9Sstevel@tonic-gate 	*/
2577c478bd9Sstevel@tonic-gate #define SARG() \
2587c478bd9Sstevel@tonic-gate 	(flags&QUADINT ? SM_VA_ARG(ap, LONGLONG_T) : \
2597c478bd9Sstevel@tonic-gate 	    flags&LONGINT ? GETARG(long) : \
2607c478bd9Sstevel@tonic-gate 	    flags&SHORTINT ? (long) (short) GETARG(int) : \
2617c478bd9Sstevel@tonic-gate 	    (long) GETARG(int))
2627c478bd9Sstevel@tonic-gate #define UARG() \
2637c478bd9Sstevel@tonic-gate 	(flags&QUADINT ? SM_VA_ARG(ap, ULONGLONG_T) : \
2647c478bd9Sstevel@tonic-gate 	    flags&LONGINT ? GETARG(unsigned long) : \
2657c478bd9Sstevel@tonic-gate 	    flags&SHORTINT ? (unsigned long) (unsigned short) GETARG(int) : \
2667c478bd9Sstevel@tonic-gate 	    (unsigned long) GETARG(unsigned int))
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	/*
2697c478bd9Sstevel@tonic-gate 	**  Get * arguments, including the form *nn$.  Preserve the nextarg
2707c478bd9Sstevel@tonic-gate 	**  that the argument can be gotten once the type is determined.
2717c478bd9Sstevel@tonic-gate 	*/
2727c478bd9Sstevel@tonic-gate #define GETASTER(val) \
2737c478bd9Sstevel@tonic-gate 	n2 = 0; \
2747c478bd9Sstevel@tonic-gate 	cp = fmt; \
2757c478bd9Sstevel@tonic-gate 	while (is_digit(*cp)) \
2767c478bd9Sstevel@tonic-gate 	{ \
2777c478bd9Sstevel@tonic-gate 		n2 = 10 * n2 + to_digit(*cp); \
2787c478bd9Sstevel@tonic-gate 		cp++; \
2797c478bd9Sstevel@tonic-gate 	} \
2807c478bd9Sstevel@tonic-gate 	if (*cp == '$') \
2817c478bd9Sstevel@tonic-gate 	{ \
2827c478bd9Sstevel@tonic-gate 		int hold = nextarg; \
2837c478bd9Sstevel@tonic-gate 		if (argtable == NULL) \
2847c478bd9Sstevel@tonic-gate 		{ \
2857c478bd9Sstevel@tonic-gate 			argtable = statargtable; \
2867c478bd9Sstevel@tonic-gate 			sm_find_arguments(fmt0, orgap, &argtable); \
2877c478bd9Sstevel@tonic-gate 		} \
2887c478bd9Sstevel@tonic-gate 		nextarg = n2; \
2897c478bd9Sstevel@tonic-gate 		val = GETARG(int); \
2907c478bd9Sstevel@tonic-gate 		nextarg = hold; \
2917c478bd9Sstevel@tonic-gate 		fmt = ++cp; \
2927c478bd9Sstevel@tonic-gate 	} \
2937c478bd9Sstevel@tonic-gate 	else \
2947c478bd9Sstevel@tonic-gate 	{ \
2957c478bd9Sstevel@tonic-gate 		val = GETARG(int); \
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate /*
2997c478bd9Sstevel@tonic-gate **  Get the argument indexed by nextarg.   If the argument table is
3007c478bd9Sstevel@tonic-gate **  built, use it to get the argument.  If its not, get the next
3017c478bd9Sstevel@tonic-gate **  argument (and arguments must be gotten sequentially).
3027c478bd9Sstevel@tonic-gate */
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate #if SM_VA_STD
3057c478bd9Sstevel@tonic-gate # define GETARG(type) \
3067c478bd9Sstevel@tonic-gate 	(((argtable != NULL) ? (void) (ap = argtable[nextarg]) : (void) 0), \
3077c478bd9Sstevel@tonic-gate 	 nextarg++, SM_VA_ARG(ap, type))
3087c478bd9Sstevel@tonic-gate #else /* SM_VA_STD */
3097c478bd9Sstevel@tonic-gate # define GETARG(type) \
3107c478bd9Sstevel@tonic-gate 	((argtable != NULL) ? (*((type*)(argtable[nextarg++]))) : \
3117c478bd9Sstevel@tonic-gate 			      (nextarg++, SM_VA_ARG(ap, type)))
3127c478bd9Sstevel@tonic-gate #endif /* SM_VA_STD */
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	/* sorry, fprintf(read_only_file, "") returns SM_IO_EOF, not 0 */
3157c478bd9Sstevel@tonic-gate 	if (cantwrite(fp))
3167c478bd9Sstevel@tonic-gate 	{
3177c478bd9Sstevel@tonic-gate 		errno = EBADF;
3187c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
3227c478bd9Sstevel@tonic-gate 	if ((fp->f_flags & (SMNBF|SMWR|SMRW)) == (SMNBF|SMWR) &&
3237c478bd9Sstevel@tonic-gate 	    fp->f_file >= 0)
3247c478bd9Sstevel@tonic-gate 		return sm_bprintf(fp, fmt0, ap);
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	fmt = (char *) fmt0;
3277c478bd9Sstevel@tonic-gate 	argtable = NULL;
3287c478bd9Sstevel@tonic-gate 	nextarg = 1;
3297c478bd9Sstevel@tonic-gate 	SM_VA_COPY(orgap, ap);
3307c478bd9Sstevel@tonic-gate 	uio.uio_iov = iovp = iov;
3317c478bd9Sstevel@tonic-gate 	uio.uio_resid = 0;
3327c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = 0;
3337c478bd9Sstevel@tonic-gate 	ret = 0;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	/* Scan the format for conversions (`%' character). */
3367c478bd9Sstevel@tonic-gate 	for (;;)
3377c478bd9Sstevel@tonic-gate 	{
3387c478bd9Sstevel@tonic-gate 		cp = fmt;
3397c478bd9Sstevel@tonic-gate 		n = 0;
3407c478bd9Sstevel@tonic-gate 		while ((wc = *fmt) != '\0')
3417c478bd9Sstevel@tonic-gate 		{
3427c478bd9Sstevel@tonic-gate 			if (wc == '%')
3437c478bd9Sstevel@tonic-gate 			{
3447c478bd9Sstevel@tonic-gate 				n = 1;
3457c478bd9Sstevel@tonic-gate 				break;
3467c478bd9Sstevel@tonic-gate 			}
3477c478bd9Sstevel@tonic-gate 			fmt++;
3487c478bd9Sstevel@tonic-gate 		}
3497c478bd9Sstevel@tonic-gate 		if ((m = fmt - cp) != 0)
3507c478bd9Sstevel@tonic-gate 		{
3517c478bd9Sstevel@tonic-gate 			PRINT(cp, m);
3527c478bd9Sstevel@tonic-gate 			ret += m;
3537c478bd9Sstevel@tonic-gate 		}
3547c478bd9Sstevel@tonic-gate 		if (n <= 0)
3557c478bd9Sstevel@tonic-gate 			goto done;
3567c478bd9Sstevel@tonic-gate 		fmt++;		/* skip over '%' */
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 		flags = 0;
3597c478bd9Sstevel@tonic-gate 		dprec = 0;
3607c478bd9Sstevel@tonic-gate 		width = 0;
3617c478bd9Sstevel@tonic-gate 		prec = -1;
3627c478bd9Sstevel@tonic-gate 		sign = '\0';
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate rflag:		ch = *fmt++;
3657c478bd9Sstevel@tonic-gate reswitch:	switch (ch)
3667c478bd9Sstevel@tonic-gate 		{
3677c478bd9Sstevel@tonic-gate 		  case ' ':
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 			/*
3707c478bd9Sstevel@tonic-gate 			**  ``If the space and + flags both appear, the space
3717c478bd9Sstevel@tonic-gate 			**  flag will be ignored.''
3727c478bd9Sstevel@tonic-gate 			**	-- ANSI X3J11
3737c478bd9Sstevel@tonic-gate 			*/
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 			if (!sign)
3767c478bd9Sstevel@tonic-gate 				sign = ' ';
3777c478bd9Sstevel@tonic-gate 			goto rflag;
3787c478bd9Sstevel@tonic-gate 		  case '#':
3797c478bd9Sstevel@tonic-gate 			flags |= ALT;
3807c478bd9Sstevel@tonic-gate 			goto rflag;
3817c478bd9Sstevel@tonic-gate 		  case '*':
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 			/*
3847c478bd9Sstevel@tonic-gate 			**  ``A negative field width argument is taken as a
3857c478bd9Sstevel@tonic-gate 			**  - flag followed by a positive field width.''
3867c478bd9Sstevel@tonic-gate 			**	-- ANSI X3J11
3877c478bd9Sstevel@tonic-gate 			**  They don't exclude field widths read from args.
3887c478bd9Sstevel@tonic-gate 			*/
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 			GETASTER(width);
3917c478bd9Sstevel@tonic-gate 			if (width >= 0)
3927c478bd9Sstevel@tonic-gate 				goto rflag;
3937c478bd9Sstevel@tonic-gate 			width = -width;
3947c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
3957c478bd9Sstevel@tonic-gate 		  case '-':
3967c478bd9Sstevel@tonic-gate 			flags |= LADJUST;
3977c478bd9Sstevel@tonic-gate 			goto rflag;
3987c478bd9Sstevel@tonic-gate 		  case '+':
3997c478bd9Sstevel@tonic-gate 			sign = '+';
4007c478bd9Sstevel@tonic-gate 			goto rflag;
4017c478bd9Sstevel@tonic-gate 		  case '.':
4027c478bd9Sstevel@tonic-gate 			if ((ch = *fmt++) == '*')
4037c478bd9Sstevel@tonic-gate 			{
4047c478bd9Sstevel@tonic-gate 				GETASTER(n);
4057c478bd9Sstevel@tonic-gate 				prec = n < 0 ? -1 : n;
4067c478bd9Sstevel@tonic-gate 				goto rflag;
4077c478bd9Sstevel@tonic-gate 			}
4087c478bd9Sstevel@tonic-gate 			n = 0;
4097c478bd9Sstevel@tonic-gate 			while (is_digit(ch))
4107c478bd9Sstevel@tonic-gate 			{
4117c478bd9Sstevel@tonic-gate 				n = 10 * n + to_digit(ch);
4127c478bd9Sstevel@tonic-gate 				ch = *fmt++;
4137c478bd9Sstevel@tonic-gate 			}
4147c478bd9Sstevel@tonic-gate 			if (ch == '$')
4157c478bd9Sstevel@tonic-gate 			{
4167c478bd9Sstevel@tonic-gate 				nextarg = n;
4177c478bd9Sstevel@tonic-gate 				if (argtable == NULL)
4187c478bd9Sstevel@tonic-gate 				{
4197c478bd9Sstevel@tonic-gate 					argtable = statargtable;
4207c478bd9Sstevel@tonic-gate 					sm_find_arguments(fmt0, orgap,
4217c478bd9Sstevel@tonic-gate 					    &argtable);
4227c478bd9Sstevel@tonic-gate 				}
4237c478bd9Sstevel@tonic-gate 				goto rflag;
4247c478bd9Sstevel@tonic-gate 			}
4257c478bd9Sstevel@tonic-gate 			prec = n < 0 ? -1 : n;
4267c478bd9Sstevel@tonic-gate 			goto reswitch;
4277c478bd9Sstevel@tonic-gate 		  case '0':
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 			/*
4307c478bd9Sstevel@tonic-gate 			**  ``Note that 0 is taken as a flag, not as the
4317c478bd9Sstevel@tonic-gate 			**  beginning of a field width.''
4327c478bd9Sstevel@tonic-gate 			**	-- ANSI X3J11
4337c478bd9Sstevel@tonic-gate 			*/
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 			flags |= ZEROPAD;
4367c478bd9Sstevel@tonic-gate 			goto rflag;
4377c478bd9Sstevel@tonic-gate 		  case '1': case '2': case '3': case '4':
4387c478bd9Sstevel@tonic-gate 		  case '5': case '6': case '7': case '8': case '9':
4397c478bd9Sstevel@tonic-gate 			n = 0;
4407c478bd9Sstevel@tonic-gate 			do
4417c478bd9Sstevel@tonic-gate 			{
4427c478bd9Sstevel@tonic-gate 				n = 10 * n + to_digit(ch);
4437c478bd9Sstevel@tonic-gate 				ch = *fmt++;
4447c478bd9Sstevel@tonic-gate 			} while (is_digit(ch));
4457c478bd9Sstevel@tonic-gate 			if (ch == '$')
4467c478bd9Sstevel@tonic-gate 			{
4477c478bd9Sstevel@tonic-gate 				nextarg = n;
4487c478bd9Sstevel@tonic-gate 				if (argtable == NULL)
4497c478bd9Sstevel@tonic-gate 				{
4507c478bd9Sstevel@tonic-gate 					argtable = statargtable;
4517c478bd9Sstevel@tonic-gate 					sm_find_arguments(fmt0, orgap,
4527c478bd9Sstevel@tonic-gate 					    &argtable);
4537c478bd9Sstevel@tonic-gate 				}
4547c478bd9Sstevel@tonic-gate 				goto rflag;
4557c478bd9Sstevel@tonic-gate 			}
4567c478bd9Sstevel@tonic-gate 			width = n;
4577c478bd9Sstevel@tonic-gate 			goto reswitch;
4587c478bd9Sstevel@tonic-gate 		  case 'h':
4597c478bd9Sstevel@tonic-gate 			flags |= SHORTINT;
4607c478bd9Sstevel@tonic-gate 			goto rflag;
4617c478bd9Sstevel@tonic-gate 		  case 'l':
4627c478bd9Sstevel@tonic-gate 			if (*fmt == 'l')
4637c478bd9Sstevel@tonic-gate 			{
4647c478bd9Sstevel@tonic-gate 				fmt++;
4657c478bd9Sstevel@tonic-gate 				flags |= QUADINT;
4667c478bd9Sstevel@tonic-gate 			}
4677c478bd9Sstevel@tonic-gate 			else
4687c478bd9Sstevel@tonic-gate 			{
4697c478bd9Sstevel@tonic-gate 				flags |= LONGINT;
4707c478bd9Sstevel@tonic-gate 			}
4717c478bd9Sstevel@tonic-gate 			goto rflag;
4727c478bd9Sstevel@tonic-gate 		  case 'q':
4737c478bd9Sstevel@tonic-gate 			flags |= QUADINT;
4747c478bd9Sstevel@tonic-gate 			goto rflag;
4757c478bd9Sstevel@tonic-gate 		  case 'c':
4767c478bd9Sstevel@tonic-gate 			*(cp = buf) = GETARG(int);
4777c478bd9Sstevel@tonic-gate 			size = 1;
4787c478bd9Sstevel@tonic-gate 			sign = '\0';
4797c478bd9Sstevel@tonic-gate 			break;
4807c478bd9Sstevel@tonic-gate 		  case 'D':
4817c478bd9Sstevel@tonic-gate 			flags |= LONGINT;
4827c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
4837c478bd9Sstevel@tonic-gate 		  case 'd':
4847c478bd9Sstevel@tonic-gate 		  case 'i':
4857c478bd9Sstevel@tonic-gate 			_uquad = SARG();
4867c478bd9Sstevel@tonic-gate 			if ((LONGLONG_T) _uquad < 0)
4877c478bd9Sstevel@tonic-gate 			{
4887c478bd9Sstevel@tonic-gate 				_uquad = -(LONGLONG_T) _uquad;
4897c478bd9Sstevel@tonic-gate 				sign = '-';
4907c478bd9Sstevel@tonic-gate 			}
4917c478bd9Sstevel@tonic-gate 			base = DEC;
4927c478bd9Sstevel@tonic-gate 			goto number;
4937c478bd9Sstevel@tonic-gate 		  case 'e':
4947c478bd9Sstevel@tonic-gate 		  case 'E':
4957c478bd9Sstevel@tonic-gate 		  case 'f':
4967c478bd9Sstevel@tonic-gate 		  case 'g':
4977c478bd9Sstevel@tonic-gate 		  case 'G':
4987c478bd9Sstevel@tonic-gate 			{
4997c478bd9Sstevel@tonic-gate 				double val;
5007c478bd9Sstevel@tonic-gate 				char *p;
5017c478bd9Sstevel@tonic-gate 				char fmt[16];
5027c478bd9Sstevel@tonic-gate 				char out[150];
5037c478bd9Sstevel@tonic-gate 				size_t len;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 				/*
5067c478bd9Sstevel@tonic-gate 				**  This code implements floating point output
5077c478bd9Sstevel@tonic-gate 				**  in the most portable manner possible,
5087c478bd9Sstevel@tonic-gate 				**  relying only on 'sprintf' as defined by
5097c478bd9Sstevel@tonic-gate 				**  the 1989 ANSI C standard.
5107c478bd9Sstevel@tonic-gate 				**  We silently cap width and precision
5117c478bd9Sstevel@tonic-gate 				**  at 120, to avoid buffer overflow.
5127c478bd9Sstevel@tonic-gate 				*/
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 				val = GETARG(double);
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 				p = fmt;
5177c478bd9Sstevel@tonic-gate 				*p++ = '%';
5187c478bd9Sstevel@tonic-gate 				if (sign)
5197c478bd9Sstevel@tonic-gate 					*p++ = sign;
5207c478bd9Sstevel@tonic-gate 				if (flags & ALT)
5217c478bd9Sstevel@tonic-gate 					*p++ = '#';
5227c478bd9Sstevel@tonic-gate 				if (flags & LADJUST)
5237c478bd9Sstevel@tonic-gate 					*p++ = '-';
5247c478bd9Sstevel@tonic-gate 				if (flags & ZEROPAD)
5257c478bd9Sstevel@tonic-gate 					*p++ = '0';
5267c478bd9Sstevel@tonic-gate 				*p++ = '*';
5277c478bd9Sstevel@tonic-gate 				if (prec >= 0)
5287c478bd9Sstevel@tonic-gate 				{
5297c478bd9Sstevel@tonic-gate 					*p++ = '.';
5307c478bd9Sstevel@tonic-gate 					*p++ = '*';
5317c478bd9Sstevel@tonic-gate 				}
5327c478bd9Sstevel@tonic-gate 				*p++ = ch;
5337c478bd9Sstevel@tonic-gate 				*p = '\0';
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 				if (width > 120)
5367c478bd9Sstevel@tonic-gate 					width = 120;
5377c478bd9Sstevel@tonic-gate 				if (prec > 120)
5387c478bd9Sstevel@tonic-gate 					prec = 120;
5397c478bd9Sstevel@tonic-gate 				if (prec >= 0)
540*49218d4fSjbeck #if HASSNPRINTF
541*49218d4fSjbeck 					snprintf(out, sizeof(out), fmt, width,
542*49218d4fSjbeck 						prec, val);
543*49218d4fSjbeck #else /* HASSNPRINTF */
5447c478bd9Sstevel@tonic-gate 					sprintf(out, fmt, width, prec, val);
545*49218d4fSjbeck #endif /* HASSNPRINTF */
5467c478bd9Sstevel@tonic-gate 				else
547*49218d4fSjbeck #if HASSNPRINTF
548*49218d4fSjbeck 					snprintf(out, sizeof(out), fmt, width,
549*49218d4fSjbeck 						val);
550*49218d4fSjbeck #else /* HASSNPRINTF */
5517c478bd9Sstevel@tonic-gate 					sprintf(out, fmt, width, val);
552*49218d4fSjbeck #endif /* HASSNPRINTF */
5537c478bd9Sstevel@tonic-gate 				len = strlen(out);
5547c478bd9Sstevel@tonic-gate 				PRINT(out, len);
5557c478bd9Sstevel@tonic-gate 				FLUSH();
5567c478bd9Sstevel@tonic-gate 				continue;
5577c478bd9Sstevel@tonic-gate 			}
5587c478bd9Sstevel@tonic-gate 		case 'n':
5597c478bd9Sstevel@tonic-gate 			if (flags & QUADINT)
5607c478bd9Sstevel@tonic-gate 				*GETARG(LONGLONG_T *) = ret;
5617c478bd9Sstevel@tonic-gate 			else if (flags & LONGINT)
5627c478bd9Sstevel@tonic-gate 				*GETARG(long *) = ret;
5637c478bd9Sstevel@tonic-gate 			else if (flags & SHORTINT)
5647c478bd9Sstevel@tonic-gate 				*GETARG(short *) = ret;
5657c478bd9Sstevel@tonic-gate 			else
5667c478bd9Sstevel@tonic-gate 				*GETARG(int *) = ret;
5677c478bd9Sstevel@tonic-gate 			continue;	/* no output */
5687c478bd9Sstevel@tonic-gate 		  case 'O':
5697c478bd9Sstevel@tonic-gate 			flags |= LONGINT;
5707c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
5717c478bd9Sstevel@tonic-gate 		  case 'o':
5727c478bd9Sstevel@tonic-gate 			_uquad = UARG();
5737c478bd9Sstevel@tonic-gate 			base = OCT;
5747c478bd9Sstevel@tonic-gate 			goto nosign;
5757c478bd9Sstevel@tonic-gate 		  case 'p':
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 			/*
5787c478bd9Sstevel@tonic-gate 			**  ``The argument shall be a pointer to void.  The
5797c478bd9Sstevel@tonic-gate 			**  value of the pointer is converted to a sequence
5807c478bd9Sstevel@tonic-gate 			**  of printable characters, in an implementation-
5817c478bd9Sstevel@tonic-gate 			**  defined manner.''
5827c478bd9Sstevel@tonic-gate 			**	-- ANSI X3J11
5837c478bd9Sstevel@tonic-gate 			*/
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 			/* NOSTRICT */
5867c478bd9Sstevel@tonic-gate 			{
5877c478bd9Sstevel@tonic-gate 				union
5887c478bd9Sstevel@tonic-gate 				{
5897c478bd9Sstevel@tonic-gate 					void *p;
5907c478bd9Sstevel@tonic-gate 					ULONGLONG_T ll;
5917c478bd9Sstevel@tonic-gate 					unsigned long l;
5927c478bd9Sstevel@tonic-gate 					unsigned i;
5937c478bd9Sstevel@tonic-gate 				} u;
5947c478bd9Sstevel@tonic-gate 				u.p = GETARG(void *);
5957c478bd9Sstevel@tonic-gate 				if (sizeof(void *) == sizeof(ULONGLONG_T))
5967c478bd9Sstevel@tonic-gate 					_uquad = u.ll;
5977c478bd9Sstevel@tonic-gate 				else if (sizeof(void *) == sizeof(long))
5987c478bd9Sstevel@tonic-gate 					_uquad = u.l;
5997c478bd9Sstevel@tonic-gate 				else
6007c478bd9Sstevel@tonic-gate 					_uquad = u.i;
6017c478bd9Sstevel@tonic-gate 			}
6027c478bd9Sstevel@tonic-gate 			base = HEX;
6037c478bd9Sstevel@tonic-gate 			xdigs = "0123456789abcdef";
6047c478bd9Sstevel@tonic-gate 			flags |= HEXPREFIX;
6057c478bd9Sstevel@tonic-gate 			ch = 'x';
6067c478bd9Sstevel@tonic-gate 			goto nosign;
6077c478bd9Sstevel@tonic-gate 		  case 's':
6087c478bd9Sstevel@tonic-gate 			if ((cp = GETARG(char *)) == NULL)
6097c478bd9Sstevel@tonic-gate 				cp = "(null)";
6107c478bd9Sstevel@tonic-gate 			if (prec >= 0)
6117c478bd9Sstevel@tonic-gate 			{
6127c478bd9Sstevel@tonic-gate 				/*
6137c478bd9Sstevel@tonic-gate 				**  can't use strlen; can only look for the
6147c478bd9Sstevel@tonic-gate 				**  NUL in the first `prec' characters, and
6157c478bd9Sstevel@tonic-gate 				**  strlen() will go further.
6167c478bd9Sstevel@tonic-gate 				*/
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 				char *p = memchr(cp, 0, prec);
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 				if (p != NULL)
6217c478bd9Sstevel@tonic-gate 				{
6227c478bd9Sstevel@tonic-gate 					size = p - cp;
6237c478bd9Sstevel@tonic-gate 					if (size > prec)
6247c478bd9Sstevel@tonic-gate 						size = prec;
6257c478bd9Sstevel@tonic-gate 				}
6267c478bd9Sstevel@tonic-gate 				else
6277c478bd9Sstevel@tonic-gate 					size = prec;
6287c478bd9Sstevel@tonic-gate 			}
6297c478bd9Sstevel@tonic-gate 			else
6307c478bd9Sstevel@tonic-gate 				size = strlen(cp);
6317c478bd9Sstevel@tonic-gate 			sign = '\0';
6327c478bd9Sstevel@tonic-gate 			break;
6337c478bd9Sstevel@tonic-gate 		  case 'U':
6347c478bd9Sstevel@tonic-gate 			flags |= LONGINT;
6357c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
6367c478bd9Sstevel@tonic-gate 		  case 'u':
6377c478bd9Sstevel@tonic-gate 			_uquad = UARG();
6387c478bd9Sstevel@tonic-gate 			base = DEC;
6397c478bd9Sstevel@tonic-gate 			goto nosign;
6407c478bd9Sstevel@tonic-gate 		  case 'X':
6417c478bd9Sstevel@tonic-gate 			xdigs = "0123456789ABCDEF";
6427c478bd9Sstevel@tonic-gate 			goto hex;
6437c478bd9Sstevel@tonic-gate 		  case 'x':
6447c478bd9Sstevel@tonic-gate 			xdigs = "0123456789abcdef";
6457c478bd9Sstevel@tonic-gate hex:			_uquad = UARG();
6467c478bd9Sstevel@tonic-gate 			base = HEX;
6477c478bd9Sstevel@tonic-gate 			/* leading 0x/X only if non-zero */
6487c478bd9Sstevel@tonic-gate 			if (flags & ALT && _uquad != 0)
6497c478bd9Sstevel@tonic-gate 				flags |= HEXPREFIX;
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 			/* unsigned conversions */
6527c478bd9Sstevel@tonic-gate nosign:			sign = '\0';
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 			/*
6557c478bd9Sstevel@tonic-gate 			**  ``... diouXx conversions ... if a precision is
6567c478bd9Sstevel@tonic-gate 			**  specified, the 0 flag will be ignored.''
6577c478bd9Sstevel@tonic-gate 			**	-- ANSI X3J11
6587c478bd9Sstevel@tonic-gate 			*/
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate number:			if ((dprec = prec) >= 0)
6617c478bd9Sstevel@tonic-gate 				flags &= ~ZEROPAD;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 			/*
6647c478bd9Sstevel@tonic-gate 			**  ``The result of converting a zero value with an
6657c478bd9Sstevel@tonic-gate 			**  explicit precision of zero is no characters.''
6667c478bd9Sstevel@tonic-gate 			**	-- ANSI X3J11
6677c478bd9Sstevel@tonic-gate 			*/
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 			cp = buf + BUF;
6707c478bd9Sstevel@tonic-gate 			if (_uquad != 0 || prec != 0)
6717c478bd9Sstevel@tonic-gate 			{
6727c478bd9Sstevel@tonic-gate 				/*
6737c478bd9Sstevel@tonic-gate 				**  Unsigned mod is hard, and unsigned mod
6747c478bd9Sstevel@tonic-gate 				**  by a constant is easier than that by
6757c478bd9Sstevel@tonic-gate 				**  a variable; hence this switch.
6767c478bd9Sstevel@tonic-gate 				*/
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 				switch (base)
6797c478bd9Sstevel@tonic-gate 				{
6807c478bd9Sstevel@tonic-gate 				  case OCT:
6817c478bd9Sstevel@tonic-gate 					do
6827c478bd9Sstevel@tonic-gate 					{
6837c478bd9Sstevel@tonic-gate 						*--cp = to_char(_uquad & 7);
6847c478bd9Sstevel@tonic-gate 						_uquad >>= 3;
6857c478bd9Sstevel@tonic-gate 					} while (_uquad);
6867c478bd9Sstevel@tonic-gate 					/* handle octal leading 0 */
6877c478bd9Sstevel@tonic-gate 					if (flags & ALT && *cp != '0')
6887c478bd9Sstevel@tonic-gate 						*--cp = '0';
6897c478bd9Sstevel@tonic-gate 					break;
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 				  case DEC:
6927c478bd9Sstevel@tonic-gate 					/* many numbers are 1 digit */
6937c478bd9Sstevel@tonic-gate 					while (_uquad >= 10)
6947c478bd9Sstevel@tonic-gate 					{
6957c478bd9Sstevel@tonic-gate 						*--cp = to_char(_uquad % 10);
6967c478bd9Sstevel@tonic-gate 						_uquad /= 10;
6977c478bd9Sstevel@tonic-gate 					}
6987c478bd9Sstevel@tonic-gate 					*--cp = to_char(_uquad);
6997c478bd9Sstevel@tonic-gate 					break;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 				  case HEX:
7027c478bd9Sstevel@tonic-gate 					do
7037c478bd9Sstevel@tonic-gate 					{
7047c478bd9Sstevel@tonic-gate 						*--cp = xdigs[_uquad & 15];
7057c478bd9Sstevel@tonic-gate 						_uquad >>= 4;
7067c478bd9Sstevel@tonic-gate 					} while (_uquad);
7077c478bd9Sstevel@tonic-gate 					break;
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 				  default:
7107c478bd9Sstevel@tonic-gate 					cp = "bug in sm_io_vfprintf: bad base";
7117c478bd9Sstevel@tonic-gate 					size = strlen(cp);
7127c478bd9Sstevel@tonic-gate 					goto skipsize;
7137c478bd9Sstevel@tonic-gate 				}
7147c478bd9Sstevel@tonic-gate 			}
7157c478bd9Sstevel@tonic-gate 			size = buf + BUF - cp;
7167c478bd9Sstevel@tonic-gate 		  skipsize:
7177c478bd9Sstevel@tonic-gate 			break;
7187c478bd9Sstevel@tonic-gate 		  default:	/* "%?" prints ?, unless ? is NUL */
7197c478bd9Sstevel@tonic-gate 			if (ch == '\0')
7207c478bd9Sstevel@tonic-gate 				goto done;
7217c478bd9Sstevel@tonic-gate 			/* pretend it was %c with argument ch */
7227c478bd9Sstevel@tonic-gate 			cp = buf;
7237c478bd9Sstevel@tonic-gate 			*cp = ch;
7247c478bd9Sstevel@tonic-gate 			size = 1;
7257c478bd9Sstevel@tonic-gate 			sign = '\0';
7267c478bd9Sstevel@tonic-gate 			break;
7277c478bd9Sstevel@tonic-gate 		}
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 		/*
7307c478bd9Sstevel@tonic-gate 		**  All reasonable formats wind up here.  At this point, `cp'
7317c478bd9Sstevel@tonic-gate 		**  points to a string which (if not flags&LADJUST) should be
7327c478bd9Sstevel@tonic-gate 		**  padded out to `width' places.  If flags&ZEROPAD, it should
7337c478bd9Sstevel@tonic-gate 		**  first be prefixed by any sign or other prefix; otherwise,
7347c478bd9Sstevel@tonic-gate 		**  it should be blank padded before the prefix is emitted.
7357c478bd9Sstevel@tonic-gate 		**  After any left-hand padding and prefixing, emit zeroes
7367c478bd9Sstevel@tonic-gate 		**  required by a decimal [diouxX] precision, then print the
7377c478bd9Sstevel@tonic-gate 		**  string proper, then emit zeroes required by any leftover
7387c478bd9Sstevel@tonic-gate 		**  floating precision; finally, if LADJUST, pad with blanks.
7397c478bd9Sstevel@tonic-gate 		**
7407c478bd9Sstevel@tonic-gate 		**  Compute actual size, so we know how much to pad.
7417c478bd9Sstevel@tonic-gate 		**  size excludes decimal prec; realsz includes it.
7427c478bd9Sstevel@tonic-gate 		*/
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 		realsz = dprec > size ? dprec : size;
7457c478bd9Sstevel@tonic-gate 		if (sign)
7467c478bd9Sstevel@tonic-gate 			realsz++;
7477c478bd9Sstevel@tonic-gate 		else if (flags & HEXPREFIX)
7487c478bd9Sstevel@tonic-gate 			realsz+= 2;
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 		/* right-adjusting blank padding */
7517c478bd9Sstevel@tonic-gate 		if ((flags & (LADJUST|ZEROPAD)) == 0)
7527c478bd9Sstevel@tonic-gate 			PAD(width - realsz, blanks);
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 		/* prefix */
7557c478bd9Sstevel@tonic-gate 		if (sign)
7567c478bd9Sstevel@tonic-gate 		{
7577c478bd9Sstevel@tonic-gate 			PRINT(&sign, 1);
7587c478bd9Sstevel@tonic-gate 		}
7597c478bd9Sstevel@tonic-gate 		else if (flags & HEXPREFIX)
7607c478bd9Sstevel@tonic-gate 		{
7617c478bd9Sstevel@tonic-gate 			ox[0] = '0';
7627c478bd9Sstevel@tonic-gate 			ox[1] = ch;
7637c478bd9Sstevel@tonic-gate 			PRINT(ox, 2);
7647c478bd9Sstevel@tonic-gate 		}
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 		/* right-adjusting zero padding */
7677c478bd9Sstevel@tonic-gate 		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
7687c478bd9Sstevel@tonic-gate 			PAD(width - realsz, zeroes);
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 		/* leading zeroes from decimal precision */
7717c478bd9Sstevel@tonic-gate 		PAD(dprec - size, zeroes);
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 		/* the string or number proper */
7747c478bd9Sstevel@tonic-gate 		PRINT(cp, size);
7757c478bd9Sstevel@tonic-gate 		/* left-adjusting padding (always blank) */
7767c478bd9Sstevel@tonic-gate 		if (flags & LADJUST)
7777c478bd9Sstevel@tonic-gate 			PAD(width - realsz, blanks);
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 		/* finally, adjust ret */
7807c478bd9Sstevel@tonic-gate 		ret += width > realsz ? width : realsz;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 		FLUSH();	/* copy out the I/O vectors */
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate done:
7857c478bd9Sstevel@tonic-gate 	FLUSH();
7867c478bd9Sstevel@tonic-gate error:
7877c478bd9Sstevel@tonic-gate 	if ((argtable != NULL) && (argtable != statargtable))
7887c478bd9Sstevel@tonic-gate 		sm_free(argtable);
7897c478bd9Sstevel@tonic-gate 	return sm_error(fp) ? SM_IO_EOF : ret;
7907c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
7917c478bd9Sstevel@tonic-gate }
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate /* Type ids for argument type table. */
7947c478bd9Sstevel@tonic-gate #define T_UNUSED	0
7957c478bd9Sstevel@tonic-gate #define T_SHORT		1
7967c478bd9Sstevel@tonic-gate #define T_U_SHORT	2
7977c478bd9Sstevel@tonic-gate #define TP_SHORT	3
7987c478bd9Sstevel@tonic-gate #define T_INT		4
7997c478bd9Sstevel@tonic-gate #define T_U_INT		5
8007c478bd9Sstevel@tonic-gate #define TP_INT		6
8017c478bd9Sstevel@tonic-gate #define T_LONG		7
8027c478bd9Sstevel@tonic-gate #define T_U_LONG	8
8037c478bd9Sstevel@tonic-gate #define TP_LONG		9
8047c478bd9Sstevel@tonic-gate #define T_QUAD		10
8057c478bd9Sstevel@tonic-gate #define T_U_QUAD	11
8067c478bd9Sstevel@tonic-gate #define TP_QUAD		12
8077c478bd9Sstevel@tonic-gate #define T_DOUBLE	13
8087c478bd9Sstevel@tonic-gate #define TP_CHAR		15
8097c478bd9Sstevel@tonic-gate #define TP_VOID		16
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate /*
8127c478bd9Sstevel@tonic-gate **  SM_FIND_ARGUMENTS -- find all args when a positional parameter is found.
8137c478bd9Sstevel@tonic-gate **
8147c478bd9Sstevel@tonic-gate **  Find all arguments when a positional parameter is encountered.  Returns a
8157c478bd9Sstevel@tonic-gate **  table, indexed by argument number, of pointers to each arguments.  The
8167c478bd9Sstevel@tonic-gate **  initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
8177c478bd9Sstevel@tonic-gate **  It will be replaced with a malloc-ed one if it overflows.
8187c478bd9Sstevel@tonic-gate **
8197c478bd9Sstevel@tonic-gate **	Parameters:
8207c478bd9Sstevel@tonic-gate **		fmt0 -- formating directives
8217c478bd9Sstevel@tonic-gate **		ap -- vector list of data unit for formating consumption
8227c478bd9Sstevel@tonic-gate **		argtable -- an indexable table (returned) of 'ap'
8237c478bd9Sstevel@tonic-gate **
8247c478bd9Sstevel@tonic-gate **	Results:
8257c478bd9Sstevel@tonic-gate **		none.
8267c478bd9Sstevel@tonic-gate */
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate static void
8297c478bd9Sstevel@tonic-gate sm_find_arguments(fmt0, ap, argtable)
8307c478bd9Sstevel@tonic-gate 	const char *fmt0;
8317c478bd9Sstevel@tonic-gate 	SM_VA_LOCAL_DECL
8327c478bd9Sstevel@tonic-gate 	va_list **argtable;
8337c478bd9Sstevel@tonic-gate {
8347c478bd9Sstevel@tonic-gate 	register char *fmt;	/* format string */
8357c478bd9Sstevel@tonic-gate 	register int ch;	/* character from fmt */
8367c478bd9Sstevel@tonic-gate 	register int n, n2;	/* handy integer (short term usage) */
8377c478bd9Sstevel@tonic-gate 	register char *cp;	/* handy char pointer (short term usage) */
8387c478bd9Sstevel@tonic-gate 	register int flags;	/* flags as above */
8397c478bd9Sstevel@tonic-gate 	unsigned char *typetable; /* table of types */
8407c478bd9Sstevel@tonic-gate 	unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
8417c478bd9Sstevel@tonic-gate 	int tablesize;		/* current size of type table */
8427c478bd9Sstevel@tonic-gate 	int tablemax;		/* largest used index in table */
8437c478bd9Sstevel@tonic-gate 	int nextarg;		/* 1-based argument index */
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	/* Add an argument type to the table, expanding if necessary. */
8467c478bd9Sstevel@tonic-gate #define ADDTYPE(type) \
8477c478bd9Sstevel@tonic-gate 	((nextarg >= tablesize) ? \
8487c478bd9Sstevel@tonic-gate 		(sm_grow_type_table_x(&typetable, &tablesize), 0) : 0, \
8497c478bd9Sstevel@tonic-gate 	typetable[nextarg++] = type, \
8507c478bd9Sstevel@tonic-gate 	(nextarg > tablemax) ? tablemax = nextarg : 0)
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate #define ADDSARG() \
8537c478bd9Sstevel@tonic-gate 	((flags & LONGINT) ? ADDTYPE(T_LONG) : \
8547c478bd9Sstevel@tonic-gate 		((flags & SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate #define ADDUARG() \
8577c478bd9Sstevel@tonic-gate 	((flags & LONGINT) ? ADDTYPE(T_U_LONG) : \
8587c478bd9Sstevel@tonic-gate 		((flags & SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	/* Add * arguments to the type array. */
8617c478bd9Sstevel@tonic-gate #define ADDASTER() \
8627c478bd9Sstevel@tonic-gate 	n2 = 0; \
8637c478bd9Sstevel@tonic-gate 	cp = fmt; \
8647c478bd9Sstevel@tonic-gate 	while (is_digit(*cp)) \
8657c478bd9Sstevel@tonic-gate 	{ \
8667c478bd9Sstevel@tonic-gate 		n2 = 10 * n2 + to_digit(*cp); \
8677c478bd9Sstevel@tonic-gate 		cp++; \
8687c478bd9Sstevel@tonic-gate 	} \
8697c478bd9Sstevel@tonic-gate 	if (*cp == '$') \
8707c478bd9Sstevel@tonic-gate 	{ \
8717c478bd9Sstevel@tonic-gate 		int hold = nextarg; \
8727c478bd9Sstevel@tonic-gate 		nextarg = n2; \
8737c478bd9Sstevel@tonic-gate 		ADDTYPE (T_INT); \
8747c478bd9Sstevel@tonic-gate 		nextarg = hold; \
8757c478bd9Sstevel@tonic-gate 		fmt = ++cp; \
8767c478bd9Sstevel@tonic-gate 	} \
8777c478bd9Sstevel@tonic-gate 	else \
8787c478bd9Sstevel@tonic-gate 	{ \
8797c478bd9Sstevel@tonic-gate 		ADDTYPE (T_INT); \
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate 	fmt = (char *) fmt0;
8827c478bd9Sstevel@tonic-gate 	typetable = stattypetable;
8837c478bd9Sstevel@tonic-gate 	tablesize = STATIC_ARG_TBL_SIZE;
8847c478bd9Sstevel@tonic-gate 	tablemax = 0;
8857c478bd9Sstevel@tonic-gate 	nextarg = 1;
8867c478bd9Sstevel@tonic-gate 	(void) memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	/* Scan the format for conversions (`%' character). */
8897c478bd9Sstevel@tonic-gate 	for (;;)
8907c478bd9Sstevel@tonic-gate 	{
8917c478bd9Sstevel@tonic-gate 		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
8927c478bd9Sstevel@tonic-gate 			/* void */;
8937c478bd9Sstevel@tonic-gate 		if (ch == '\0')
8947c478bd9Sstevel@tonic-gate 			goto done;
8957c478bd9Sstevel@tonic-gate 		fmt++;		/* skip over '%' */
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 		flags = 0;
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate rflag:		ch = *fmt++;
9007c478bd9Sstevel@tonic-gate reswitch:	switch (ch)
9017c478bd9Sstevel@tonic-gate 		{
9027c478bd9Sstevel@tonic-gate 		  case ' ':
9037c478bd9Sstevel@tonic-gate 		  case '#':
9047c478bd9Sstevel@tonic-gate 			goto rflag;
9057c478bd9Sstevel@tonic-gate 		  case '*':
9067c478bd9Sstevel@tonic-gate 			ADDASTER();
9077c478bd9Sstevel@tonic-gate 			goto rflag;
9087c478bd9Sstevel@tonic-gate 		  case '-':
9097c478bd9Sstevel@tonic-gate 		  case '+':
9107c478bd9Sstevel@tonic-gate 			goto rflag;
9117c478bd9Sstevel@tonic-gate 		  case '.':
9127c478bd9Sstevel@tonic-gate 			if ((ch = *fmt++) == '*')
9137c478bd9Sstevel@tonic-gate 			{
9147c478bd9Sstevel@tonic-gate 				ADDASTER();
9157c478bd9Sstevel@tonic-gate 				goto rflag;
9167c478bd9Sstevel@tonic-gate 			}
9177c478bd9Sstevel@tonic-gate 			while (is_digit(ch))
9187c478bd9Sstevel@tonic-gate 			{
9197c478bd9Sstevel@tonic-gate 				ch = *fmt++;
9207c478bd9Sstevel@tonic-gate 			}
9217c478bd9Sstevel@tonic-gate 			goto reswitch;
9227c478bd9Sstevel@tonic-gate 		  case '0':
9237c478bd9Sstevel@tonic-gate 			goto rflag;
9247c478bd9Sstevel@tonic-gate 		  case '1': case '2': case '3': case '4':
9257c478bd9Sstevel@tonic-gate 		  case '5': case '6': case '7': case '8': case '9':
9267c478bd9Sstevel@tonic-gate 			n = 0;
9277c478bd9Sstevel@tonic-gate 			do
9287c478bd9Sstevel@tonic-gate 			{
9297c478bd9Sstevel@tonic-gate 				n = 10 * n + to_digit(ch);
9307c478bd9Sstevel@tonic-gate 				ch = *fmt++;
9317c478bd9Sstevel@tonic-gate 			} while (is_digit(ch));
9327c478bd9Sstevel@tonic-gate 			if (ch == '$')
9337c478bd9Sstevel@tonic-gate 			{
9347c478bd9Sstevel@tonic-gate 				nextarg = n;
9357c478bd9Sstevel@tonic-gate 				goto rflag;
9367c478bd9Sstevel@tonic-gate 			}
9377c478bd9Sstevel@tonic-gate 			goto reswitch;
9387c478bd9Sstevel@tonic-gate 		  case 'h':
9397c478bd9Sstevel@tonic-gate 			flags |= SHORTINT;
9407c478bd9Sstevel@tonic-gate 			goto rflag;
9417c478bd9Sstevel@tonic-gate 		  case 'l':
9427c478bd9Sstevel@tonic-gate 			flags |= LONGINT;
9437c478bd9Sstevel@tonic-gate 			goto rflag;
9447c478bd9Sstevel@tonic-gate 		  case 'q':
9457c478bd9Sstevel@tonic-gate 			flags |= QUADINT;
9467c478bd9Sstevel@tonic-gate 			goto rflag;
9477c478bd9Sstevel@tonic-gate 		  case 'c':
9487c478bd9Sstevel@tonic-gate 			ADDTYPE(T_INT);
9497c478bd9Sstevel@tonic-gate 			break;
9507c478bd9Sstevel@tonic-gate 		  case 'D':
9517c478bd9Sstevel@tonic-gate 			flags |= LONGINT;
9527c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
9537c478bd9Sstevel@tonic-gate 		  case 'd':
9547c478bd9Sstevel@tonic-gate 		  case 'i':
9557c478bd9Sstevel@tonic-gate 			if (flags & QUADINT)
9567c478bd9Sstevel@tonic-gate 			{
9577c478bd9Sstevel@tonic-gate 				ADDTYPE(T_QUAD);
9587c478bd9Sstevel@tonic-gate 			}
9597c478bd9Sstevel@tonic-gate 			else
9607c478bd9Sstevel@tonic-gate 			{
9617c478bd9Sstevel@tonic-gate 				ADDSARG();
9627c478bd9Sstevel@tonic-gate 			}
9637c478bd9Sstevel@tonic-gate 			break;
9647c478bd9Sstevel@tonic-gate 		  case 'e':
9657c478bd9Sstevel@tonic-gate 		  case 'E':
9667c478bd9Sstevel@tonic-gate 		  case 'f':
9677c478bd9Sstevel@tonic-gate 		  case 'g':
9687c478bd9Sstevel@tonic-gate 		  case 'G':
9697c478bd9Sstevel@tonic-gate 			ADDTYPE(T_DOUBLE);
9707c478bd9Sstevel@tonic-gate 			break;
9717c478bd9Sstevel@tonic-gate 		  case 'n':
9727c478bd9Sstevel@tonic-gate 			if (flags & QUADINT)
9737c478bd9Sstevel@tonic-gate 				ADDTYPE(TP_QUAD);
9747c478bd9Sstevel@tonic-gate 			else if (flags & LONGINT)
9757c478bd9Sstevel@tonic-gate 				ADDTYPE(TP_LONG);
9767c478bd9Sstevel@tonic-gate 			else if (flags & SHORTINT)
9777c478bd9Sstevel@tonic-gate 				ADDTYPE(TP_SHORT);
9787c478bd9Sstevel@tonic-gate 			else
9797c478bd9Sstevel@tonic-gate 				ADDTYPE(TP_INT);
9807c478bd9Sstevel@tonic-gate 			continue;	/* no output */
9817c478bd9Sstevel@tonic-gate 		  case 'O':
9827c478bd9Sstevel@tonic-gate 			flags |= LONGINT;
9837c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
9847c478bd9Sstevel@tonic-gate 		  case 'o':
9857c478bd9Sstevel@tonic-gate 			if (flags & QUADINT)
9867c478bd9Sstevel@tonic-gate 				ADDTYPE(T_U_QUAD);
9877c478bd9Sstevel@tonic-gate 			else
9887c478bd9Sstevel@tonic-gate 				ADDUARG();
9897c478bd9Sstevel@tonic-gate 			break;
9907c478bd9Sstevel@tonic-gate 		  case 'p':
9917c478bd9Sstevel@tonic-gate 			ADDTYPE(TP_VOID);
9927c478bd9Sstevel@tonic-gate 			break;
9937c478bd9Sstevel@tonic-gate 		  case 's':
9947c478bd9Sstevel@tonic-gate 			ADDTYPE(TP_CHAR);
9957c478bd9Sstevel@tonic-gate 			break;
9967c478bd9Sstevel@tonic-gate 		  case 'U':
9977c478bd9Sstevel@tonic-gate 			flags |= LONGINT;
9987c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
9997c478bd9Sstevel@tonic-gate 		  case 'u':
10007c478bd9Sstevel@tonic-gate 			if (flags & QUADINT)
10017c478bd9Sstevel@tonic-gate 				ADDTYPE(T_U_QUAD);
10027c478bd9Sstevel@tonic-gate 			else
10037c478bd9Sstevel@tonic-gate 				ADDUARG();
10047c478bd9Sstevel@tonic-gate 			break;
10057c478bd9Sstevel@tonic-gate 		  case 'X':
10067c478bd9Sstevel@tonic-gate 		  case 'x':
10077c478bd9Sstevel@tonic-gate 			if (flags & QUADINT)
10087c478bd9Sstevel@tonic-gate 				ADDTYPE(T_U_QUAD);
10097c478bd9Sstevel@tonic-gate 			else
10107c478bd9Sstevel@tonic-gate 				ADDUARG();
10117c478bd9Sstevel@tonic-gate 			break;
10127c478bd9Sstevel@tonic-gate 		  default:	/* "%?" prints ?, unless ? is NUL */
10137c478bd9Sstevel@tonic-gate 			if (ch == '\0')
10147c478bd9Sstevel@tonic-gate 				goto done;
10157c478bd9Sstevel@tonic-gate 			break;
10167c478bd9Sstevel@tonic-gate 		}
10177c478bd9Sstevel@tonic-gate 	}
10187c478bd9Sstevel@tonic-gate done:
10197c478bd9Sstevel@tonic-gate 	/* Build the argument table. */
10207c478bd9Sstevel@tonic-gate 	if (tablemax >= STATIC_ARG_TBL_SIZE)
10217c478bd9Sstevel@tonic-gate 	{
10227c478bd9Sstevel@tonic-gate 		*argtable = (va_list *)
10237c478bd9Sstevel@tonic-gate 		    sm_malloc(sizeof(va_list) * (tablemax + 1));
10247c478bd9Sstevel@tonic-gate 	}
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	for (n = 1; n <= tablemax; n++)
10277c478bd9Sstevel@tonic-gate 	{
10287c478bd9Sstevel@tonic-gate 		SM_VA_COPY((*argtable)[n], ap);
10297c478bd9Sstevel@tonic-gate 		switch (typetable [n])
10307c478bd9Sstevel@tonic-gate 		{
10317c478bd9Sstevel@tonic-gate 		  case T_UNUSED:
10327c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, int);
10337c478bd9Sstevel@tonic-gate 			break;
10347c478bd9Sstevel@tonic-gate 		  case T_SHORT:
10357c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, int);
10367c478bd9Sstevel@tonic-gate 			break;
10377c478bd9Sstevel@tonic-gate 		  case T_U_SHORT:
10387c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, int);
10397c478bd9Sstevel@tonic-gate 			break;
10407c478bd9Sstevel@tonic-gate 		  case TP_SHORT:
10417c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, short *);
10427c478bd9Sstevel@tonic-gate 			break;
10437c478bd9Sstevel@tonic-gate 		  case T_INT:
10447c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, int);
10457c478bd9Sstevel@tonic-gate 			break;
10467c478bd9Sstevel@tonic-gate 		  case T_U_INT:
10477c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, unsigned int);
10487c478bd9Sstevel@tonic-gate 			break;
10497c478bd9Sstevel@tonic-gate 		  case TP_INT:
10507c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, int *);
10517c478bd9Sstevel@tonic-gate 			break;
10527c478bd9Sstevel@tonic-gate 		  case T_LONG:
10537c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, long);
10547c478bd9Sstevel@tonic-gate 			break;
10557c478bd9Sstevel@tonic-gate 		  case T_U_LONG:
10567c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, unsigned long);
10577c478bd9Sstevel@tonic-gate 			break;
10587c478bd9Sstevel@tonic-gate 		  case TP_LONG:
10597c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, long *);
10607c478bd9Sstevel@tonic-gate 			break;
10617c478bd9Sstevel@tonic-gate 		  case T_QUAD:
10627c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, LONGLONG_T);
10637c478bd9Sstevel@tonic-gate 			break;
10647c478bd9Sstevel@tonic-gate 		  case T_U_QUAD:
10657c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, ULONGLONG_T);
10667c478bd9Sstevel@tonic-gate 			break;
10677c478bd9Sstevel@tonic-gate 		  case TP_QUAD:
10687c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, LONGLONG_T *);
10697c478bd9Sstevel@tonic-gate 			break;
10707c478bd9Sstevel@tonic-gate 		  case T_DOUBLE:
10717c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, double);
10727c478bd9Sstevel@tonic-gate 			break;
10737c478bd9Sstevel@tonic-gate 		  case TP_CHAR:
10747c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, char *);
10757c478bd9Sstevel@tonic-gate 			break;
10767c478bd9Sstevel@tonic-gate 		  case TP_VOID:
10777c478bd9Sstevel@tonic-gate 			(void) SM_VA_ARG(ap, void *);
10787c478bd9Sstevel@tonic-gate 			break;
10797c478bd9Sstevel@tonic-gate 		}
10807c478bd9Sstevel@tonic-gate 	}
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	if ((typetable != NULL) && (typetable != stattypetable))
10837c478bd9Sstevel@tonic-gate 		sm_free(typetable);
10847c478bd9Sstevel@tonic-gate }
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate /*
10877c478bd9Sstevel@tonic-gate **  SM_GROW_TYPE_TABLE -- Increase the size of the type table.
10887c478bd9Sstevel@tonic-gate **
10897c478bd9Sstevel@tonic-gate **	Parameters:
10907c478bd9Sstevel@tonic-gate **		tabletype -- type of table to grow
10917c478bd9Sstevel@tonic-gate **		tablesize -- requested new table size
10927c478bd9Sstevel@tonic-gate **
10937c478bd9Sstevel@tonic-gate **	Results:
10947c478bd9Sstevel@tonic-gate **		Raises an exception if can't allocate memory.
10957c478bd9Sstevel@tonic-gate */
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate static void
10987c478bd9Sstevel@tonic-gate sm_grow_type_table_x(typetable, tablesize)
10997c478bd9Sstevel@tonic-gate 	unsigned char **typetable;
11007c478bd9Sstevel@tonic-gate 	int *tablesize;
11017c478bd9Sstevel@tonic-gate {
11027c478bd9Sstevel@tonic-gate 	unsigned char *oldtable = *typetable;
11037c478bd9Sstevel@tonic-gate 	int newsize = *tablesize * 2;
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	if (*tablesize == STATIC_ARG_TBL_SIZE)
11067c478bd9Sstevel@tonic-gate 	{
11077c478bd9Sstevel@tonic-gate 		*typetable = (unsigned char *) sm_malloc_x(sizeof(unsigned char)
11087c478bd9Sstevel@tonic-gate 							   * newsize);
11097c478bd9Sstevel@tonic-gate 		(void) memmove(*typetable, oldtable, *tablesize);
11107c478bd9Sstevel@tonic-gate 	}
11117c478bd9Sstevel@tonic-gate 	else
11127c478bd9Sstevel@tonic-gate 	{
11137c478bd9Sstevel@tonic-gate 		*typetable = (unsigned char *) sm_realloc_x(typetable,
11147c478bd9Sstevel@tonic-gate 					sizeof(unsigned char) * newsize);
11157c478bd9Sstevel@tonic-gate 	}
11167c478bd9Sstevel@tonic-gate 	(void) memset(&typetable [*tablesize], T_UNUSED,
11177c478bd9Sstevel@tonic-gate 		       (newsize - *tablesize));
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	*tablesize = newsize;
11207c478bd9Sstevel@tonic-gate }
1121