190792Sgshapiro/* 2261194Sgshapiro * Copyright (c) 2000-2001, 2004 Proofpoint, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * Copyright (c) 1990 590792Sgshapiro * The Regents of the University of California. All rights reserved. 690792Sgshapiro * 790792Sgshapiro * This code is derived from software contributed to Berkeley by 890792Sgshapiro * Chris Torek. 990792Sgshapiro * 1090792Sgshapiro * By using this file, you agree to the terms and conditions set 1190792Sgshapiro * forth in the LICENSE file which can be found at the top level of 1290792Sgshapiro * the sendmail distribution. 1390792Sgshapiro */ 1490792Sgshapiro 1590792Sgshapiro#include <sm/gen.h> 16266527SgshapiroSM_IDSTR(id, "@(#)$Id: vfprintf.c,v 1.55 2013-11-22 20:51:44 ca Exp $") 1790792Sgshapiro 1890792Sgshapiro/* 1990792Sgshapiro** Overall: 2090792Sgshapiro** Actual printing innards. 2190792Sgshapiro** This code is large and complicated... 2290792Sgshapiro*/ 2390792Sgshapiro 2490792Sgshapiro#include <sys/types.h> 2590792Sgshapiro#include <stdlib.h> 2690792Sgshapiro#include <string.h> 2790792Sgshapiro#include <errno.h> 2890792Sgshapiro#include <sm/config.h> 2990792Sgshapiro#include <sm/varargs.h> 3090792Sgshapiro#include <sm/io.h> 3190792Sgshapiro#include <sm/heap.h> 3290792Sgshapiro#include <sm/conf.h> 3390792Sgshapiro#include "local.h" 3490792Sgshapiro#include "fvwrite.h" 3590792Sgshapiro 36141858Sgshapirostatic int sm_bprintf __P((SM_FILE_T *, const char *, va_list)); 3790792Sgshapirostatic void sm_find_arguments __P((const char *, va_list , va_list **)); 3890792Sgshapirostatic void sm_grow_type_table_x __P((unsigned char **, int *)); 3990792Sgshapirostatic int sm_print __P((SM_FILE_T *, int, struct sm_uio *)); 4090792Sgshapiro 4190792Sgshapiro/* 4290792Sgshapiro** SM_PRINT -- print/flush to the file 4390792Sgshapiro** 4490792Sgshapiro** Flush out all the vectors defined by the given uio, 4590792Sgshapiro** then reset it so that it can be reused. 4690792Sgshapiro** 4790792Sgshapiro** Parameters: 4890792Sgshapiro** fp -- file pointer 4990792Sgshapiro** timeout -- time to complete operation (milliseconds) 5090792Sgshapiro** uio -- vector list of memory locations of data for printing 5190792Sgshapiro** 5290792Sgshapiro** Results: 5390792Sgshapiro** Success: 0 (zero) 5490792Sgshapiro** Failure: 5590792Sgshapiro*/ 5690792Sgshapiro 5790792Sgshapirostatic int 5890792Sgshapirosm_print(fp, timeout, uio) 5990792Sgshapiro SM_FILE_T *fp; 6090792Sgshapiro int timeout; 6190792Sgshapiro register struct sm_uio *uio; 6290792Sgshapiro{ 6390792Sgshapiro register int err; 6490792Sgshapiro 6590792Sgshapiro if (uio->uio_resid == 0) 6690792Sgshapiro { 6790792Sgshapiro uio->uio_iovcnt = 0; 6890792Sgshapiro return 0; 6990792Sgshapiro } 7090792Sgshapiro err = sm_fvwrite(fp, timeout, uio); 7190792Sgshapiro uio->uio_resid = 0; 7290792Sgshapiro uio->uio_iovcnt = 0; 7390792Sgshapiro return err; 7490792Sgshapiro} 7590792Sgshapiro 7690792Sgshapiro/* 7790792Sgshapiro** SM_BPRINTF -- allow formating to an unbuffered file. 7890792Sgshapiro** 7990792Sgshapiro** Helper function for `fprintf to unbuffered unix file': creates a 8090792Sgshapiro** temporary buffer (via a "fake" file pointer). 8190792Sgshapiro** We only work on write-only files; this avoids 8290792Sgshapiro** worries about ungetc buffers and so forth. 8390792Sgshapiro** 8490792Sgshapiro** Parameters: 8590792Sgshapiro** fp -- the file to send the o/p to 8690792Sgshapiro** fmt -- format instructions for the o/p 8790792Sgshapiro** ap -- vectors of data units used for formating 8890792Sgshapiro** 8990792Sgshapiro** Results: 9090792Sgshapiro** Failure: SM_IO_EOF and errno set 9190792Sgshapiro** Success: number of data units used in the formating 9290792Sgshapiro** 9390792Sgshapiro** Side effects: 9490792Sgshapiro** formatted o/p can be SM_IO_BUFSIZ length maximum 9590792Sgshapiro*/ 9690792Sgshapiro 9790792Sgshapirostatic int 9890792Sgshapirosm_bprintf(fp, fmt, ap) 99141858Sgshapiro SM_FILE_T *fp; 10090792Sgshapiro const char *fmt; 10190792Sgshapiro SM_VA_LOCAL_DECL 10290792Sgshapiro{ 10390792Sgshapiro int ret; 10490792Sgshapiro SM_FILE_T fake; 10590792Sgshapiro unsigned char buf[SM_IO_BUFSIZ]; 10690792Sgshapiro extern const char SmFileMagic[]; 10790792Sgshapiro 10890792Sgshapiro /* copy the important variables */ 10990792Sgshapiro fake.sm_magic = SmFileMagic; 11090792Sgshapiro fake.f_timeout = SM_TIME_FOREVER; 11190792Sgshapiro fake.f_timeoutstate = SM_TIME_BLOCK; 11290792Sgshapiro fake.f_flags = fp->f_flags & ~SMNBF; 11390792Sgshapiro fake.f_file = fp->f_file; 11490792Sgshapiro fake.f_cookie = fp->f_cookie; 11590792Sgshapiro fake.f_write = fp->f_write; 11690792Sgshapiro fake.f_close = NULL; 11790792Sgshapiro fake.f_open = NULL; 11890792Sgshapiro fake.f_read = NULL; 11990792Sgshapiro fake.f_seek = NULL; 12090792Sgshapiro fake.f_setinfo = fake.f_getinfo = NULL; 12190792Sgshapiro fake.f_type = "sm_bprintf:fake"; 12290792Sgshapiro 12390792Sgshapiro /* set up the buffer */ 12490792Sgshapiro fake.f_bf.smb_base = fake.f_p = buf; 12590792Sgshapiro fake.f_bf.smb_size = fake.f_w = sizeof(buf); 12690792Sgshapiro fake.f_lbfsize = 0; /* not actually used, but Just In Case */ 12790792Sgshapiro 12890792Sgshapiro /* do the work, then copy any error status */ 12990792Sgshapiro ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap); 13090792Sgshapiro if (ret >= 0 && sm_io_flush(&fake, SM_TIME_FOREVER)) 13190792Sgshapiro ret = SM_IO_EOF; /* errno set by sm_io_flush */ 13290792Sgshapiro if (fake.f_flags & SMERR) 13390792Sgshapiro fp->f_flags |= SMERR; 13490792Sgshapiro return ret; 13590792Sgshapiro} 13690792Sgshapiro 13790792Sgshapiro 13890792Sgshapiro#define BUF 40 13990792Sgshapiro 14090792Sgshapiro#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 14190792Sgshapiro 14290792Sgshapiro 14390792Sgshapiro/* Macros for converting digits to letters and vice versa */ 14490792Sgshapiro#define to_digit(c) ((c) - '0') 14590792Sgshapiro#define is_digit(c) ((unsigned) to_digit(c) <= 9) 14690792Sgshapiro#define to_char(n) ((char) (n) + '0') 14790792Sgshapiro 14890792Sgshapiro/* Flags used during conversion. */ 14990792Sgshapiro#define ALT 0x001 /* alternate form */ 15090792Sgshapiro#define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 15190792Sgshapiro#define LADJUST 0x004 /* left adjustment */ 15290792Sgshapiro#define LONGINT 0x010 /* long integer */ 15390792Sgshapiro#define QUADINT 0x020 /* quad integer */ 15490792Sgshapiro#define SHORTINT 0x040 /* short integer */ 15590792Sgshapiro#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 15690792Sgshapiro#define FPT 0x100 /* Floating point number */ 15790792Sgshapiro 15890792Sgshapiro/* 159285229Sgshapiro** SM_IO_VFPRINTF -- performs actual formating for o/p 16090792Sgshapiro** 16190792Sgshapiro** Parameters: 16290792Sgshapiro** fp -- file pointer for o/p 16390792Sgshapiro** timeout -- time to complete the print 16490792Sgshapiro** fmt0 -- formating directives 16590792Sgshapiro** ap -- vectors with data units for formating 16690792Sgshapiro** 16790792Sgshapiro** Results: 16890792Sgshapiro** Success: number of data units used for formatting 16990792Sgshapiro** Failure: SM_IO_EOF and sets errno 17090792Sgshapiro*/ 17190792Sgshapiro 17290792Sgshapiroint 17390792Sgshapirosm_io_vfprintf(fp, timeout, fmt0, ap) 17490792Sgshapiro SM_FILE_T *fp; 17590792Sgshapiro int timeout; 17690792Sgshapiro const char *fmt0; 17790792Sgshapiro SM_VA_LOCAL_DECL 17890792Sgshapiro{ 17990792Sgshapiro register char *fmt; /* format string */ 18090792Sgshapiro register int ch; /* character from fmt */ 18190792Sgshapiro register int n, m, n2; /* handy integers (short term usage) */ 18290792Sgshapiro register char *cp; /* handy char pointer (short term usage) */ 18390792Sgshapiro register struct sm_iov *iovp;/* for PRINT macro */ 18490792Sgshapiro register int flags; /* flags as above */ 18590792Sgshapiro int ret; /* return value accumulator */ 18690792Sgshapiro int width; /* width from format (%8d), or 0 */ 18790792Sgshapiro int prec; /* precision from format (%.3d), or -1 */ 18890792Sgshapiro char sign; /* sign prefix (' ', '+', '-', or \0) */ 18990792Sgshapiro wchar_t wc; 19090792Sgshapiro ULONGLONG_T _uquad; /* integer arguments %[diouxX] */ 19190792Sgshapiro enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ 19290792Sgshapiro int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 19390792Sgshapiro int realsz; /* field size expanded by dprec */ 19490792Sgshapiro int size; /* size of converted field or string */ 19590792Sgshapiro char *xdigs="0123456789abcdef"; /* digits for [xX] conversion */ 19690792Sgshapiro#define NIOV 8 19790792Sgshapiro struct sm_uio uio; /* output information: summary */ 19890792Sgshapiro struct sm_iov iov[NIOV];/* ... and individual io vectors */ 19990792Sgshapiro char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 20090792Sgshapiro char ox[2]; /* space for 0x hex-prefix */ 20190792Sgshapiro va_list *argtable; /* args, built due to positional arg */ 20290792Sgshapiro va_list statargtable[STATIC_ARG_TBL_SIZE]; 20390792Sgshapiro int nextarg; /* 1-based argument index */ 20490792Sgshapiro va_list orgap; /* original argument pointer */ 20590792Sgshapiro 20690792Sgshapiro /* 20790792Sgshapiro ** Choose PADSIZE to trade efficiency vs. size. If larger printf 20890792Sgshapiro ** fields occur frequently, increase PADSIZE and make the initialisers 20990792Sgshapiro ** below longer. 21090792Sgshapiro */ 21190792Sgshapiro#define PADSIZE 16 /* pad chunk size */ 21290792Sgshapiro static char blanks[PADSIZE] = 21390792Sgshapiro {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 21490792Sgshapiro static char zeroes[PADSIZE] = 21590792Sgshapiro {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 21690792Sgshapiro 21790792Sgshapiro /* 21890792Sgshapiro ** BEWARE, these `goto error' on error, and PAD uses `n'. 21990792Sgshapiro */ 22090792Sgshapiro#define PRINT(ptr, len) do { \ 22190792Sgshapiro iovp->iov_base = (ptr); \ 22290792Sgshapiro iovp->iov_len = (len); \ 22390792Sgshapiro uio.uio_resid += (len); \ 22490792Sgshapiro iovp++; \ 22590792Sgshapiro if (++uio.uio_iovcnt >= NIOV) \ 22690792Sgshapiro { \ 22790792Sgshapiro if (sm_print(fp, timeout, &uio)) \ 22890792Sgshapiro goto error; \ 22990792Sgshapiro iovp = iov; \ 23090792Sgshapiro } \ 23190792Sgshapiro} while (0) 23290792Sgshapiro#define PAD(howmany, with) do \ 23390792Sgshapiro{ \ 23490792Sgshapiro if ((n = (howmany)) > 0) \ 23590792Sgshapiro { \ 23690792Sgshapiro while (n > PADSIZE) { \ 23790792Sgshapiro PRINT(with, PADSIZE); \ 23890792Sgshapiro n -= PADSIZE; \ 23990792Sgshapiro } \ 24090792Sgshapiro PRINT(with, n); \ 24190792Sgshapiro } \ 24290792Sgshapiro} while (0) 24390792Sgshapiro#define FLUSH() do \ 24490792Sgshapiro{ \ 24590792Sgshapiro if (uio.uio_resid && sm_print(fp, timeout, &uio)) \ 24690792Sgshapiro goto error; \ 24790792Sgshapiro uio.uio_iovcnt = 0; \ 24890792Sgshapiro iovp = iov; \ 24990792Sgshapiro} while (0) 25090792Sgshapiro 25190792Sgshapiro /* 25290792Sgshapiro ** To extend shorts properly, we need both signed and unsigned 25390792Sgshapiro ** argument extraction methods. 25490792Sgshapiro */ 25590792Sgshapiro#define SARG() \ 25690792Sgshapiro (flags&QUADINT ? SM_VA_ARG(ap, LONGLONG_T) : \ 25790792Sgshapiro flags&LONGINT ? GETARG(long) : \ 25890792Sgshapiro flags&SHORTINT ? (long) (short) GETARG(int) : \ 25990792Sgshapiro (long) GETARG(int)) 26090792Sgshapiro#define UARG() \ 26190792Sgshapiro (flags&QUADINT ? SM_VA_ARG(ap, ULONGLONG_T) : \ 26290792Sgshapiro flags&LONGINT ? GETARG(unsigned long) : \ 26390792Sgshapiro flags&SHORTINT ? (unsigned long) (unsigned short) GETARG(int) : \ 26490792Sgshapiro (unsigned long) GETARG(unsigned int)) 26590792Sgshapiro 26690792Sgshapiro /* 26790792Sgshapiro ** Get * arguments, including the form *nn$. Preserve the nextarg 26890792Sgshapiro ** that the argument can be gotten once the type is determined. 26990792Sgshapiro */ 27090792Sgshapiro#define GETASTER(val) \ 27190792Sgshapiro n2 = 0; \ 27290792Sgshapiro cp = fmt; \ 27390792Sgshapiro while (is_digit(*cp)) \ 27490792Sgshapiro { \ 27590792Sgshapiro n2 = 10 * n2 + to_digit(*cp); \ 27690792Sgshapiro cp++; \ 27790792Sgshapiro } \ 27890792Sgshapiro if (*cp == '$') \ 27990792Sgshapiro { \ 28090792Sgshapiro int hold = nextarg; \ 28190792Sgshapiro if (argtable == NULL) \ 28290792Sgshapiro { \ 28390792Sgshapiro argtable = statargtable; \ 28490792Sgshapiro sm_find_arguments(fmt0, orgap, &argtable); \ 28590792Sgshapiro } \ 28690792Sgshapiro nextarg = n2; \ 28790792Sgshapiro val = GETARG(int); \ 28890792Sgshapiro nextarg = hold; \ 28990792Sgshapiro fmt = ++cp; \ 29090792Sgshapiro } \ 29190792Sgshapiro else \ 29290792Sgshapiro { \ 29390792Sgshapiro val = GETARG(int); \ 29490792Sgshapiro } 29590792Sgshapiro 29690792Sgshapiro/* 29790792Sgshapiro** Get the argument indexed by nextarg. If the argument table is 29890792Sgshapiro** built, use it to get the argument. If its not, get the next 29990792Sgshapiro** argument (and arguments must be gotten sequentially). 30090792Sgshapiro*/ 30190792Sgshapiro 30290792Sgshapiro#if SM_VA_STD 30390792Sgshapiro# define GETARG(type) \ 30490792Sgshapiro (((argtable != NULL) ? (void) (ap = argtable[nextarg]) : (void) 0), \ 30590792Sgshapiro nextarg++, SM_VA_ARG(ap, type)) 30690792Sgshapiro#else /* SM_VA_STD */ 30790792Sgshapiro# define GETARG(type) \ 30890792Sgshapiro ((argtable != NULL) ? (*((type*)(argtable[nextarg++]))) : \ 30990792Sgshapiro (nextarg++, SM_VA_ARG(ap, type))) 31090792Sgshapiro#endif /* SM_VA_STD */ 31190792Sgshapiro 31290792Sgshapiro /* sorry, fprintf(read_only_file, "") returns SM_IO_EOF, not 0 */ 31390792Sgshapiro if (cantwrite(fp)) 31490792Sgshapiro { 31590792Sgshapiro errno = EBADF; 31690792Sgshapiro return SM_IO_EOF; 31790792Sgshapiro } 31890792Sgshapiro 31990792Sgshapiro /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 32090792Sgshapiro if ((fp->f_flags & (SMNBF|SMWR|SMRW)) == (SMNBF|SMWR) && 32190792Sgshapiro fp->f_file >= 0) 32290792Sgshapiro return sm_bprintf(fp, fmt0, ap); 32390792Sgshapiro 32490792Sgshapiro fmt = (char *) fmt0; 32590792Sgshapiro argtable = NULL; 32690792Sgshapiro nextarg = 1; 32790792Sgshapiro SM_VA_COPY(orgap, ap); 32890792Sgshapiro uio.uio_iov = iovp = iov; 32990792Sgshapiro uio.uio_resid = 0; 33090792Sgshapiro uio.uio_iovcnt = 0; 33190792Sgshapiro ret = 0; 33290792Sgshapiro 33390792Sgshapiro /* Scan the format for conversions (`%' character). */ 33490792Sgshapiro for (;;) 33590792Sgshapiro { 33690792Sgshapiro cp = fmt; 33790792Sgshapiro n = 0; 33890792Sgshapiro while ((wc = *fmt) != '\0') 33990792Sgshapiro { 34090792Sgshapiro if (wc == '%') 34190792Sgshapiro { 34290792Sgshapiro n = 1; 34390792Sgshapiro break; 34490792Sgshapiro } 34590792Sgshapiro fmt++; 34690792Sgshapiro } 34790792Sgshapiro if ((m = fmt - cp) != 0) 34890792Sgshapiro { 34990792Sgshapiro PRINT(cp, m); 35090792Sgshapiro ret += m; 35190792Sgshapiro } 35290792Sgshapiro if (n <= 0) 35390792Sgshapiro goto done; 35490792Sgshapiro fmt++; /* skip over '%' */ 35590792Sgshapiro 35690792Sgshapiro flags = 0; 35790792Sgshapiro dprec = 0; 35890792Sgshapiro width = 0; 35990792Sgshapiro prec = -1; 36090792Sgshapiro sign = '\0'; 36190792Sgshapiro 36290792Sgshapirorflag: ch = *fmt++; 36390792Sgshapiroreswitch: switch (ch) 36490792Sgshapiro { 36590792Sgshapiro case ' ': 36690792Sgshapiro 36790792Sgshapiro /* 36890792Sgshapiro ** ``If the space and + flags both appear, the space 36990792Sgshapiro ** flag will be ignored.'' 37090792Sgshapiro ** -- ANSI X3J11 37190792Sgshapiro */ 37290792Sgshapiro 37390792Sgshapiro if (!sign) 37490792Sgshapiro sign = ' '; 37590792Sgshapiro goto rflag; 37690792Sgshapiro case '#': 37790792Sgshapiro flags |= ALT; 37890792Sgshapiro goto rflag; 37990792Sgshapiro case '*': 38090792Sgshapiro 38190792Sgshapiro /* 38290792Sgshapiro ** ``A negative field width argument is taken as a 38390792Sgshapiro ** - flag followed by a positive field width.'' 38490792Sgshapiro ** -- ANSI X3J11 38590792Sgshapiro ** They don't exclude field widths read from args. 38690792Sgshapiro */ 38790792Sgshapiro 38890792Sgshapiro GETASTER(width); 38990792Sgshapiro if (width >= 0) 39090792Sgshapiro goto rflag; 39190792Sgshapiro width = -width; 39290792Sgshapiro /* FALLTHROUGH */ 39390792Sgshapiro case '-': 39490792Sgshapiro flags |= LADJUST; 39590792Sgshapiro goto rflag; 39690792Sgshapiro case '+': 39790792Sgshapiro sign = '+'; 39890792Sgshapiro goto rflag; 39990792Sgshapiro case '.': 40090792Sgshapiro if ((ch = *fmt++) == '*') 40190792Sgshapiro { 40290792Sgshapiro GETASTER(n); 40390792Sgshapiro prec = n < 0 ? -1 : n; 40490792Sgshapiro goto rflag; 40590792Sgshapiro } 40690792Sgshapiro n = 0; 40790792Sgshapiro while (is_digit(ch)) 40890792Sgshapiro { 40990792Sgshapiro n = 10 * n + to_digit(ch); 41090792Sgshapiro ch = *fmt++; 41190792Sgshapiro } 41290792Sgshapiro if (ch == '$') 41390792Sgshapiro { 41490792Sgshapiro nextarg = n; 41590792Sgshapiro if (argtable == NULL) 41690792Sgshapiro { 41790792Sgshapiro argtable = statargtable; 41890792Sgshapiro sm_find_arguments(fmt0, orgap, 41990792Sgshapiro &argtable); 42090792Sgshapiro } 42190792Sgshapiro goto rflag; 42290792Sgshapiro } 42390792Sgshapiro prec = n < 0 ? -1 : n; 42490792Sgshapiro goto reswitch; 42590792Sgshapiro case '0': 42690792Sgshapiro 42790792Sgshapiro /* 42890792Sgshapiro ** ``Note that 0 is taken as a flag, not as the 42990792Sgshapiro ** beginning of a field width.'' 43090792Sgshapiro ** -- ANSI X3J11 43190792Sgshapiro */ 43290792Sgshapiro 43390792Sgshapiro flags |= ZEROPAD; 43490792Sgshapiro goto rflag; 43590792Sgshapiro case '1': case '2': case '3': case '4': 43690792Sgshapiro case '5': case '6': case '7': case '8': case '9': 43790792Sgshapiro n = 0; 43890792Sgshapiro do 43990792Sgshapiro { 44090792Sgshapiro n = 10 * n + to_digit(ch); 44190792Sgshapiro ch = *fmt++; 44290792Sgshapiro } while (is_digit(ch)); 44390792Sgshapiro if (ch == '$') 44490792Sgshapiro { 44590792Sgshapiro nextarg = n; 44690792Sgshapiro if (argtable == NULL) 44790792Sgshapiro { 44890792Sgshapiro argtable = statargtable; 44990792Sgshapiro sm_find_arguments(fmt0, orgap, 45090792Sgshapiro &argtable); 45190792Sgshapiro } 45290792Sgshapiro goto rflag; 45390792Sgshapiro } 45490792Sgshapiro width = n; 45590792Sgshapiro goto reswitch; 45690792Sgshapiro case 'h': 45790792Sgshapiro flags |= SHORTINT; 45890792Sgshapiro goto rflag; 45990792Sgshapiro case 'l': 46090792Sgshapiro if (*fmt == 'l') 46190792Sgshapiro { 46290792Sgshapiro fmt++; 46390792Sgshapiro flags |= QUADINT; 46490792Sgshapiro } 46590792Sgshapiro else 46690792Sgshapiro { 46790792Sgshapiro flags |= LONGINT; 46890792Sgshapiro } 46990792Sgshapiro goto rflag; 47090792Sgshapiro case 'q': 47190792Sgshapiro flags |= QUADINT; 47290792Sgshapiro goto rflag; 47390792Sgshapiro case 'c': 47490792Sgshapiro *(cp = buf) = GETARG(int); 47590792Sgshapiro size = 1; 47690792Sgshapiro sign = '\0'; 47790792Sgshapiro break; 47890792Sgshapiro case 'D': 47990792Sgshapiro flags |= LONGINT; 48090792Sgshapiro /*FALLTHROUGH*/ 48190792Sgshapiro case 'd': 48290792Sgshapiro case 'i': 48390792Sgshapiro _uquad = SARG(); 48490792Sgshapiro if ((LONGLONG_T) _uquad < 0) 48590792Sgshapiro { 48690792Sgshapiro _uquad = -(LONGLONG_T) _uquad; 48790792Sgshapiro sign = '-'; 48890792Sgshapiro } 48990792Sgshapiro base = DEC; 49090792Sgshapiro goto number; 49190792Sgshapiro case 'e': 49290792Sgshapiro case 'E': 49390792Sgshapiro case 'f': 49490792Sgshapiro case 'g': 49590792Sgshapiro case 'G': 49690792Sgshapiro { 49790792Sgshapiro double val; 49890792Sgshapiro char *p; 49990792Sgshapiro char fmt[16]; 50090792Sgshapiro char out[150]; 50190792Sgshapiro size_t len; 50290792Sgshapiro 50390792Sgshapiro /* 50490792Sgshapiro ** This code implements floating point output 50590792Sgshapiro ** in the most portable manner possible, 50690792Sgshapiro ** relying only on 'sprintf' as defined by 50790792Sgshapiro ** the 1989 ANSI C standard. 50890792Sgshapiro ** We silently cap width and precision 50990792Sgshapiro ** at 120, to avoid buffer overflow. 51090792Sgshapiro */ 51190792Sgshapiro 51290792Sgshapiro val = GETARG(double); 51390792Sgshapiro 51490792Sgshapiro p = fmt; 51590792Sgshapiro *p++ = '%'; 51690792Sgshapiro if (sign) 51790792Sgshapiro *p++ = sign; 51890792Sgshapiro if (flags & ALT) 51990792Sgshapiro *p++ = '#'; 52090792Sgshapiro if (flags & LADJUST) 52190792Sgshapiro *p++ = '-'; 52290792Sgshapiro if (flags & ZEROPAD) 52390792Sgshapiro *p++ = '0'; 52490792Sgshapiro *p++ = '*'; 52590792Sgshapiro if (prec >= 0) 52690792Sgshapiro { 52790792Sgshapiro *p++ = '.'; 52890792Sgshapiro *p++ = '*'; 52990792Sgshapiro } 53090792Sgshapiro *p++ = ch; 53190792Sgshapiro *p = '\0'; 53290792Sgshapiro 53390792Sgshapiro if (width > 120) 53490792Sgshapiro width = 120; 53590792Sgshapiro if (prec > 120) 53690792Sgshapiro prec = 120; 53790792Sgshapiro if (prec >= 0) 538157001Sgshapiro#if HASSNPRINTF 539157001Sgshapiro snprintf(out, sizeof(out), fmt, width, 540157001Sgshapiro prec, val); 541157001Sgshapiro#else /* HASSNPRINTF */ 54290792Sgshapiro sprintf(out, fmt, width, prec, val); 543157001Sgshapiro#endif /* HASSNPRINTF */ 54490792Sgshapiro else 545157001Sgshapiro#if HASSNPRINTF 546157001Sgshapiro snprintf(out, sizeof(out), fmt, width, 547157001Sgshapiro val); 548157001Sgshapiro#else /* HASSNPRINTF */ 54990792Sgshapiro sprintf(out, fmt, width, val); 550157001Sgshapiro#endif /* HASSNPRINTF */ 55190792Sgshapiro len = strlen(out); 55290792Sgshapiro PRINT(out, len); 55390792Sgshapiro FLUSH(); 55490792Sgshapiro continue; 55590792Sgshapiro } 55690792Sgshapiro case 'n': 55790792Sgshapiro if (flags & QUADINT) 55890792Sgshapiro *GETARG(LONGLONG_T *) = ret; 55990792Sgshapiro else if (flags & LONGINT) 56090792Sgshapiro *GETARG(long *) = ret; 56190792Sgshapiro else if (flags & SHORTINT) 56290792Sgshapiro *GETARG(short *) = ret; 56390792Sgshapiro else 56490792Sgshapiro *GETARG(int *) = ret; 56590792Sgshapiro continue; /* no output */ 56690792Sgshapiro case 'O': 56790792Sgshapiro flags |= LONGINT; 56890792Sgshapiro /*FALLTHROUGH*/ 56990792Sgshapiro case 'o': 57090792Sgshapiro _uquad = UARG(); 57190792Sgshapiro base = OCT; 57290792Sgshapiro goto nosign; 57390792Sgshapiro case 'p': 57490792Sgshapiro 57590792Sgshapiro /* 57690792Sgshapiro ** ``The argument shall be a pointer to void. The 57790792Sgshapiro ** value of the pointer is converted to a sequence 57890792Sgshapiro ** of printable characters, in an implementation- 57990792Sgshapiro ** defined manner.'' 58090792Sgshapiro ** -- ANSI X3J11 58190792Sgshapiro */ 58290792Sgshapiro 58390792Sgshapiro /* NOSTRICT */ 58490792Sgshapiro { 58590792Sgshapiro union 58690792Sgshapiro { 58790792Sgshapiro void *p; 58890792Sgshapiro ULONGLONG_T ll; 58990792Sgshapiro unsigned long l; 59090792Sgshapiro unsigned i; 59190792Sgshapiro } u; 59290792Sgshapiro u.p = GETARG(void *); 59390792Sgshapiro if (sizeof(void *) == sizeof(ULONGLONG_T)) 59490792Sgshapiro _uquad = u.ll; 59590792Sgshapiro else if (sizeof(void *) == sizeof(long)) 59690792Sgshapiro _uquad = u.l; 59790792Sgshapiro else 59890792Sgshapiro _uquad = u.i; 59990792Sgshapiro } 60090792Sgshapiro base = HEX; 60190792Sgshapiro xdigs = "0123456789abcdef"; 60290792Sgshapiro flags |= HEXPREFIX; 60390792Sgshapiro ch = 'x'; 60490792Sgshapiro goto nosign; 60590792Sgshapiro case 's': 60690792Sgshapiro if ((cp = GETARG(char *)) == NULL) 60790792Sgshapiro cp = "(null)"; 60890792Sgshapiro if (prec >= 0) 60990792Sgshapiro { 61090792Sgshapiro /* 61190792Sgshapiro ** can't use strlen; can only look for the 61290792Sgshapiro ** NUL in the first `prec' characters, and 61390792Sgshapiro ** strlen() will go further. 61490792Sgshapiro */ 61590792Sgshapiro 61690792Sgshapiro char *p = memchr(cp, 0, prec); 61790792Sgshapiro 61890792Sgshapiro if (p != NULL) 61990792Sgshapiro { 62090792Sgshapiro size = p - cp; 62190792Sgshapiro if (size > prec) 62290792Sgshapiro size = prec; 62390792Sgshapiro } 62490792Sgshapiro else 62590792Sgshapiro size = prec; 62690792Sgshapiro } 62790792Sgshapiro else 62890792Sgshapiro size = strlen(cp); 62990792Sgshapiro sign = '\0'; 63090792Sgshapiro break; 63190792Sgshapiro case 'U': 63290792Sgshapiro flags |= LONGINT; 63390792Sgshapiro /*FALLTHROUGH*/ 63490792Sgshapiro case 'u': 63590792Sgshapiro _uquad = UARG(); 63690792Sgshapiro base = DEC; 63790792Sgshapiro goto nosign; 63890792Sgshapiro case 'X': 63990792Sgshapiro xdigs = "0123456789ABCDEF"; 64090792Sgshapiro goto hex; 64190792Sgshapiro case 'x': 64290792Sgshapiro xdigs = "0123456789abcdef"; 64390792Sgshapirohex: _uquad = UARG(); 64490792Sgshapiro base = HEX; 64590792Sgshapiro /* leading 0x/X only if non-zero */ 64690792Sgshapiro if (flags & ALT && _uquad != 0) 64790792Sgshapiro flags |= HEXPREFIX; 64890792Sgshapiro 64990792Sgshapiro /* unsigned conversions */ 65090792Sgshapironosign: sign = '\0'; 65190792Sgshapiro 65290792Sgshapiro /* 65390792Sgshapiro ** ``... diouXx conversions ... if a precision is 65490792Sgshapiro ** specified, the 0 flag will be ignored.'' 65590792Sgshapiro ** -- ANSI X3J11 65690792Sgshapiro */ 65790792Sgshapiro 65890792Sgshapironumber: if ((dprec = prec) >= 0) 65990792Sgshapiro flags &= ~ZEROPAD; 66090792Sgshapiro 66190792Sgshapiro /* 66290792Sgshapiro ** ``The result of converting a zero value with an 66390792Sgshapiro ** explicit precision of zero is no characters.'' 66490792Sgshapiro ** -- ANSI X3J11 66590792Sgshapiro */ 66690792Sgshapiro 66790792Sgshapiro cp = buf + BUF; 66890792Sgshapiro if (_uquad != 0 || prec != 0) 66990792Sgshapiro { 67090792Sgshapiro /* 67190792Sgshapiro ** Unsigned mod is hard, and unsigned mod 67290792Sgshapiro ** by a constant is easier than that by 67390792Sgshapiro ** a variable; hence this switch. 67490792Sgshapiro */ 67590792Sgshapiro 67690792Sgshapiro switch (base) 67790792Sgshapiro { 67890792Sgshapiro case OCT: 67990792Sgshapiro do 68090792Sgshapiro { 68190792Sgshapiro *--cp = to_char(_uquad & 7); 68290792Sgshapiro _uquad >>= 3; 68390792Sgshapiro } while (_uquad); 68490792Sgshapiro /* handle octal leading 0 */ 68590792Sgshapiro if (flags & ALT && *cp != '0') 68690792Sgshapiro *--cp = '0'; 68790792Sgshapiro break; 68890792Sgshapiro 68990792Sgshapiro case DEC: 69090792Sgshapiro /* many numbers are 1 digit */ 69190792Sgshapiro while (_uquad >= 10) 69290792Sgshapiro { 69390792Sgshapiro *--cp = to_char(_uquad % 10); 69490792Sgshapiro _uquad /= 10; 69590792Sgshapiro } 69690792Sgshapiro *--cp = to_char(_uquad); 69790792Sgshapiro break; 69890792Sgshapiro 69990792Sgshapiro case HEX: 70090792Sgshapiro do 70190792Sgshapiro { 70290792Sgshapiro *--cp = xdigs[_uquad & 15]; 70390792Sgshapiro _uquad >>= 4; 70490792Sgshapiro } while (_uquad); 70590792Sgshapiro break; 70690792Sgshapiro 70790792Sgshapiro default: 70890792Sgshapiro cp = "bug in sm_io_vfprintf: bad base"; 70990792Sgshapiro size = strlen(cp); 71090792Sgshapiro goto skipsize; 71190792Sgshapiro } 71290792Sgshapiro } 71390792Sgshapiro size = buf + BUF - cp; 71490792Sgshapiro skipsize: 71590792Sgshapiro break; 71690792Sgshapiro default: /* "%?" prints ?, unless ? is NUL */ 71790792Sgshapiro if (ch == '\0') 71890792Sgshapiro goto done; 71990792Sgshapiro /* pretend it was %c with argument ch */ 72090792Sgshapiro cp = buf; 72190792Sgshapiro *cp = ch; 72290792Sgshapiro size = 1; 72390792Sgshapiro sign = '\0'; 72490792Sgshapiro break; 72590792Sgshapiro } 72690792Sgshapiro 72790792Sgshapiro /* 72890792Sgshapiro ** All reasonable formats wind up here. At this point, `cp' 72990792Sgshapiro ** points to a string which (if not flags&LADJUST) should be 73090792Sgshapiro ** padded out to `width' places. If flags&ZEROPAD, it should 73190792Sgshapiro ** first be prefixed by any sign or other prefix; otherwise, 73290792Sgshapiro ** it should be blank padded before the prefix is emitted. 73390792Sgshapiro ** After any left-hand padding and prefixing, emit zeroes 73490792Sgshapiro ** required by a decimal [diouxX] precision, then print the 73590792Sgshapiro ** string proper, then emit zeroes required by any leftover 73690792Sgshapiro ** floating precision; finally, if LADJUST, pad with blanks. 73790792Sgshapiro ** 73890792Sgshapiro ** Compute actual size, so we know how much to pad. 73990792Sgshapiro ** size excludes decimal prec; realsz includes it. 74090792Sgshapiro */ 74190792Sgshapiro 74290792Sgshapiro realsz = dprec > size ? dprec : size; 74390792Sgshapiro if (sign) 74490792Sgshapiro realsz++; 74590792Sgshapiro else if (flags & HEXPREFIX) 74690792Sgshapiro realsz+= 2; 74790792Sgshapiro 74890792Sgshapiro /* right-adjusting blank padding */ 74990792Sgshapiro if ((flags & (LADJUST|ZEROPAD)) == 0) 75090792Sgshapiro PAD(width - realsz, blanks); 75190792Sgshapiro 75290792Sgshapiro /* prefix */ 75390792Sgshapiro if (sign) 75490792Sgshapiro { 75590792Sgshapiro PRINT(&sign, 1); 75690792Sgshapiro } 75790792Sgshapiro else if (flags & HEXPREFIX) 75890792Sgshapiro { 75990792Sgshapiro ox[0] = '0'; 76090792Sgshapiro ox[1] = ch; 76190792Sgshapiro PRINT(ox, 2); 76290792Sgshapiro } 76390792Sgshapiro 76490792Sgshapiro /* right-adjusting zero padding */ 76590792Sgshapiro if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 76690792Sgshapiro PAD(width - realsz, zeroes); 76790792Sgshapiro 76890792Sgshapiro /* leading zeroes from decimal precision */ 76990792Sgshapiro PAD(dprec - size, zeroes); 77090792Sgshapiro 77190792Sgshapiro /* the string or number proper */ 77290792Sgshapiro PRINT(cp, size); 77390792Sgshapiro /* left-adjusting padding (always blank) */ 77490792Sgshapiro if (flags & LADJUST) 77590792Sgshapiro PAD(width - realsz, blanks); 77690792Sgshapiro 77790792Sgshapiro /* finally, adjust ret */ 77890792Sgshapiro ret += width > realsz ? width : realsz; 77990792Sgshapiro 78090792Sgshapiro FLUSH(); /* copy out the I/O vectors */ 78190792Sgshapiro } 78290792Sgshapirodone: 78390792Sgshapiro FLUSH(); 78490792Sgshapiroerror: 78590792Sgshapiro if ((argtable != NULL) && (argtable != statargtable)) 78690792Sgshapiro sm_free(argtable); 78790792Sgshapiro return sm_error(fp) ? SM_IO_EOF : ret; 78890792Sgshapiro /* NOTREACHED */ 78990792Sgshapiro} 79090792Sgshapiro 79190792Sgshapiro/* Type ids for argument type table. */ 79290792Sgshapiro#define T_UNUSED 0 79390792Sgshapiro#define T_SHORT 1 79490792Sgshapiro#define T_U_SHORT 2 79590792Sgshapiro#define TP_SHORT 3 79690792Sgshapiro#define T_INT 4 79790792Sgshapiro#define T_U_INT 5 79890792Sgshapiro#define TP_INT 6 79990792Sgshapiro#define T_LONG 7 80090792Sgshapiro#define T_U_LONG 8 80190792Sgshapiro#define TP_LONG 9 80290792Sgshapiro#define T_QUAD 10 80390792Sgshapiro#define T_U_QUAD 11 80490792Sgshapiro#define TP_QUAD 12 80590792Sgshapiro#define T_DOUBLE 13 80690792Sgshapiro#define TP_CHAR 15 80790792Sgshapiro#define TP_VOID 16 80890792Sgshapiro 80990792Sgshapiro/* 81090792Sgshapiro** SM_FIND_ARGUMENTS -- find all args when a positional parameter is found. 81190792Sgshapiro** 81290792Sgshapiro** Find all arguments when a positional parameter is encountered. Returns a 81390792Sgshapiro** table, indexed by argument number, of pointers to each arguments. The 81490792Sgshapiro** initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 81590792Sgshapiro** It will be replaced with a malloc-ed one if it overflows. 81690792Sgshapiro** 81790792Sgshapiro** Parameters: 81890792Sgshapiro** fmt0 -- formating directives 81990792Sgshapiro** ap -- vector list of data unit for formating consumption 82090792Sgshapiro** argtable -- an indexable table (returned) of 'ap' 82190792Sgshapiro** 82290792Sgshapiro** Results: 82390792Sgshapiro** none. 82490792Sgshapiro*/ 82590792Sgshapiro 82690792Sgshapirostatic void 82790792Sgshapirosm_find_arguments(fmt0, ap, argtable) 82890792Sgshapiro const char *fmt0; 82990792Sgshapiro SM_VA_LOCAL_DECL 83090792Sgshapiro va_list **argtable; 83190792Sgshapiro{ 83290792Sgshapiro register char *fmt; /* format string */ 83390792Sgshapiro register int ch; /* character from fmt */ 83490792Sgshapiro register int n, n2; /* handy integer (short term usage) */ 83590792Sgshapiro register char *cp; /* handy char pointer (short term usage) */ 83690792Sgshapiro register int flags; /* flags as above */ 83790792Sgshapiro unsigned char *typetable; /* table of types */ 83890792Sgshapiro unsigned char stattypetable[STATIC_ARG_TBL_SIZE]; 83990792Sgshapiro int tablesize; /* current size of type table */ 84090792Sgshapiro int tablemax; /* largest used index in table */ 84190792Sgshapiro int nextarg; /* 1-based argument index */ 84290792Sgshapiro 84390792Sgshapiro /* Add an argument type to the table, expanding if necessary. */ 84490792Sgshapiro#define ADDTYPE(type) \ 84590792Sgshapiro ((nextarg >= tablesize) ? \ 84690792Sgshapiro (sm_grow_type_table_x(&typetable, &tablesize), 0) : 0, \ 84790792Sgshapiro typetable[nextarg++] = type, \ 84890792Sgshapiro (nextarg > tablemax) ? tablemax = nextarg : 0) 84990792Sgshapiro 85090792Sgshapiro#define ADDSARG() \ 85190792Sgshapiro ((flags & LONGINT) ? ADDTYPE(T_LONG) : \ 85290792Sgshapiro ((flags & SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT))) 85390792Sgshapiro 85490792Sgshapiro#define ADDUARG() \ 85590792Sgshapiro ((flags & LONGINT) ? ADDTYPE(T_U_LONG) : \ 85690792Sgshapiro ((flags & SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT))) 85790792Sgshapiro 85890792Sgshapiro /* Add * arguments to the type array. */ 85990792Sgshapiro#define ADDASTER() \ 86090792Sgshapiro n2 = 0; \ 86190792Sgshapiro cp = fmt; \ 86290792Sgshapiro while (is_digit(*cp)) \ 86390792Sgshapiro { \ 86490792Sgshapiro n2 = 10 * n2 + to_digit(*cp); \ 86590792Sgshapiro cp++; \ 86690792Sgshapiro } \ 86790792Sgshapiro if (*cp == '$') \ 86890792Sgshapiro { \ 86990792Sgshapiro int hold = nextarg; \ 87090792Sgshapiro nextarg = n2; \ 87190792Sgshapiro ADDTYPE (T_INT); \ 87290792Sgshapiro nextarg = hold; \ 87390792Sgshapiro fmt = ++cp; \ 87490792Sgshapiro } \ 87590792Sgshapiro else \ 87690792Sgshapiro { \ 87790792Sgshapiro ADDTYPE (T_INT); \ 87890792Sgshapiro } 87990792Sgshapiro fmt = (char *) fmt0; 88090792Sgshapiro typetable = stattypetable; 88190792Sgshapiro tablesize = STATIC_ARG_TBL_SIZE; 88290792Sgshapiro tablemax = 0; 88390792Sgshapiro nextarg = 1; 88490792Sgshapiro (void) memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); 88590792Sgshapiro 88690792Sgshapiro /* Scan the format for conversions (`%' character). */ 88790792Sgshapiro for (;;) 88890792Sgshapiro { 88990792Sgshapiro for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 89090792Sgshapiro /* void */; 89190792Sgshapiro if (ch == '\0') 89290792Sgshapiro goto done; 89390792Sgshapiro fmt++; /* skip over '%' */ 89490792Sgshapiro 89590792Sgshapiro flags = 0; 89690792Sgshapiro 89790792Sgshapirorflag: ch = *fmt++; 89890792Sgshapiroreswitch: switch (ch) 89990792Sgshapiro { 90090792Sgshapiro case ' ': 90190792Sgshapiro case '#': 90290792Sgshapiro goto rflag; 90390792Sgshapiro case '*': 90490792Sgshapiro ADDASTER(); 90590792Sgshapiro goto rflag; 90690792Sgshapiro case '-': 90790792Sgshapiro case '+': 90890792Sgshapiro goto rflag; 90990792Sgshapiro case '.': 91090792Sgshapiro if ((ch = *fmt++) == '*') 91190792Sgshapiro { 91290792Sgshapiro ADDASTER(); 91390792Sgshapiro goto rflag; 91490792Sgshapiro } 91590792Sgshapiro while (is_digit(ch)) 91690792Sgshapiro { 91790792Sgshapiro ch = *fmt++; 91890792Sgshapiro } 91990792Sgshapiro goto reswitch; 92090792Sgshapiro case '0': 92190792Sgshapiro goto rflag; 92290792Sgshapiro case '1': case '2': case '3': case '4': 92390792Sgshapiro case '5': case '6': case '7': case '8': case '9': 92490792Sgshapiro n = 0; 92590792Sgshapiro do 92690792Sgshapiro { 92790792Sgshapiro n = 10 * n + to_digit(ch); 92890792Sgshapiro ch = *fmt++; 92990792Sgshapiro } while (is_digit(ch)); 93090792Sgshapiro if (ch == '$') 93190792Sgshapiro { 93290792Sgshapiro nextarg = n; 93390792Sgshapiro goto rflag; 93490792Sgshapiro } 93590792Sgshapiro goto reswitch; 93690792Sgshapiro case 'h': 93790792Sgshapiro flags |= SHORTINT; 93890792Sgshapiro goto rflag; 93990792Sgshapiro case 'l': 94090792Sgshapiro flags |= LONGINT; 94190792Sgshapiro goto rflag; 94290792Sgshapiro case 'q': 94390792Sgshapiro flags |= QUADINT; 94490792Sgshapiro goto rflag; 94590792Sgshapiro case 'c': 94690792Sgshapiro ADDTYPE(T_INT); 94790792Sgshapiro break; 94890792Sgshapiro case 'D': 94990792Sgshapiro flags |= LONGINT; 95090792Sgshapiro /*FALLTHROUGH*/ 95190792Sgshapiro case 'd': 95290792Sgshapiro case 'i': 95390792Sgshapiro if (flags & QUADINT) 95490792Sgshapiro { 95590792Sgshapiro ADDTYPE(T_QUAD); 95690792Sgshapiro } 95790792Sgshapiro else 95890792Sgshapiro { 95990792Sgshapiro ADDSARG(); 96090792Sgshapiro } 96190792Sgshapiro break; 96290792Sgshapiro case 'e': 96390792Sgshapiro case 'E': 96490792Sgshapiro case 'f': 96590792Sgshapiro case 'g': 96690792Sgshapiro case 'G': 96790792Sgshapiro ADDTYPE(T_DOUBLE); 96890792Sgshapiro break; 96990792Sgshapiro case 'n': 97090792Sgshapiro if (flags & QUADINT) 97190792Sgshapiro ADDTYPE(TP_QUAD); 97290792Sgshapiro else if (flags & LONGINT) 97390792Sgshapiro ADDTYPE(TP_LONG); 97490792Sgshapiro else if (flags & SHORTINT) 97590792Sgshapiro ADDTYPE(TP_SHORT); 97690792Sgshapiro else 97790792Sgshapiro ADDTYPE(TP_INT); 97890792Sgshapiro continue; /* no output */ 97990792Sgshapiro case 'O': 98090792Sgshapiro flags |= LONGINT; 98190792Sgshapiro /*FALLTHROUGH*/ 98290792Sgshapiro case 'o': 98390792Sgshapiro if (flags & QUADINT) 98490792Sgshapiro ADDTYPE(T_U_QUAD); 98590792Sgshapiro else 98690792Sgshapiro ADDUARG(); 98790792Sgshapiro break; 98890792Sgshapiro case 'p': 98990792Sgshapiro ADDTYPE(TP_VOID); 99090792Sgshapiro break; 99190792Sgshapiro case 's': 99290792Sgshapiro ADDTYPE(TP_CHAR); 99390792Sgshapiro break; 99490792Sgshapiro case 'U': 99590792Sgshapiro flags |= LONGINT; 99690792Sgshapiro /*FALLTHROUGH*/ 99790792Sgshapiro case 'u': 99890792Sgshapiro if (flags & QUADINT) 99990792Sgshapiro ADDTYPE(T_U_QUAD); 100090792Sgshapiro else 100190792Sgshapiro ADDUARG(); 100290792Sgshapiro break; 100390792Sgshapiro case 'X': 100490792Sgshapiro case 'x': 100590792Sgshapiro if (flags & QUADINT) 100690792Sgshapiro ADDTYPE(T_U_QUAD); 100790792Sgshapiro else 100890792Sgshapiro ADDUARG(); 100990792Sgshapiro break; 101090792Sgshapiro default: /* "%?" prints ?, unless ? is NUL */ 101190792Sgshapiro if (ch == '\0') 101290792Sgshapiro goto done; 101390792Sgshapiro break; 101490792Sgshapiro } 101590792Sgshapiro } 101690792Sgshapirodone: 101790792Sgshapiro /* Build the argument table. */ 101890792Sgshapiro if (tablemax >= STATIC_ARG_TBL_SIZE) 101990792Sgshapiro { 102090792Sgshapiro *argtable = (va_list *) 102190792Sgshapiro sm_malloc(sizeof(va_list) * (tablemax + 1)); 102290792Sgshapiro } 102390792Sgshapiro 102490792Sgshapiro for (n = 1; n <= tablemax; n++) 102590792Sgshapiro { 102690792Sgshapiro SM_VA_COPY((*argtable)[n], ap); 102790792Sgshapiro switch (typetable [n]) 102890792Sgshapiro { 102990792Sgshapiro case T_UNUSED: 103090792Sgshapiro (void) SM_VA_ARG(ap, int); 103190792Sgshapiro break; 103290792Sgshapiro case T_SHORT: 103390792Sgshapiro (void) SM_VA_ARG(ap, int); 103490792Sgshapiro break; 103590792Sgshapiro case T_U_SHORT: 103690792Sgshapiro (void) SM_VA_ARG(ap, int); 103790792Sgshapiro break; 103890792Sgshapiro case TP_SHORT: 103990792Sgshapiro (void) SM_VA_ARG(ap, short *); 104090792Sgshapiro break; 104190792Sgshapiro case T_INT: 104290792Sgshapiro (void) SM_VA_ARG(ap, int); 104390792Sgshapiro break; 104490792Sgshapiro case T_U_INT: 104590792Sgshapiro (void) SM_VA_ARG(ap, unsigned int); 104690792Sgshapiro break; 104790792Sgshapiro case TP_INT: 104890792Sgshapiro (void) SM_VA_ARG(ap, int *); 104990792Sgshapiro break; 105090792Sgshapiro case T_LONG: 105190792Sgshapiro (void) SM_VA_ARG(ap, long); 105290792Sgshapiro break; 105390792Sgshapiro case T_U_LONG: 105490792Sgshapiro (void) SM_VA_ARG(ap, unsigned long); 105590792Sgshapiro break; 105690792Sgshapiro case TP_LONG: 105790792Sgshapiro (void) SM_VA_ARG(ap, long *); 105890792Sgshapiro break; 105990792Sgshapiro case T_QUAD: 106090792Sgshapiro (void) SM_VA_ARG(ap, LONGLONG_T); 106190792Sgshapiro break; 106290792Sgshapiro case T_U_QUAD: 106390792Sgshapiro (void) SM_VA_ARG(ap, ULONGLONG_T); 106490792Sgshapiro break; 106590792Sgshapiro case TP_QUAD: 106690792Sgshapiro (void) SM_VA_ARG(ap, LONGLONG_T *); 106790792Sgshapiro break; 106890792Sgshapiro case T_DOUBLE: 106990792Sgshapiro (void) SM_VA_ARG(ap, double); 107090792Sgshapiro break; 107190792Sgshapiro case TP_CHAR: 107290792Sgshapiro (void) SM_VA_ARG(ap, char *); 107390792Sgshapiro break; 107490792Sgshapiro case TP_VOID: 107590792Sgshapiro (void) SM_VA_ARG(ap, void *); 107690792Sgshapiro break; 107790792Sgshapiro } 107890792Sgshapiro } 107990792Sgshapiro 108090792Sgshapiro if ((typetable != NULL) && (typetable != stattypetable)) 108190792Sgshapiro sm_free(typetable); 108290792Sgshapiro} 108390792Sgshapiro 108490792Sgshapiro/* 108590792Sgshapiro** SM_GROW_TYPE_TABLE -- Increase the size of the type table. 108690792Sgshapiro** 108790792Sgshapiro** Parameters: 108890792Sgshapiro** tabletype -- type of table to grow 108990792Sgshapiro** tablesize -- requested new table size 109090792Sgshapiro** 109190792Sgshapiro** Results: 109290792Sgshapiro** Raises an exception if can't allocate memory. 109390792Sgshapiro*/ 109490792Sgshapiro 109590792Sgshapirostatic void 109690792Sgshapirosm_grow_type_table_x(typetable, tablesize) 109790792Sgshapiro unsigned char **typetable; 109890792Sgshapiro int *tablesize; 109990792Sgshapiro{ 110090792Sgshapiro unsigned char *oldtable = *typetable; 110190792Sgshapiro int newsize = *tablesize * 2; 110290792Sgshapiro 110390792Sgshapiro if (*tablesize == STATIC_ARG_TBL_SIZE) 110490792Sgshapiro { 110590792Sgshapiro *typetable = (unsigned char *) sm_malloc_x(sizeof(unsigned char) 110690792Sgshapiro * newsize); 110790792Sgshapiro (void) memmove(*typetable, oldtable, *tablesize); 110890792Sgshapiro } 110990792Sgshapiro else 111090792Sgshapiro { 111190792Sgshapiro *typetable = (unsigned char *) sm_realloc_x(typetable, 111290792Sgshapiro sizeof(unsigned char) * newsize); 111390792Sgshapiro } 111490792Sgshapiro (void) memset(&typetable [*tablesize], T_UNUSED, 111590792Sgshapiro (newsize - *tablesize)); 111690792Sgshapiro 111790792Sgshapiro *tablesize = newsize; 111890792Sgshapiro} 1119