140266059SGregory Neil Shapiro /*
25dd76dd0SGregory Neil Shapiro * Copyright (c) 2000-2001, 2004 Proofpoint, Inc. and its suppliers.
340266059SGregory Neil Shapiro * All rights reserved.
440266059SGregory Neil Shapiro * Copyright (c) 1990
540266059SGregory Neil Shapiro * The Regents of the University of California. All rights reserved.
640266059SGregory Neil Shapiro *
740266059SGregory Neil Shapiro * This code is derived from software contributed to Berkeley by
840266059SGregory Neil Shapiro * Chris Torek.
940266059SGregory Neil Shapiro *
1040266059SGregory Neil Shapiro * By using this file, you agree to the terms and conditions set
1140266059SGregory Neil Shapiro * forth in the LICENSE file which can be found at the top level of
1240266059SGregory Neil Shapiro * the sendmail distribution.
1340266059SGregory Neil Shapiro */
1440266059SGregory Neil Shapiro
1540266059SGregory Neil Shapiro #include <sm/gen.h>
164313cc83SGregory Neil Shapiro SM_IDSTR(id, "@(#)$Id: vfprintf.c,v 1.55 2013-11-22 20:51:44 ca Exp $")
1740266059SGregory Neil Shapiro
1840266059SGregory Neil Shapiro /*
1940266059SGregory Neil Shapiro ** Overall:
2040266059SGregory Neil Shapiro ** Actual printing innards.
2140266059SGregory Neil Shapiro ** This code is large and complicated...
2240266059SGregory Neil Shapiro */
2340266059SGregory Neil Shapiro
2440266059SGregory Neil Shapiro #include <sys/types.h>
2540266059SGregory Neil Shapiro #include <stdlib.h>
2640266059SGregory Neil Shapiro #include <string.h>
2740266059SGregory Neil Shapiro #include <errno.h>
2840266059SGregory Neil Shapiro #include <sm/config.h>
2940266059SGregory Neil Shapiro #include <sm/varargs.h>
3040266059SGregory Neil Shapiro #include <sm/io.h>
3140266059SGregory Neil Shapiro #include <sm/heap.h>
3240266059SGregory Neil Shapiro #include <sm/conf.h>
3340266059SGregory Neil Shapiro #include "local.h"
3440266059SGregory Neil Shapiro #include "fvwrite.h"
3540266059SGregory Neil Shapiro
36b6bacd31SGregory Neil Shapiro static int sm_bprintf __P((SM_FILE_T *, const char *, va_list));
3740266059SGregory Neil Shapiro static void sm_find_arguments __P((const char *, va_list , va_list **));
3840266059SGregory Neil Shapiro static void sm_grow_type_table_x __P((unsigned char **, int *));
3940266059SGregory Neil Shapiro static int sm_print __P((SM_FILE_T *, int, struct sm_uio *));
4040266059SGregory Neil Shapiro
4140266059SGregory Neil Shapiro /*
4240266059SGregory Neil Shapiro ** SM_PRINT -- print/flush to the file
4340266059SGregory Neil Shapiro **
4440266059SGregory Neil Shapiro ** Flush out all the vectors defined by the given uio,
4540266059SGregory Neil Shapiro ** then reset it so that it can be reused.
4640266059SGregory Neil Shapiro **
4740266059SGregory Neil Shapiro ** Parameters:
4840266059SGregory Neil Shapiro ** fp -- file pointer
4940266059SGregory Neil Shapiro ** timeout -- time to complete operation (milliseconds)
5040266059SGregory Neil Shapiro ** uio -- vector list of memory locations of data for printing
5140266059SGregory Neil Shapiro **
5240266059SGregory Neil Shapiro ** Results:
5340266059SGregory Neil Shapiro ** Success: 0 (zero)
5440266059SGregory Neil Shapiro ** Failure:
5540266059SGregory Neil Shapiro */
5640266059SGregory Neil Shapiro
5740266059SGregory Neil Shapiro static int
sm_print(fp,timeout,uio)5840266059SGregory Neil Shapiro sm_print(fp, timeout, uio)
5940266059SGregory Neil Shapiro SM_FILE_T *fp;
6040266059SGregory Neil Shapiro int timeout;
6140266059SGregory Neil Shapiro register struct sm_uio *uio;
6240266059SGregory Neil Shapiro {
6340266059SGregory Neil Shapiro register int err;
6440266059SGregory Neil Shapiro
6540266059SGregory Neil Shapiro if (uio->uio_resid == 0)
6640266059SGregory Neil Shapiro {
6740266059SGregory Neil Shapiro uio->uio_iovcnt = 0;
6840266059SGregory Neil Shapiro return 0;
6940266059SGregory Neil Shapiro }
7040266059SGregory Neil Shapiro err = sm_fvwrite(fp, timeout, uio);
7140266059SGregory Neil Shapiro uio->uio_resid = 0;
7240266059SGregory Neil Shapiro uio->uio_iovcnt = 0;
7340266059SGregory Neil Shapiro return err;
7440266059SGregory Neil Shapiro }
7540266059SGregory Neil Shapiro
7640266059SGregory Neil Shapiro /*
77*d39bd2c1SGregory Neil Shapiro ** SM_BPRINTF -- allow formatting to an unbuffered file.
7840266059SGregory Neil Shapiro **
7940266059SGregory Neil Shapiro ** Helper function for `fprintf to unbuffered unix file': creates a
8040266059SGregory Neil Shapiro ** temporary buffer (via a "fake" file pointer).
8140266059SGregory Neil Shapiro ** We only work on write-only files; this avoids
8240266059SGregory Neil Shapiro ** worries about ungetc buffers and so forth.
8340266059SGregory Neil Shapiro **
8440266059SGregory Neil Shapiro ** Parameters:
8540266059SGregory Neil Shapiro ** fp -- the file to send the o/p to
8640266059SGregory Neil Shapiro ** fmt -- format instructions for the o/p
87*d39bd2c1SGregory Neil Shapiro ** ap -- vectors of data units used for formatting
8840266059SGregory Neil Shapiro **
8940266059SGregory Neil Shapiro ** Results:
9040266059SGregory Neil Shapiro ** Failure: SM_IO_EOF and errno set
91*d39bd2c1SGregory Neil Shapiro ** Success: number of data units used in the formatting
9240266059SGregory Neil Shapiro **
9340266059SGregory Neil Shapiro ** Side effects:
9440266059SGregory Neil Shapiro ** formatted o/p can be SM_IO_BUFSIZ length maximum
9540266059SGregory Neil Shapiro */
9640266059SGregory Neil Shapiro
9740266059SGregory Neil Shapiro static int
sm_bprintf(fp,fmt,ap)9840266059SGregory Neil Shapiro sm_bprintf(fp, fmt, ap)
99b6bacd31SGregory Neil Shapiro SM_FILE_T *fp;
10040266059SGregory Neil Shapiro const char *fmt;
1012fb4f839SGregory Neil Shapiro va_list ap;
10240266059SGregory Neil Shapiro {
10340266059SGregory Neil Shapiro int ret;
10440266059SGregory Neil Shapiro SM_FILE_T fake;
10540266059SGregory Neil Shapiro unsigned char buf[SM_IO_BUFSIZ];
10640266059SGregory Neil Shapiro extern const char SmFileMagic[];
10740266059SGregory Neil Shapiro
10840266059SGregory Neil Shapiro /* copy the important variables */
10940266059SGregory Neil Shapiro fake.sm_magic = SmFileMagic;
11040266059SGregory Neil Shapiro fake.f_timeout = SM_TIME_FOREVER;
11140266059SGregory Neil Shapiro fake.f_timeoutstate = SM_TIME_BLOCK;
11240266059SGregory Neil Shapiro fake.f_flags = fp->f_flags & ~SMNBF;
11340266059SGregory Neil Shapiro fake.f_file = fp->f_file;
11440266059SGregory Neil Shapiro fake.f_cookie = fp->f_cookie;
11540266059SGregory Neil Shapiro fake.f_write = fp->f_write;
11640266059SGregory Neil Shapiro fake.f_close = NULL;
11740266059SGregory Neil Shapiro fake.f_open = NULL;
11840266059SGregory Neil Shapiro fake.f_read = NULL;
11940266059SGregory Neil Shapiro fake.f_seek = NULL;
12040266059SGregory Neil Shapiro fake.f_setinfo = fake.f_getinfo = NULL;
12140266059SGregory Neil Shapiro fake.f_type = "sm_bprintf:fake";
12240266059SGregory Neil Shapiro
12340266059SGregory Neil Shapiro /* set up the buffer */
12440266059SGregory Neil Shapiro fake.f_bf.smb_base = fake.f_p = buf;
12540266059SGregory Neil Shapiro fake.f_bf.smb_size = fake.f_w = sizeof(buf);
12640266059SGregory Neil Shapiro fake.f_lbfsize = 0; /* not actually used, but Just In Case */
12740266059SGregory Neil Shapiro
12840266059SGregory Neil Shapiro /* do the work, then copy any error status */
12940266059SGregory Neil Shapiro ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap);
13040266059SGregory Neil Shapiro if (ret >= 0 && sm_io_flush(&fake, SM_TIME_FOREVER))
13140266059SGregory Neil Shapiro ret = SM_IO_EOF; /* errno set by sm_io_flush */
13240266059SGregory Neil Shapiro if (fake.f_flags & SMERR)
13340266059SGregory Neil Shapiro fp->f_flags |= SMERR;
13440266059SGregory Neil Shapiro return ret;
13540266059SGregory Neil Shapiro }
13640266059SGregory Neil Shapiro
13740266059SGregory Neil Shapiro
13840266059SGregory Neil Shapiro #define BUF 40
13940266059SGregory Neil Shapiro
14040266059SGregory Neil Shapiro #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
14140266059SGregory Neil Shapiro
14240266059SGregory Neil Shapiro
14340266059SGregory Neil Shapiro /* Macros for converting digits to letters and vice versa */
14440266059SGregory Neil Shapiro #define to_digit(c) ((c) - '0')
14540266059SGregory Neil Shapiro #define is_digit(c) ((unsigned) to_digit(c) <= 9)
14640266059SGregory Neil Shapiro #define to_char(n) ((char) (n) + '0')
14740266059SGregory Neil Shapiro
14840266059SGregory Neil Shapiro /* Flags used during conversion. */
14940266059SGregory Neil Shapiro #define ALT 0x001 /* alternate form */
15040266059SGregory Neil Shapiro #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
15140266059SGregory Neil Shapiro #define LADJUST 0x004 /* left adjustment */
15240266059SGregory Neil Shapiro #define LONGINT 0x010 /* long integer */
15340266059SGregory Neil Shapiro #define QUADINT 0x020 /* quad integer */
15440266059SGregory Neil Shapiro #define SHORTINT 0x040 /* short integer */
15540266059SGregory Neil Shapiro #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
15640266059SGregory Neil Shapiro #define FPT 0x100 /* Floating point number */
15740266059SGregory Neil Shapiro
15840266059SGregory Neil Shapiro /*
159*d39bd2c1SGregory Neil Shapiro ** SM_IO_VFPRINTF -- performs actual formatting for o/p
16040266059SGregory Neil Shapiro **
16140266059SGregory Neil Shapiro ** Parameters:
16240266059SGregory Neil Shapiro ** fp -- file pointer for o/p
16340266059SGregory Neil Shapiro ** timeout -- time to complete the print
164*d39bd2c1SGregory Neil Shapiro ** fmt0 -- formatting directives
165*d39bd2c1SGregory Neil Shapiro ** ap -- vectors with data units for formatting
16640266059SGregory Neil Shapiro **
16740266059SGregory Neil Shapiro ** Results:
16840266059SGregory Neil Shapiro ** Success: number of data units used for formatting
16940266059SGregory Neil Shapiro ** Failure: SM_IO_EOF and sets errno
17040266059SGregory Neil Shapiro */
17140266059SGregory Neil Shapiro
17240266059SGregory Neil Shapiro int
sm_io_vfprintf(fp,timeout,fmt0,ap)17340266059SGregory Neil Shapiro sm_io_vfprintf(fp, timeout, fmt0, ap)
17440266059SGregory Neil Shapiro SM_FILE_T *fp;
17540266059SGregory Neil Shapiro int timeout;
17640266059SGregory Neil Shapiro const char *fmt0;
1772fb4f839SGregory Neil Shapiro va_list ap;
17840266059SGregory Neil Shapiro {
17940266059SGregory Neil Shapiro register char *fmt; /* format string */
18040266059SGregory Neil Shapiro register int ch; /* character from fmt */
18140266059SGregory Neil Shapiro register int n, m, n2; /* handy integers (short term usage) */
18240266059SGregory Neil Shapiro register char *cp; /* handy char pointer (short term usage) */
18340266059SGregory Neil Shapiro register struct sm_iov *iovp;/* for PRINT macro */
18440266059SGregory Neil Shapiro register int flags; /* flags as above */
18540266059SGregory Neil Shapiro int ret; /* return value accumulator */
18640266059SGregory Neil Shapiro int width; /* width from format (%8d), or 0 */
18740266059SGregory Neil Shapiro int prec; /* precision from format (%.3d), or -1 */
18840266059SGregory Neil Shapiro char sign; /* sign prefix (' ', '+', '-', or \0) */
18940266059SGregory Neil Shapiro wchar_t wc;
19040266059SGregory Neil Shapiro ULONGLONG_T _uquad; /* integer arguments %[diouxX] */
19140266059SGregory Neil Shapiro enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
19240266059SGregory Neil Shapiro int dprec; /* a copy of prec if [diouxX], 0 otherwise */
19340266059SGregory Neil Shapiro int realsz; /* field size expanded by dprec */
19440266059SGregory Neil Shapiro int size; /* size of converted field or string */
19540266059SGregory Neil Shapiro char *xdigs="0123456789abcdef"; /* digits for [xX] conversion */
19640266059SGregory Neil Shapiro #define NIOV 8
19740266059SGregory Neil Shapiro struct sm_uio uio; /* output information: summary */
19840266059SGregory Neil Shapiro struct sm_iov iov[NIOV];/* ... and individual io vectors */
19940266059SGregory Neil Shapiro char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
20040266059SGregory Neil Shapiro char ox[2]; /* space for 0x hex-prefix */
20140266059SGregory Neil Shapiro va_list *argtable; /* args, built due to positional arg */
20240266059SGregory Neil Shapiro va_list statargtable[STATIC_ARG_TBL_SIZE];
20340266059SGregory Neil Shapiro int nextarg; /* 1-based argument index */
20440266059SGregory Neil Shapiro va_list orgap; /* original argument pointer */
20540266059SGregory Neil Shapiro
20640266059SGregory Neil Shapiro /*
20740266059SGregory Neil Shapiro ** Choose PADSIZE to trade efficiency vs. size. If larger printf
20840266059SGregory Neil Shapiro ** fields occur frequently, increase PADSIZE and make the initialisers
20940266059SGregory Neil Shapiro ** below longer.
21040266059SGregory Neil Shapiro */
21140266059SGregory Neil Shapiro #define PADSIZE 16 /* pad chunk size */
21240266059SGregory Neil Shapiro static char blanks[PADSIZE] =
21340266059SGregory Neil Shapiro {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
21440266059SGregory Neil Shapiro static char zeroes[PADSIZE] =
21540266059SGregory Neil Shapiro {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
21640266059SGregory Neil Shapiro
21740266059SGregory Neil Shapiro /*
21840266059SGregory Neil Shapiro ** BEWARE, these `goto error' on error, and PAD uses `n'.
21940266059SGregory Neil Shapiro */
22040266059SGregory Neil Shapiro #define PRINT(ptr, len) do { \
22140266059SGregory Neil Shapiro iovp->iov_base = (ptr); \
22240266059SGregory Neil Shapiro iovp->iov_len = (len); \
22340266059SGregory Neil Shapiro uio.uio_resid += (len); \
22440266059SGregory Neil Shapiro iovp++; \
22540266059SGregory Neil Shapiro if (++uio.uio_iovcnt >= NIOV) \
22640266059SGregory Neil Shapiro { \
22740266059SGregory Neil Shapiro if (sm_print(fp, timeout, &uio)) \
22840266059SGregory Neil Shapiro goto error; \
22940266059SGregory Neil Shapiro iovp = iov; \
23040266059SGregory Neil Shapiro } \
23140266059SGregory Neil Shapiro } while (0)
23240266059SGregory Neil Shapiro #define PAD(howmany, with) do \
23340266059SGregory Neil Shapiro { \
23440266059SGregory Neil Shapiro if ((n = (howmany)) > 0) \
23540266059SGregory Neil Shapiro { \
23640266059SGregory Neil Shapiro while (n > PADSIZE) { \
23740266059SGregory Neil Shapiro PRINT(with, PADSIZE); \
23840266059SGregory Neil Shapiro n -= PADSIZE; \
23940266059SGregory Neil Shapiro } \
24040266059SGregory Neil Shapiro PRINT(with, n); \
24140266059SGregory Neil Shapiro } \
24240266059SGregory Neil Shapiro } while (0)
24340266059SGregory Neil Shapiro #define FLUSH() do \
24440266059SGregory Neil Shapiro { \
24540266059SGregory Neil Shapiro if (uio.uio_resid && sm_print(fp, timeout, &uio)) \
24640266059SGregory Neil Shapiro goto error; \
24740266059SGregory Neil Shapiro uio.uio_iovcnt = 0; \
24840266059SGregory Neil Shapiro iovp = iov; \
24940266059SGregory Neil Shapiro } while (0)
25040266059SGregory Neil Shapiro
25140266059SGregory Neil Shapiro /*
25240266059SGregory Neil Shapiro ** To extend shorts properly, we need both signed and unsigned
25340266059SGregory Neil Shapiro ** argument extraction methods.
25440266059SGregory Neil Shapiro */
25540266059SGregory Neil Shapiro #define SARG() \
25640266059SGregory Neil Shapiro (flags&QUADINT ? SM_VA_ARG(ap, LONGLONG_T) : \
25740266059SGregory Neil Shapiro flags&LONGINT ? GETARG(long) : \
25840266059SGregory Neil Shapiro flags&SHORTINT ? (long) (short) GETARG(int) : \
25940266059SGregory Neil Shapiro (long) GETARG(int))
26040266059SGregory Neil Shapiro #define UARG() \
26140266059SGregory Neil Shapiro (flags&QUADINT ? SM_VA_ARG(ap, ULONGLONG_T) : \
26240266059SGregory Neil Shapiro flags&LONGINT ? GETARG(unsigned long) : \
26340266059SGregory Neil Shapiro flags&SHORTINT ? (unsigned long) (unsigned short) GETARG(int) : \
26440266059SGregory Neil Shapiro (unsigned long) GETARG(unsigned int))
26540266059SGregory Neil Shapiro
26640266059SGregory Neil Shapiro /*
26740266059SGregory Neil Shapiro ** Get * arguments, including the form *nn$. Preserve the nextarg
26840266059SGregory Neil Shapiro ** that the argument can be gotten once the type is determined.
26940266059SGregory Neil Shapiro */
27040266059SGregory Neil Shapiro #define GETASTER(val) \
27140266059SGregory Neil Shapiro n2 = 0; \
27240266059SGregory Neil Shapiro cp = fmt; \
27340266059SGregory Neil Shapiro while (is_digit(*cp)) \
27440266059SGregory Neil Shapiro { \
27540266059SGregory Neil Shapiro n2 = 10 * n2 + to_digit(*cp); \
27640266059SGregory Neil Shapiro cp++; \
27740266059SGregory Neil Shapiro } \
27840266059SGregory Neil Shapiro if (*cp == '$') \
27940266059SGregory Neil Shapiro { \
28040266059SGregory Neil Shapiro int hold = nextarg; \
28140266059SGregory Neil Shapiro if (argtable == NULL) \
28240266059SGregory Neil Shapiro { \
28340266059SGregory Neil Shapiro argtable = statargtable; \
28440266059SGregory Neil Shapiro sm_find_arguments(fmt0, orgap, &argtable); \
28540266059SGregory Neil Shapiro } \
28640266059SGregory Neil Shapiro nextarg = n2; \
28740266059SGregory Neil Shapiro val = GETARG(int); \
28840266059SGregory Neil Shapiro nextarg = hold; \
28940266059SGregory Neil Shapiro fmt = ++cp; \
29040266059SGregory Neil Shapiro } \
29140266059SGregory Neil Shapiro else \
29240266059SGregory Neil Shapiro { \
29340266059SGregory Neil Shapiro val = GETARG(int); \
29440266059SGregory Neil Shapiro }
29540266059SGregory Neil Shapiro
29640266059SGregory Neil Shapiro /*
29740266059SGregory Neil Shapiro ** Get the argument indexed by nextarg. If the argument table is
29840266059SGregory Neil Shapiro ** built, use it to get the argument. If its not, get the next
29940266059SGregory Neil Shapiro ** argument (and arguments must be gotten sequentially).
30040266059SGregory Neil Shapiro */
30140266059SGregory Neil Shapiro
30240266059SGregory Neil Shapiro #if SM_VA_STD
30340266059SGregory Neil Shapiro # define GETARG(type) \
30440266059SGregory Neil Shapiro (((argtable != NULL) ? (void) (ap = argtable[nextarg]) : (void) 0), \
30540266059SGregory Neil Shapiro nextarg++, SM_VA_ARG(ap, type))
30640266059SGregory Neil Shapiro #else /* SM_VA_STD */
30740266059SGregory Neil Shapiro # define GETARG(type) \
30840266059SGregory Neil Shapiro ((argtable != NULL) ? (*((type*)(argtable[nextarg++]))) : \
30940266059SGregory Neil Shapiro (nextarg++, SM_VA_ARG(ap, type)))
31040266059SGregory Neil Shapiro #endif /* SM_VA_STD */
31140266059SGregory Neil Shapiro
31240266059SGregory Neil Shapiro /* sorry, fprintf(read_only_file, "") returns SM_IO_EOF, not 0 */
31340266059SGregory Neil Shapiro if (cantwrite(fp))
31440266059SGregory Neil Shapiro {
31540266059SGregory Neil Shapiro errno = EBADF;
31640266059SGregory Neil Shapiro return SM_IO_EOF;
31740266059SGregory Neil Shapiro }
31840266059SGregory Neil Shapiro
31940266059SGregory Neil Shapiro /* optimise fprintf(stderr) (and other unbuffered Unix files) */
32040266059SGregory Neil Shapiro if ((fp->f_flags & (SMNBF|SMWR|SMRW)) == (SMNBF|SMWR) &&
32140266059SGregory Neil Shapiro fp->f_file >= 0)
32240266059SGregory Neil Shapiro return sm_bprintf(fp, fmt0, ap);
32340266059SGregory Neil Shapiro
32440266059SGregory Neil Shapiro fmt = (char *) fmt0;
32540266059SGregory Neil Shapiro argtable = NULL;
32640266059SGregory Neil Shapiro nextarg = 1;
32740266059SGregory Neil Shapiro SM_VA_COPY(orgap, ap);
32840266059SGregory Neil Shapiro uio.uio_iov = iovp = iov;
32940266059SGregory Neil Shapiro uio.uio_resid = 0;
33040266059SGregory Neil Shapiro uio.uio_iovcnt = 0;
33140266059SGregory Neil Shapiro ret = 0;
33240266059SGregory Neil Shapiro
33340266059SGregory Neil Shapiro /* Scan the format for conversions (`%' character). */
33440266059SGregory Neil Shapiro for (;;)
33540266059SGregory Neil Shapiro {
33640266059SGregory Neil Shapiro cp = fmt;
33740266059SGregory Neil Shapiro n = 0;
33840266059SGregory Neil Shapiro while ((wc = *fmt) != '\0')
33940266059SGregory Neil Shapiro {
34040266059SGregory Neil Shapiro if (wc == '%')
34140266059SGregory Neil Shapiro {
34240266059SGregory Neil Shapiro n = 1;
34340266059SGregory Neil Shapiro break;
34440266059SGregory Neil Shapiro }
34540266059SGregory Neil Shapiro fmt++;
34640266059SGregory Neil Shapiro }
34740266059SGregory Neil Shapiro if ((m = fmt - cp) != 0)
34840266059SGregory Neil Shapiro {
34940266059SGregory Neil Shapiro PRINT(cp, m);
35040266059SGregory Neil Shapiro ret += m;
35140266059SGregory Neil Shapiro }
35240266059SGregory Neil Shapiro if (n <= 0)
35340266059SGregory Neil Shapiro goto done;
35440266059SGregory Neil Shapiro fmt++; /* skip over '%' */
35540266059SGregory Neil Shapiro
35640266059SGregory Neil Shapiro flags = 0;
35740266059SGregory Neil Shapiro dprec = 0;
35840266059SGregory Neil Shapiro width = 0;
35940266059SGregory Neil Shapiro prec = -1;
36040266059SGregory Neil Shapiro sign = '\0';
36140266059SGregory Neil Shapiro
36240266059SGregory Neil Shapiro rflag: ch = *fmt++;
36340266059SGregory Neil Shapiro reswitch: switch (ch)
36440266059SGregory Neil Shapiro {
36540266059SGregory Neil Shapiro case ' ':
36640266059SGregory Neil Shapiro
36740266059SGregory Neil Shapiro /*
36840266059SGregory Neil Shapiro ** ``If the space and + flags both appear, the space
36940266059SGregory Neil Shapiro ** flag will be ignored.''
37040266059SGregory Neil Shapiro ** -- ANSI X3J11
37140266059SGregory Neil Shapiro */
37240266059SGregory Neil Shapiro
37340266059SGregory Neil Shapiro if (!sign)
37440266059SGregory Neil Shapiro sign = ' ';
37540266059SGregory Neil Shapiro goto rflag;
37640266059SGregory Neil Shapiro case '#':
37740266059SGregory Neil Shapiro flags |= ALT;
37840266059SGregory Neil Shapiro goto rflag;
37940266059SGregory Neil Shapiro case '*':
38040266059SGregory Neil Shapiro
38140266059SGregory Neil Shapiro /*
38240266059SGregory Neil Shapiro ** ``A negative field width argument is taken as a
38340266059SGregory Neil Shapiro ** - flag followed by a positive field width.''
38440266059SGregory Neil Shapiro ** -- ANSI X3J11
38540266059SGregory Neil Shapiro ** They don't exclude field widths read from args.
38640266059SGregory Neil Shapiro */
38740266059SGregory Neil Shapiro
38840266059SGregory Neil Shapiro GETASTER(width);
38940266059SGregory Neil Shapiro if (width >= 0)
39040266059SGregory Neil Shapiro goto rflag;
39140266059SGregory Neil Shapiro width = -width;
39240266059SGregory Neil Shapiro /* FALLTHROUGH */
39340266059SGregory Neil Shapiro case '-':
39440266059SGregory Neil Shapiro flags |= LADJUST;
39540266059SGregory Neil Shapiro goto rflag;
39640266059SGregory Neil Shapiro case '+':
39740266059SGregory Neil Shapiro sign = '+';
39840266059SGregory Neil Shapiro goto rflag;
39940266059SGregory Neil Shapiro case '.':
40040266059SGregory Neil Shapiro if ((ch = *fmt++) == '*')
40140266059SGregory Neil Shapiro {
40240266059SGregory Neil Shapiro GETASTER(n);
40340266059SGregory Neil Shapiro prec = n < 0 ? -1 : n;
40440266059SGregory Neil Shapiro goto rflag;
40540266059SGregory Neil Shapiro }
40640266059SGregory Neil Shapiro n = 0;
40740266059SGregory Neil Shapiro while (is_digit(ch))
40840266059SGregory Neil Shapiro {
40940266059SGregory Neil Shapiro n = 10 * n + to_digit(ch);
41040266059SGregory Neil Shapiro ch = *fmt++;
41140266059SGregory Neil Shapiro }
41240266059SGregory Neil Shapiro if (ch == '$')
41340266059SGregory Neil Shapiro {
41440266059SGregory Neil Shapiro nextarg = n;
41540266059SGregory Neil Shapiro if (argtable == NULL)
41640266059SGregory Neil Shapiro {
41740266059SGregory Neil Shapiro argtable = statargtable;
41840266059SGregory Neil Shapiro sm_find_arguments(fmt0, orgap,
41940266059SGregory Neil Shapiro &argtable);
42040266059SGregory Neil Shapiro }
42140266059SGregory Neil Shapiro goto rflag;
42240266059SGregory Neil Shapiro }
42340266059SGregory Neil Shapiro prec = n < 0 ? -1 : n;
42440266059SGregory Neil Shapiro goto reswitch;
42540266059SGregory Neil Shapiro case '0':
42640266059SGregory Neil Shapiro
42740266059SGregory Neil Shapiro /*
42840266059SGregory Neil Shapiro ** ``Note that 0 is taken as a flag, not as the
42940266059SGregory Neil Shapiro ** beginning of a field width.''
43040266059SGregory Neil Shapiro ** -- ANSI X3J11
43140266059SGregory Neil Shapiro */
43240266059SGregory Neil Shapiro
43340266059SGregory Neil Shapiro flags |= ZEROPAD;
43440266059SGregory Neil Shapiro goto rflag;
43540266059SGregory Neil Shapiro case '1': case '2': case '3': case '4':
43640266059SGregory Neil Shapiro case '5': case '6': case '7': case '8': case '9':
43740266059SGregory Neil Shapiro n = 0;
43840266059SGregory Neil Shapiro do
43940266059SGregory Neil Shapiro {
44040266059SGregory Neil Shapiro n = 10 * n + to_digit(ch);
44140266059SGregory Neil Shapiro ch = *fmt++;
44240266059SGregory Neil Shapiro } while (is_digit(ch));
44340266059SGregory Neil Shapiro if (ch == '$')
44440266059SGregory Neil Shapiro {
44540266059SGregory Neil Shapiro nextarg = n;
44640266059SGregory Neil Shapiro if (argtable == NULL)
44740266059SGregory Neil Shapiro {
44840266059SGregory Neil Shapiro argtable = statargtable;
44940266059SGregory Neil Shapiro sm_find_arguments(fmt0, orgap,
45040266059SGregory Neil Shapiro &argtable);
45140266059SGregory Neil Shapiro }
45240266059SGregory Neil Shapiro goto rflag;
45340266059SGregory Neil Shapiro }
45440266059SGregory Neil Shapiro width = n;
45540266059SGregory Neil Shapiro goto reswitch;
45640266059SGregory Neil Shapiro case 'h':
45740266059SGregory Neil Shapiro flags |= SHORTINT;
45840266059SGregory Neil Shapiro goto rflag;
45940266059SGregory Neil Shapiro case 'l':
46040266059SGregory Neil Shapiro if (*fmt == 'l')
46140266059SGregory Neil Shapiro {
46240266059SGregory Neil Shapiro fmt++;
46340266059SGregory Neil Shapiro flags |= QUADINT;
46440266059SGregory Neil Shapiro }
46540266059SGregory Neil Shapiro else
46640266059SGregory Neil Shapiro {
46740266059SGregory Neil Shapiro flags |= LONGINT;
46840266059SGregory Neil Shapiro }
46940266059SGregory Neil Shapiro goto rflag;
47040266059SGregory Neil Shapiro case 'q':
47140266059SGregory Neil Shapiro flags |= QUADINT;
47240266059SGregory Neil Shapiro goto rflag;
47340266059SGregory Neil Shapiro case 'c':
47440266059SGregory Neil Shapiro *(cp = buf) = GETARG(int);
47540266059SGregory Neil Shapiro size = 1;
47640266059SGregory Neil Shapiro sign = '\0';
47740266059SGregory Neil Shapiro break;
47840266059SGregory Neil Shapiro case 'D':
47940266059SGregory Neil Shapiro flags |= LONGINT;
48040266059SGregory Neil Shapiro /*FALLTHROUGH*/
48140266059SGregory Neil Shapiro case 'd':
48240266059SGregory Neil Shapiro case 'i':
48340266059SGregory Neil Shapiro _uquad = SARG();
48440266059SGregory Neil Shapiro if ((LONGLONG_T) _uquad < 0)
48540266059SGregory Neil Shapiro {
48640266059SGregory Neil Shapiro _uquad = -(LONGLONG_T) _uquad;
48740266059SGregory Neil Shapiro sign = '-';
48840266059SGregory Neil Shapiro }
48940266059SGregory Neil Shapiro base = DEC;
49040266059SGregory Neil Shapiro goto number;
49140266059SGregory Neil Shapiro case 'e':
49240266059SGregory Neil Shapiro case 'E':
49340266059SGregory Neil Shapiro case 'f':
49440266059SGregory Neil Shapiro case 'g':
49540266059SGregory Neil Shapiro case 'G':
49640266059SGregory Neil Shapiro {
49740266059SGregory Neil Shapiro double val;
49840266059SGregory Neil Shapiro char *p;
49940266059SGregory Neil Shapiro char fmt[16];
50040266059SGregory Neil Shapiro char out[150];
50140266059SGregory Neil Shapiro size_t len;
50240266059SGregory Neil Shapiro
50340266059SGregory Neil Shapiro /*
50440266059SGregory Neil Shapiro ** This code implements floating point output
50540266059SGregory Neil Shapiro ** in the most portable manner possible,
50640266059SGregory Neil Shapiro ** relying only on 'sprintf' as defined by
50740266059SGregory Neil Shapiro ** the 1989 ANSI C standard.
50840266059SGregory Neil Shapiro ** We silently cap width and precision
50940266059SGregory Neil Shapiro ** at 120, to avoid buffer overflow.
51040266059SGregory Neil Shapiro */
51140266059SGregory Neil Shapiro
51240266059SGregory Neil Shapiro val = GETARG(double);
51340266059SGregory Neil Shapiro
51440266059SGregory Neil Shapiro p = fmt;
51540266059SGregory Neil Shapiro *p++ = '%';
51640266059SGregory Neil Shapiro if (sign)
51740266059SGregory Neil Shapiro *p++ = sign;
51840266059SGregory Neil Shapiro if (flags & ALT)
51940266059SGregory Neil Shapiro *p++ = '#';
52040266059SGregory Neil Shapiro if (flags & LADJUST)
52140266059SGregory Neil Shapiro *p++ = '-';
52240266059SGregory Neil Shapiro if (flags & ZEROPAD)
52340266059SGregory Neil Shapiro *p++ = '0';
52440266059SGregory Neil Shapiro *p++ = '*';
52540266059SGregory Neil Shapiro if (prec >= 0)
52640266059SGregory Neil Shapiro {
52740266059SGregory Neil Shapiro *p++ = '.';
52840266059SGregory Neil Shapiro *p++ = '*';
52940266059SGregory Neil Shapiro }
53040266059SGregory Neil Shapiro *p++ = ch;
53140266059SGregory Neil Shapiro *p = '\0';
53240266059SGregory Neil Shapiro
53340266059SGregory Neil Shapiro if (width > 120)
53440266059SGregory Neil Shapiro width = 120;
53540266059SGregory Neil Shapiro if (prec > 120)
53640266059SGregory Neil Shapiro prec = 120;
53740266059SGregory Neil Shapiro if (prec >= 0)
5384e4196cbSGregory Neil Shapiro #if HASSNPRINTF
5394e4196cbSGregory Neil Shapiro snprintf(out, sizeof(out), fmt, width,
5404e4196cbSGregory Neil Shapiro prec, val);
5415b0945b5SGregory Neil Shapiro #else
54240266059SGregory Neil Shapiro sprintf(out, fmt, width, prec, val);
5435b0945b5SGregory Neil Shapiro #endif
54440266059SGregory Neil Shapiro else
5454e4196cbSGregory Neil Shapiro #if HASSNPRINTF
5464e4196cbSGregory Neil Shapiro snprintf(out, sizeof(out), fmt, width,
5474e4196cbSGregory Neil Shapiro val);
5485b0945b5SGregory Neil Shapiro #else
54940266059SGregory Neil Shapiro sprintf(out, fmt, width, val);
5505b0945b5SGregory Neil Shapiro #endif
55140266059SGregory Neil Shapiro len = strlen(out);
55240266059SGregory Neil Shapiro PRINT(out, len);
55340266059SGregory Neil Shapiro FLUSH();
55440266059SGregory Neil Shapiro continue;
55540266059SGregory Neil Shapiro }
55640266059SGregory Neil Shapiro case 'n':
55740266059SGregory Neil Shapiro if (flags & QUADINT)
55840266059SGregory Neil Shapiro *GETARG(LONGLONG_T *) = ret;
55940266059SGregory Neil Shapiro else if (flags & LONGINT)
56040266059SGregory Neil Shapiro *GETARG(long *) = ret;
56140266059SGregory Neil Shapiro else if (flags & SHORTINT)
56240266059SGregory Neil Shapiro *GETARG(short *) = ret;
56340266059SGregory Neil Shapiro else
56440266059SGregory Neil Shapiro *GETARG(int *) = ret;
56540266059SGregory Neil Shapiro continue; /* no output */
56640266059SGregory Neil Shapiro case 'O':
56740266059SGregory Neil Shapiro flags |= LONGINT;
56840266059SGregory Neil Shapiro /*FALLTHROUGH*/
56940266059SGregory Neil Shapiro case 'o':
57040266059SGregory Neil Shapiro _uquad = UARG();
57140266059SGregory Neil Shapiro base = OCT;
57240266059SGregory Neil Shapiro goto nosign;
57340266059SGregory Neil Shapiro case 'p':
57440266059SGregory Neil Shapiro
57540266059SGregory Neil Shapiro /*
57640266059SGregory Neil Shapiro ** ``The argument shall be a pointer to void. The
57740266059SGregory Neil Shapiro ** value of the pointer is converted to a sequence
57840266059SGregory Neil Shapiro ** of printable characters, in an implementation-
57940266059SGregory Neil Shapiro ** defined manner.''
58040266059SGregory Neil Shapiro ** -- ANSI X3J11
58140266059SGregory Neil Shapiro */
58240266059SGregory Neil Shapiro
58340266059SGregory Neil Shapiro /* NOSTRICT */
58440266059SGregory Neil Shapiro {
58540266059SGregory Neil Shapiro union
58640266059SGregory Neil Shapiro {
58740266059SGregory Neil Shapiro void *p;
58840266059SGregory Neil Shapiro ULONGLONG_T ll;
58940266059SGregory Neil Shapiro unsigned long l;
59040266059SGregory Neil Shapiro unsigned i;
59140266059SGregory Neil Shapiro } u;
59240266059SGregory Neil Shapiro u.p = GETARG(void *);
59340266059SGregory Neil Shapiro if (sizeof(void *) == sizeof(ULONGLONG_T))
59440266059SGregory Neil Shapiro _uquad = u.ll;
59540266059SGregory Neil Shapiro else if (sizeof(void *) == sizeof(long))
59640266059SGregory Neil Shapiro _uquad = u.l;
59740266059SGregory Neil Shapiro else
59840266059SGregory Neil Shapiro _uquad = u.i;
59940266059SGregory Neil Shapiro }
60040266059SGregory Neil Shapiro base = HEX;
60140266059SGregory Neil Shapiro xdigs = "0123456789abcdef";
60240266059SGregory Neil Shapiro flags |= HEXPREFIX;
60340266059SGregory Neil Shapiro ch = 'x';
60440266059SGregory Neil Shapiro goto nosign;
60540266059SGregory Neil Shapiro case 's':
60640266059SGregory Neil Shapiro if ((cp = GETARG(char *)) == NULL)
60740266059SGregory Neil Shapiro cp = "(null)";
60840266059SGregory Neil Shapiro if (prec >= 0)
60940266059SGregory Neil Shapiro {
61040266059SGregory Neil Shapiro /*
61140266059SGregory Neil Shapiro ** can't use strlen; can only look for the
61240266059SGregory Neil Shapiro ** NUL in the first `prec' characters, and
61340266059SGregory Neil Shapiro ** strlen() will go further.
61440266059SGregory Neil Shapiro */
61540266059SGregory Neil Shapiro
61640266059SGregory Neil Shapiro char *p = memchr(cp, 0, prec);
61740266059SGregory Neil Shapiro
61840266059SGregory Neil Shapiro if (p != NULL)
61940266059SGregory Neil Shapiro {
62040266059SGregory Neil Shapiro size = p - cp;
62140266059SGregory Neil Shapiro if (size > prec)
62240266059SGregory Neil Shapiro size = prec;
62340266059SGregory Neil Shapiro }
62440266059SGregory Neil Shapiro else
62540266059SGregory Neil Shapiro size = prec;
62640266059SGregory Neil Shapiro }
62740266059SGregory Neil Shapiro else
62840266059SGregory Neil Shapiro size = strlen(cp);
62940266059SGregory Neil Shapiro sign = '\0';
63040266059SGregory Neil Shapiro break;
63140266059SGregory Neil Shapiro case 'U':
63240266059SGregory Neil Shapiro flags |= LONGINT;
63340266059SGregory Neil Shapiro /*FALLTHROUGH*/
63440266059SGregory Neil Shapiro case 'u':
63540266059SGregory Neil Shapiro _uquad = UARG();
63640266059SGregory Neil Shapiro base = DEC;
63740266059SGregory Neil Shapiro goto nosign;
63840266059SGregory Neil Shapiro case 'X':
63940266059SGregory Neil Shapiro xdigs = "0123456789ABCDEF";
64040266059SGregory Neil Shapiro goto hex;
64140266059SGregory Neil Shapiro case 'x':
64240266059SGregory Neil Shapiro xdigs = "0123456789abcdef";
64340266059SGregory Neil Shapiro hex: _uquad = UARG();
64440266059SGregory Neil Shapiro base = HEX;
64540266059SGregory Neil Shapiro /* leading 0x/X only if non-zero */
64640266059SGregory Neil Shapiro if (flags & ALT && _uquad != 0)
64740266059SGregory Neil Shapiro flags |= HEXPREFIX;
64840266059SGregory Neil Shapiro
64940266059SGregory Neil Shapiro /* unsigned conversions */
65040266059SGregory Neil Shapiro nosign: sign = '\0';
65140266059SGregory Neil Shapiro
65240266059SGregory Neil Shapiro /*
65340266059SGregory Neil Shapiro ** ``... diouXx conversions ... if a precision is
65440266059SGregory Neil Shapiro ** specified, the 0 flag will be ignored.''
65540266059SGregory Neil Shapiro ** -- ANSI X3J11
65640266059SGregory Neil Shapiro */
65740266059SGregory Neil Shapiro
65840266059SGregory Neil Shapiro number: if ((dprec = prec) >= 0)
65940266059SGregory Neil Shapiro flags &= ~ZEROPAD;
66040266059SGregory Neil Shapiro
66140266059SGregory Neil Shapiro /*
66240266059SGregory Neil Shapiro ** ``The result of converting a zero value with an
66340266059SGregory Neil Shapiro ** explicit precision of zero is no characters.''
66440266059SGregory Neil Shapiro ** -- ANSI X3J11
66540266059SGregory Neil Shapiro */
66640266059SGregory Neil Shapiro
66740266059SGregory Neil Shapiro cp = buf + BUF;
66840266059SGregory Neil Shapiro if (_uquad != 0 || prec != 0)
66940266059SGregory Neil Shapiro {
67040266059SGregory Neil Shapiro /*
67140266059SGregory Neil Shapiro ** Unsigned mod is hard, and unsigned mod
67240266059SGregory Neil Shapiro ** by a constant is easier than that by
67340266059SGregory Neil Shapiro ** a variable; hence this switch.
67440266059SGregory Neil Shapiro */
67540266059SGregory Neil Shapiro
67640266059SGregory Neil Shapiro switch (base)
67740266059SGregory Neil Shapiro {
67840266059SGregory Neil Shapiro case OCT:
67940266059SGregory Neil Shapiro do
68040266059SGregory Neil Shapiro {
68140266059SGregory Neil Shapiro *--cp = to_char(_uquad & 7);
68240266059SGregory Neil Shapiro _uquad >>= 3;
68340266059SGregory Neil Shapiro } while (_uquad);
68440266059SGregory Neil Shapiro /* handle octal leading 0 */
68540266059SGregory Neil Shapiro if (flags & ALT && *cp != '0')
68640266059SGregory Neil Shapiro *--cp = '0';
68740266059SGregory Neil Shapiro break;
68840266059SGregory Neil Shapiro
68940266059SGregory Neil Shapiro case DEC:
69040266059SGregory Neil Shapiro /* many numbers are 1 digit */
69140266059SGregory Neil Shapiro while (_uquad >= 10)
69240266059SGregory Neil Shapiro {
69340266059SGregory Neil Shapiro *--cp = to_char(_uquad % 10);
69440266059SGregory Neil Shapiro _uquad /= 10;
69540266059SGregory Neil Shapiro }
69640266059SGregory Neil Shapiro *--cp = to_char(_uquad);
69740266059SGregory Neil Shapiro break;
69840266059SGregory Neil Shapiro
69940266059SGregory Neil Shapiro case HEX:
70040266059SGregory Neil Shapiro do
70140266059SGregory Neil Shapiro {
70240266059SGregory Neil Shapiro *--cp = xdigs[_uquad & 15];
70340266059SGregory Neil Shapiro _uquad >>= 4;
70440266059SGregory Neil Shapiro } while (_uquad);
70540266059SGregory Neil Shapiro break;
70640266059SGregory Neil Shapiro
70740266059SGregory Neil Shapiro default:
70840266059SGregory Neil Shapiro cp = "bug in sm_io_vfprintf: bad base";
70940266059SGregory Neil Shapiro size = strlen(cp);
71040266059SGregory Neil Shapiro goto skipsize;
71140266059SGregory Neil Shapiro }
71240266059SGregory Neil Shapiro }
71340266059SGregory Neil Shapiro size = buf + BUF - cp;
71440266059SGregory Neil Shapiro skipsize:
71540266059SGregory Neil Shapiro break;
71640266059SGregory Neil Shapiro default: /* "%?" prints ?, unless ? is NUL */
71740266059SGregory Neil Shapiro if (ch == '\0')
71840266059SGregory Neil Shapiro goto done;
71940266059SGregory Neil Shapiro /* pretend it was %c with argument ch */
72040266059SGregory Neil Shapiro cp = buf;
72140266059SGregory Neil Shapiro *cp = ch;
72240266059SGregory Neil Shapiro size = 1;
72340266059SGregory Neil Shapiro sign = '\0';
72440266059SGregory Neil Shapiro break;
72540266059SGregory Neil Shapiro }
72640266059SGregory Neil Shapiro
72740266059SGregory Neil Shapiro /*
72840266059SGregory Neil Shapiro ** All reasonable formats wind up here. At this point, `cp'
72940266059SGregory Neil Shapiro ** points to a string which (if not flags&LADJUST) should be
73040266059SGregory Neil Shapiro ** padded out to `width' places. If flags&ZEROPAD, it should
73140266059SGregory Neil Shapiro ** first be prefixed by any sign or other prefix; otherwise,
73240266059SGregory Neil Shapiro ** it should be blank padded before the prefix is emitted.
73340266059SGregory Neil Shapiro ** After any left-hand padding and prefixing, emit zeroes
73440266059SGregory Neil Shapiro ** required by a decimal [diouxX] precision, then print the
73540266059SGregory Neil Shapiro ** string proper, then emit zeroes required by any leftover
73640266059SGregory Neil Shapiro ** floating precision; finally, if LADJUST, pad with blanks.
73740266059SGregory Neil Shapiro **
73840266059SGregory Neil Shapiro ** Compute actual size, so we know how much to pad.
73940266059SGregory Neil Shapiro ** size excludes decimal prec; realsz includes it.
74040266059SGregory Neil Shapiro */
74140266059SGregory Neil Shapiro
74240266059SGregory Neil Shapiro realsz = dprec > size ? dprec : size;
74340266059SGregory Neil Shapiro if (sign)
74440266059SGregory Neil Shapiro realsz++;
74540266059SGregory Neil Shapiro else if (flags & HEXPREFIX)
74640266059SGregory Neil Shapiro realsz+= 2;
74740266059SGregory Neil Shapiro
74840266059SGregory Neil Shapiro /* right-adjusting blank padding */
74940266059SGregory Neil Shapiro if ((flags & (LADJUST|ZEROPAD)) == 0)
75040266059SGregory Neil Shapiro PAD(width - realsz, blanks);
75140266059SGregory Neil Shapiro
75240266059SGregory Neil Shapiro /* prefix */
75340266059SGregory Neil Shapiro if (sign)
75440266059SGregory Neil Shapiro {
75540266059SGregory Neil Shapiro PRINT(&sign, 1);
75640266059SGregory Neil Shapiro }
75740266059SGregory Neil Shapiro else if (flags & HEXPREFIX)
75840266059SGregory Neil Shapiro {
75940266059SGregory Neil Shapiro ox[0] = '0';
76040266059SGregory Neil Shapiro ox[1] = ch;
76140266059SGregory Neil Shapiro PRINT(ox, 2);
76240266059SGregory Neil Shapiro }
76340266059SGregory Neil Shapiro
76440266059SGregory Neil Shapiro /* right-adjusting zero padding */
76540266059SGregory Neil Shapiro if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
76640266059SGregory Neil Shapiro PAD(width - realsz, zeroes);
76740266059SGregory Neil Shapiro
76840266059SGregory Neil Shapiro /* leading zeroes from decimal precision */
76940266059SGregory Neil Shapiro PAD(dprec - size, zeroes);
77040266059SGregory Neil Shapiro
77140266059SGregory Neil Shapiro /* the string or number proper */
77240266059SGregory Neil Shapiro PRINT(cp, size);
77340266059SGregory Neil Shapiro /* left-adjusting padding (always blank) */
77440266059SGregory Neil Shapiro if (flags & LADJUST)
77540266059SGregory Neil Shapiro PAD(width - realsz, blanks);
77640266059SGregory Neil Shapiro
77740266059SGregory Neil Shapiro /* finally, adjust ret */
77840266059SGregory Neil Shapiro ret += width > realsz ? width : realsz;
77940266059SGregory Neil Shapiro
78040266059SGregory Neil Shapiro FLUSH(); /* copy out the I/O vectors */
78140266059SGregory Neil Shapiro }
78240266059SGregory Neil Shapiro done:
78340266059SGregory Neil Shapiro FLUSH();
78440266059SGregory Neil Shapiro error:
7855b0945b5SGregory Neil Shapiro SM_VA_END_COPY(orgap);
78640266059SGregory Neil Shapiro if ((argtable != NULL) && (argtable != statargtable))
78740266059SGregory Neil Shapiro sm_free(argtable);
78840266059SGregory Neil Shapiro return sm_error(fp) ? SM_IO_EOF : ret;
78940266059SGregory Neil Shapiro /* NOTREACHED */
79040266059SGregory Neil Shapiro }
79140266059SGregory Neil Shapiro
79240266059SGregory Neil Shapiro /* Type ids for argument type table. */
79340266059SGregory Neil Shapiro #define T_UNUSED 0
79440266059SGregory Neil Shapiro #define T_SHORT 1
79540266059SGregory Neil Shapiro #define T_U_SHORT 2
79640266059SGregory Neil Shapiro #define TP_SHORT 3
79740266059SGregory Neil Shapiro #define T_INT 4
79840266059SGregory Neil Shapiro #define T_U_INT 5
79940266059SGregory Neil Shapiro #define TP_INT 6
80040266059SGregory Neil Shapiro #define T_LONG 7
80140266059SGregory Neil Shapiro #define T_U_LONG 8
80240266059SGregory Neil Shapiro #define TP_LONG 9
80340266059SGregory Neil Shapiro #define T_QUAD 10
80440266059SGregory Neil Shapiro #define T_U_QUAD 11
80540266059SGregory Neil Shapiro #define TP_QUAD 12
80640266059SGregory Neil Shapiro #define T_DOUBLE 13
80740266059SGregory Neil Shapiro #define TP_CHAR 15
80840266059SGregory Neil Shapiro #define TP_VOID 16
80940266059SGregory Neil Shapiro
81040266059SGregory Neil Shapiro /*
81140266059SGregory Neil Shapiro ** SM_FIND_ARGUMENTS -- find all args when a positional parameter is found.
81240266059SGregory Neil Shapiro **
81340266059SGregory Neil Shapiro ** Find all arguments when a positional parameter is encountered. Returns a
81440266059SGregory Neil Shapiro ** table, indexed by argument number, of pointers to each arguments. The
81540266059SGregory Neil Shapiro ** initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
81640266059SGregory Neil Shapiro ** It will be replaced with a malloc-ed one if it overflows.
81740266059SGregory Neil Shapiro **
81840266059SGregory Neil Shapiro ** Parameters:
819*d39bd2c1SGregory Neil Shapiro ** fmt0 -- formatting directives
820*d39bd2c1SGregory Neil Shapiro ** ap -- vector list of data unit for formatting consumption
82140266059SGregory Neil Shapiro ** argtable -- an indexable table (returned) of 'ap'
82240266059SGregory Neil Shapiro **
82340266059SGregory Neil Shapiro ** Results:
82440266059SGregory Neil Shapiro ** none.
82540266059SGregory Neil Shapiro */
82640266059SGregory Neil Shapiro
82740266059SGregory Neil Shapiro static void
sm_find_arguments(fmt0,ap,argtable)82840266059SGregory Neil Shapiro sm_find_arguments(fmt0, ap, argtable)
82940266059SGregory Neil Shapiro const char *fmt0;
8302fb4f839SGregory Neil Shapiro va_list ap;
83140266059SGregory Neil Shapiro va_list **argtable;
83240266059SGregory Neil Shapiro {
83340266059SGregory Neil Shapiro register char *fmt; /* format string */
83440266059SGregory Neil Shapiro register int ch; /* character from fmt */
83540266059SGregory Neil Shapiro register int n, n2; /* handy integer (short term usage) */
83640266059SGregory Neil Shapiro register char *cp; /* handy char pointer (short term usage) */
83740266059SGregory Neil Shapiro register int flags; /* flags as above */
83840266059SGregory Neil Shapiro unsigned char *typetable; /* table of types */
83940266059SGregory Neil Shapiro unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
84040266059SGregory Neil Shapiro int tablesize; /* current size of type table */
84140266059SGregory Neil Shapiro int tablemax; /* largest used index in table */
84240266059SGregory Neil Shapiro int nextarg; /* 1-based argument index */
84340266059SGregory Neil Shapiro
84440266059SGregory Neil Shapiro /* Add an argument type to the table, expanding if necessary. */
84540266059SGregory Neil Shapiro #define ADDTYPE(type) \
84640266059SGregory Neil Shapiro ((nextarg >= tablesize) ? \
84740266059SGregory Neil Shapiro (sm_grow_type_table_x(&typetable, &tablesize), 0) : 0, \
84840266059SGregory Neil Shapiro typetable[nextarg++] = type, \
84940266059SGregory Neil Shapiro (nextarg > tablemax) ? tablemax = nextarg : 0)
85040266059SGregory Neil Shapiro
85140266059SGregory Neil Shapiro #define ADDSARG() \
85240266059SGregory Neil Shapiro ((flags & LONGINT) ? ADDTYPE(T_LONG) : \
85340266059SGregory Neil Shapiro ((flags & SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))
85440266059SGregory Neil Shapiro
85540266059SGregory Neil Shapiro #define ADDUARG() \
85640266059SGregory Neil Shapiro ((flags & LONGINT) ? ADDTYPE(T_U_LONG) : \
85740266059SGregory Neil Shapiro ((flags & SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))
85840266059SGregory Neil Shapiro
85940266059SGregory Neil Shapiro /* Add * arguments to the type array. */
86040266059SGregory Neil Shapiro #define ADDASTER() \
86140266059SGregory Neil Shapiro n2 = 0; \
86240266059SGregory Neil Shapiro cp = fmt; \
86340266059SGregory Neil Shapiro while (is_digit(*cp)) \
86440266059SGregory Neil Shapiro { \
86540266059SGregory Neil Shapiro n2 = 10 * n2 + to_digit(*cp); \
86640266059SGregory Neil Shapiro cp++; \
86740266059SGregory Neil Shapiro } \
86840266059SGregory Neil Shapiro if (*cp == '$') \
86940266059SGregory Neil Shapiro { \
87040266059SGregory Neil Shapiro int hold = nextarg; \
87140266059SGregory Neil Shapiro nextarg = n2; \
87240266059SGregory Neil Shapiro ADDTYPE (T_INT); \
87340266059SGregory Neil Shapiro nextarg = hold; \
87440266059SGregory Neil Shapiro fmt = ++cp; \
87540266059SGregory Neil Shapiro } \
87640266059SGregory Neil Shapiro else \
87740266059SGregory Neil Shapiro { \
87840266059SGregory Neil Shapiro ADDTYPE (T_INT); \
87940266059SGregory Neil Shapiro }
88040266059SGregory Neil Shapiro fmt = (char *) fmt0;
88140266059SGregory Neil Shapiro typetable = stattypetable;
88240266059SGregory Neil Shapiro tablesize = STATIC_ARG_TBL_SIZE;
88340266059SGregory Neil Shapiro tablemax = 0;
88440266059SGregory Neil Shapiro nextarg = 1;
88540266059SGregory Neil Shapiro (void) memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
88640266059SGregory Neil Shapiro
88740266059SGregory Neil Shapiro /* Scan the format for conversions (`%' character). */
88840266059SGregory Neil Shapiro for (;;)
88940266059SGregory Neil Shapiro {
89040266059SGregory Neil Shapiro for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
89140266059SGregory Neil Shapiro /* void */;
89240266059SGregory Neil Shapiro if (ch == '\0')
89340266059SGregory Neil Shapiro goto done;
89440266059SGregory Neil Shapiro fmt++; /* skip over '%' */
89540266059SGregory Neil Shapiro
89640266059SGregory Neil Shapiro flags = 0;
89740266059SGregory Neil Shapiro
89840266059SGregory Neil Shapiro rflag: ch = *fmt++;
89940266059SGregory Neil Shapiro reswitch: switch (ch)
90040266059SGregory Neil Shapiro {
90140266059SGregory Neil Shapiro case ' ':
90240266059SGregory Neil Shapiro case '#':
90340266059SGregory Neil Shapiro goto rflag;
90440266059SGregory Neil Shapiro case '*':
90540266059SGregory Neil Shapiro ADDASTER();
90640266059SGregory Neil Shapiro goto rflag;
90740266059SGregory Neil Shapiro case '-':
90840266059SGregory Neil Shapiro case '+':
90940266059SGregory Neil Shapiro goto rflag;
91040266059SGregory Neil Shapiro case '.':
91140266059SGregory Neil Shapiro if ((ch = *fmt++) == '*')
91240266059SGregory Neil Shapiro {
91340266059SGregory Neil Shapiro ADDASTER();
91440266059SGregory Neil Shapiro goto rflag;
91540266059SGregory Neil Shapiro }
91640266059SGregory Neil Shapiro while (is_digit(ch))
91740266059SGregory Neil Shapiro {
91840266059SGregory Neil Shapiro ch = *fmt++;
91940266059SGregory Neil Shapiro }
92040266059SGregory Neil Shapiro goto reswitch;
92140266059SGregory Neil Shapiro case '0':
92240266059SGregory Neil Shapiro goto rflag;
92340266059SGregory Neil Shapiro case '1': case '2': case '3': case '4':
92440266059SGregory Neil Shapiro case '5': case '6': case '7': case '8': case '9':
92540266059SGregory Neil Shapiro n = 0;
92640266059SGregory Neil Shapiro do
92740266059SGregory Neil Shapiro {
92840266059SGregory Neil Shapiro n = 10 * n + to_digit(ch);
92940266059SGregory Neil Shapiro ch = *fmt++;
93040266059SGregory Neil Shapiro } while (is_digit(ch));
93140266059SGregory Neil Shapiro if (ch == '$')
93240266059SGregory Neil Shapiro {
93340266059SGregory Neil Shapiro nextarg = n;
93440266059SGregory Neil Shapiro goto rflag;
93540266059SGregory Neil Shapiro }
93640266059SGregory Neil Shapiro goto reswitch;
93740266059SGregory Neil Shapiro case 'h':
93840266059SGregory Neil Shapiro flags |= SHORTINT;
93940266059SGregory Neil Shapiro goto rflag;
94040266059SGregory Neil Shapiro case 'l':
94140266059SGregory Neil Shapiro flags |= LONGINT;
94240266059SGregory Neil Shapiro goto rflag;
94340266059SGregory Neil Shapiro case 'q':
94440266059SGregory Neil Shapiro flags |= QUADINT;
94540266059SGregory Neil Shapiro goto rflag;
94640266059SGregory Neil Shapiro case 'c':
94740266059SGregory Neil Shapiro ADDTYPE(T_INT);
94840266059SGregory Neil Shapiro break;
94940266059SGregory Neil Shapiro case 'D':
95040266059SGregory Neil Shapiro flags |= LONGINT;
95140266059SGregory Neil Shapiro /*FALLTHROUGH*/
95240266059SGregory Neil Shapiro case 'd':
95340266059SGregory Neil Shapiro case 'i':
95440266059SGregory Neil Shapiro if (flags & QUADINT)
95540266059SGregory Neil Shapiro {
95640266059SGregory Neil Shapiro ADDTYPE(T_QUAD);
95740266059SGregory Neil Shapiro }
95840266059SGregory Neil Shapiro else
95940266059SGregory Neil Shapiro {
96040266059SGregory Neil Shapiro ADDSARG();
96140266059SGregory Neil Shapiro }
96240266059SGregory Neil Shapiro break;
96340266059SGregory Neil Shapiro case 'e':
96440266059SGregory Neil Shapiro case 'E':
96540266059SGregory Neil Shapiro case 'f':
96640266059SGregory Neil Shapiro case 'g':
96740266059SGregory Neil Shapiro case 'G':
96840266059SGregory Neil Shapiro ADDTYPE(T_DOUBLE);
96940266059SGregory Neil Shapiro break;
97040266059SGregory Neil Shapiro case 'n':
97140266059SGregory Neil Shapiro if (flags & QUADINT)
97240266059SGregory Neil Shapiro ADDTYPE(TP_QUAD);
97340266059SGregory Neil Shapiro else if (flags & LONGINT)
97440266059SGregory Neil Shapiro ADDTYPE(TP_LONG);
97540266059SGregory Neil Shapiro else if (flags & SHORTINT)
97640266059SGregory Neil Shapiro ADDTYPE(TP_SHORT);
97740266059SGregory Neil Shapiro else
97840266059SGregory Neil Shapiro ADDTYPE(TP_INT);
97940266059SGregory Neil Shapiro continue; /* no output */
98040266059SGregory Neil Shapiro case 'O':
98140266059SGregory Neil Shapiro flags |= LONGINT;
98240266059SGregory Neil Shapiro /*FALLTHROUGH*/
98340266059SGregory Neil Shapiro case 'o':
98440266059SGregory Neil Shapiro if (flags & QUADINT)
98540266059SGregory Neil Shapiro ADDTYPE(T_U_QUAD);
98640266059SGregory Neil Shapiro else
98740266059SGregory Neil Shapiro ADDUARG();
98840266059SGregory Neil Shapiro break;
98940266059SGregory Neil Shapiro case 'p':
99040266059SGregory Neil Shapiro ADDTYPE(TP_VOID);
99140266059SGregory Neil Shapiro break;
99240266059SGregory Neil Shapiro case 's':
99340266059SGregory Neil Shapiro ADDTYPE(TP_CHAR);
99440266059SGregory Neil Shapiro break;
99540266059SGregory Neil Shapiro case 'U':
99640266059SGregory Neil Shapiro flags |= LONGINT;
99740266059SGregory Neil Shapiro /*FALLTHROUGH*/
99840266059SGregory Neil Shapiro case 'u':
99940266059SGregory Neil Shapiro if (flags & QUADINT)
100040266059SGregory Neil Shapiro ADDTYPE(T_U_QUAD);
100140266059SGregory Neil Shapiro else
100240266059SGregory Neil Shapiro ADDUARG();
100340266059SGregory Neil Shapiro break;
100440266059SGregory Neil Shapiro case 'X':
100540266059SGregory Neil Shapiro case 'x':
100640266059SGregory Neil Shapiro if (flags & QUADINT)
100740266059SGregory Neil Shapiro ADDTYPE(T_U_QUAD);
100840266059SGregory Neil Shapiro else
100940266059SGregory Neil Shapiro ADDUARG();
101040266059SGregory Neil Shapiro break;
101140266059SGregory Neil Shapiro default: /* "%?" prints ?, unless ? is NUL */
101240266059SGregory Neil Shapiro if (ch == '\0')
101340266059SGregory Neil Shapiro goto done;
101440266059SGregory Neil Shapiro break;
101540266059SGregory Neil Shapiro }
101640266059SGregory Neil Shapiro }
101740266059SGregory Neil Shapiro done:
101840266059SGregory Neil Shapiro /* Build the argument table. */
101940266059SGregory Neil Shapiro if (tablemax >= STATIC_ARG_TBL_SIZE)
102040266059SGregory Neil Shapiro {
102140266059SGregory Neil Shapiro *argtable = (va_list *)
102240266059SGregory Neil Shapiro sm_malloc(sizeof(va_list) * (tablemax + 1));
102340266059SGregory Neil Shapiro }
102440266059SGregory Neil Shapiro
102540266059SGregory Neil Shapiro for (n = 1; n <= tablemax; n++)
102640266059SGregory Neil Shapiro {
102740266059SGregory Neil Shapiro SM_VA_COPY((*argtable)[n], ap);
102840266059SGregory Neil Shapiro switch (typetable [n])
102940266059SGregory Neil Shapiro {
103040266059SGregory Neil Shapiro case T_UNUSED:
103140266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, int);
103240266059SGregory Neil Shapiro break;
103340266059SGregory Neil Shapiro case T_SHORT:
103440266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, int);
103540266059SGregory Neil Shapiro break;
103640266059SGregory Neil Shapiro case T_U_SHORT:
103740266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, int);
103840266059SGregory Neil Shapiro break;
103940266059SGregory Neil Shapiro case TP_SHORT:
104040266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, short *);
104140266059SGregory Neil Shapiro break;
104240266059SGregory Neil Shapiro case T_INT:
104340266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, int);
104440266059SGregory Neil Shapiro break;
104540266059SGregory Neil Shapiro case T_U_INT:
104640266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, unsigned int);
104740266059SGregory Neil Shapiro break;
104840266059SGregory Neil Shapiro case TP_INT:
104940266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, int *);
105040266059SGregory Neil Shapiro break;
105140266059SGregory Neil Shapiro case T_LONG:
105240266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, long);
105340266059SGregory Neil Shapiro break;
105440266059SGregory Neil Shapiro case T_U_LONG:
105540266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, unsigned long);
105640266059SGregory Neil Shapiro break;
105740266059SGregory Neil Shapiro case TP_LONG:
105840266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, long *);
105940266059SGregory Neil Shapiro break;
106040266059SGregory Neil Shapiro case T_QUAD:
106140266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, LONGLONG_T);
106240266059SGregory Neil Shapiro break;
106340266059SGregory Neil Shapiro case T_U_QUAD:
106440266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, ULONGLONG_T);
106540266059SGregory Neil Shapiro break;
106640266059SGregory Neil Shapiro case TP_QUAD:
106740266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, LONGLONG_T *);
106840266059SGregory Neil Shapiro break;
106940266059SGregory Neil Shapiro case T_DOUBLE:
107040266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, double);
107140266059SGregory Neil Shapiro break;
107240266059SGregory Neil Shapiro case TP_CHAR:
107340266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, char *);
107440266059SGregory Neil Shapiro break;
107540266059SGregory Neil Shapiro case TP_VOID:
107640266059SGregory Neil Shapiro (void) SM_VA_ARG(ap, void *);
107740266059SGregory Neil Shapiro break;
107840266059SGregory Neil Shapiro }
10792fb4f839SGregory Neil Shapiro SM_VA_END_COPY((*argtable)[n]);
108040266059SGregory Neil Shapiro }
108140266059SGregory Neil Shapiro
108240266059SGregory Neil Shapiro if ((typetable != NULL) && (typetable != stattypetable))
108340266059SGregory Neil Shapiro sm_free(typetable);
108440266059SGregory Neil Shapiro }
108540266059SGregory Neil Shapiro
108640266059SGregory Neil Shapiro /*
108740266059SGregory Neil Shapiro ** SM_GROW_TYPE_TABLE -- Increase the size of the type table.
108840266059SGregory Neil Shapiro **
108940266059SGregory Neil Shapiro ** Parameters:
109040266059SGregory Neil Shapiro ** tabletype -- type of table to grow
109140266059SGregory Neil Shapiro ** tablesize -- requested new table size
109240266059SGregory Neil Shapiro **
109340266059SGregory Neil Shapiro ** Results:
109440266059SGregory Neil Shapiro ** Raises an exception if can't allocate memory.
109540266059SGregory Neil Shapiro */
109640266059SGregory Neil Shapiro
109740266059SGregory Neil Shapiro static void
sm_grow_type_table_x(typetable,tablesize)109840266059SGregory Neil Shapiro sm_grow_type_table_x(typetable, tablesize)
109940266059SGregory Neil Shapiro unsigned char **typetable;
110040266059SGregory Neil Shapiro int *tablesize;
110140266059SGregory Neil Shapiro {
110240266059SGregory Neil Shapiro unsigned char *oldtable = *typetable;
110340266059SGregory Neil Shapiro int newsize = *tablesize * 2;
110440266059SGregory Neil Shapiro
110540266059SGregory Neil Shapiro if (*tablesize == STATIC_ARG_TBL_SIZE)
110640266059SGregory Neil Shapiro {
110740266059SGregory Neil Shapiro *typetable = (unsigned char *) sm_malloc_x(sizeof(unsigned char)
110840266059SGregory Neil Shapiro * newsize);
110940266059SGregory Neil Shapiro (void) memmove(*typetable, oldtable, *tablesize);
111040266059SGregory Neil Shapiro }
111140266059SGregory Neil Shapiro else
111240266059SGregory Neil Shapiro {
111340266059SGregory Neil Shapiro *typetable = (unsigned char *) sm_realloc_x(typetable,
111440266059SGregory Neil Shapiro sizeof(unsigned char) * newsize);
111540266059SGregory Neil Shapiro }
111640266059SGregory Neil Shapiro (void) memset(&typetable [*tablesize], T_UNUSED,
111740266059SGregory Neil Shapiro (newsize - *tablesize));
111840266059SGregory Neil Shapiro
111940266059SGregory Neil Shapiro *tablesize = newsize;
112040266059SGregory Neil Shapiro }
1121