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, 1993
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: vfscanf.c,v 1.55 2013-11-22 20:51:44 ca Exp $")
1740266059SGregory Neil Shapiro
1840266059SGregory Neil Shapiro #include <ctype.h>
1940266059SGregory Neil Shapiro #include <stdlib.h>
2040266059SGregory Neil Shapiro #include <errno.h>
2140266059SGregory Neil Shapiro #include <setjmp.h>
224e4196cbSGregory Neil Shapiro #include <sm/time.h>
2340266059SGregory Neil Shapiro #include <sm/varargs.h>
2440266059SGregory Neil Shapiro #include <sm/config.h>
2540266059SGregory Neil Shapiro #include <sm/io.h>
2640266059SGregory Neil Shapiro #include <sm/signal.h>
2740266059SGregory Neil Shapiro #include <sm/clock.h>
2840266059SGregory Neil Shapiro #include <sm/string.h>
2940266059SGregory Neil Shapiro #include "local.h"
3040266059SGregory Neil Shapiro
3140266059SGregory Neil Shapiro #define BUF 513 /* Maximum length of numeric string. */
3240266059SGregory Neil Shapiro
3340266059SGregory Neil Shapiro /* Flags used during conversion. */
3440266059SGregory Neil Shapiro #define LONG 0x01 /* l: long or double */
3540266059SGregory Neil Shapiro #define SHORT 0x04 /* h: short */
3640266059SGregory Neil Shapiro #define QUAD 0x08 /* q: quad (same as ll) */
3740266059SGregory Neil Shapiro #define SUPPRESS 0x10 /* suppress assignment */
3840266059SGregory Neil Shapiro #define POINTER 0x20 /* weird %p pointer (`fake hex') */
3940266059SGregory Neil Shapiro #define NOSKIP 0x40 /* do not skip blanks */
4040266059SGregory Neil Shapiro
4140266059SGregory Neil Shapiro /*
4240266059SGregory Neil Shapiro ** The following are used in numeric conversions only:
4340266059SGregory Neil Shapiro ** SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
4440266059SGregory Neil Shapiro ** SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
4540266059SGregory Neil Shapiro */
4640266059SGregory Neil Shapiro
4740266059SGregory Neil Shapiro #define SIGNOK 0x080 /* +/- is (still) legal */
4840266059SGregory Neil Shapiro #define NDIGITS 0x100 /* no digits detected */
4940266059SGregory Neil Shapiro
5040266059SGregory Neil Shapiro #define DPTOK 0x200 /* (float) decimal point is still legal */
5140266059SGregory Neil Shapiro #define EXPOK 0x400 /* (float) exponent (e+3, etc) still legal */
5240266059SGregory Neil Shapiro
5340266059SGregory Neil Shapiro #define PFXOK 0x200 /* 0x prefix is (still) legal */
5440266059SGregory Neil Shapiro #define NZDIGITS 0x400 /* no zero digits detected */
5540266059SGregory Neil Shapiro
5640266059SGregory Neil Shapiro /* Conversion types. */
5740266059SGregory Neil Shapiro #define CT_CHAR 0 /* %c conversion */
5840266059SGregory Neil Shapiro #define CT_CCL 1 /* %[...] conversion */
5940266059SGregory Neil Shapiro #define CT_STRING 2 /* %s conversion */
6040266059SGregory Neil Shapiro #define CT_INT 3 /* integer, i.e., strtoll or strtoull */
6140266059SGregory Neil Shapiro #define CT_FLOAT 4 /* floating, i.e., strtod */
6240266059SGregory Neil Shapiro
63b6bacd31SGregory Neil Shapiro static void scanalrm __P((int));
6440266059SGregory Neil Shapiro static unsigned char *sm_sccl __P((char *, unsigned char *));
6540266059SGregory Neil Shapiro static jmp_buf ScanTimeOut;
6640266059SGregory Neil Shapiro
6740266059SGregory Neil Shapiro /*
6840266059SGregory Neil Shapiro ** SCANALRM -- handler when timeout activated for sm_io_vfscanf()
6940266059SGregory Neil Shapiro **
7040266059SGregory Neil Shapiro ** Returns flow of control to where setjmp(ScanTimeOut) was set.
7140266059SGregory Neil Shapiro **
7240266059SGregory Neil Shapiro ** Parameters:
7340266059SGregory Neil Shapiro ** sig -- unused
7440266059SGregory Neil Shapiro **
7540266059SGregory Neil Shapiro ** Returns:
7640266059SGregory Neil Shapiro ** does not return
7740266059SGregory Neil Shapiro **
7840266059SGregory Neil Shapiro ** Side Effects:
7940266059SGregory Neil Shapiro ** returns flow of control to setjmp(ScanTimeOut).
8040266059SGregory Neil Shapiro **
8140266059SGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
8240266059SGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
8340266059SGregory Neil Shapiro ** DOING.
8440266059SGregory Neil Shapiro */
8540266059SGregory Neil Shapiro
8640266059SGregory Neil Shapiro /* ARGSUSED0 */
8740266059SGregory Neil Shapiro static void
scanalrm(sig)8840266059SGregory Neil Shapiro scanalrm(sig)
8940266059SGregory Neil Shapiro int sig;
9040266059SGregory Neil Shapiro {
9140266059SGregory Neil Shapiro longjmp(ScanTimeOut, 1);
9240266059SGregory Neil Shapiro }
9340266059SGregory Neil Shapiro
9440266059SGregory Neil Shapiro /*
9540266059SGregory Neil Shapiro ** SM_VFSCANF -- convert input into data units
9640266059SGregory Neil Shapiro **
9740266059SGregory Neil Shapiro ** Parameters:
9840266059SGregory Neil Shapiro ** fp -- file pointer for input data
9940266059SGregory Neil Shapiro ** timeout -- time intvl allowed to complete (milliseconds)
10040266059SGregory Neil Shapiro ** fmt0 -- format for finding data units
10140266059SGregory Neil Shapiro ** ap -- vectors for memory location for storing data units
10240266059SGregory Neil Shapiro **
10340266059SGregory Neil Shapiro ** Results:
10440266059SGregory Neil Shapiro ** Success: number of data units assigned
10540266059SGregory Neil Shapiro ** Failure: SM_IO_EOF
10640266059SGregory Neil Shapiro */
10740266059SGregory Neil Shapiro
10840266059SGregory Neil Shapiro int
sm_vfscanf(fp,timeout,fmt0,ap)10940266059SGregory Neil Shapiro sm_vfscanf(fp, timeout, fmt0, ap)
11040266059SGregory Neil Shapiro register SM_FILE_T *fp;
11140266059SGregory Neil Shapiro int SM_NONVOLATILE timeout;
11240266059SGregory Neil Shapiro char const *fmt0;
1135b0945b5SGregory Neil Shapiro va_list ap;
11440266059SGregory Neil Shapiro {
11540266059SGregory Neil Shapiro register unsigned char *SM_NONVOLATILE fmt = (unsigned char *) fmt0;
11640266059SGregory Neil Shapiro register int c; /* character from format, or conversion */
11740266059SGregory Neil Shapiro register size_t width; /* field width, or 0 */
11840266059SGregory Neil Shapiro register char *p; /* points into all kinds of strings */
11940266059SGregory Neil Shapiro register int n; /* handy integer */
12040266059SGregory Neil Shapiro register int flags; /* flags as defined above */
12140266059SGregory Neil Shapiro register char *p0; /* saves original value of p when necessary */
12240266059SGregory Neil Shapiro int nassigned; /* number of fields assigned */
12340266059SGregory Neil Shapiro int nread; /* number of characters consumed from fp */
12440266059SGregory Neil Shapiro int base; /* base argument to strtoll/strtoull */
125d0cef73dSGregory Neil Shapiro
126d0cef73dSGregory Neil Shapiro /* conversion function (strtoll/strtoull) */
127d0cef73dSGregory Neil Shapiro ULONGLONG_T (*ccfn) __P((const char *, char **, int));
12840266059SGregory Neil Shapiro char ccltab[256]; /* character class table for %[...] */
12940266059SGregory Neil Shapiro char buf[BUF]; /* buffer for numeric conversions */
13040266059SGregory Neil Shapiro SM_EVENT *evt = NULL;
13140266059SGregory Neil Shapiro
13240266059SGregory Neil Shapiro /* `basefix' is used to avoid `if' tests in the integer scanner */
13340266059SGregory Neil Shapiro static short basefix[17] =
13440266059SGregory Neil Shapiro { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
13540266059SGregory Neil Shapiro
13640266059SGregory Neil Shapiro if (timeout == SM_TIME_DEFAULT)
13740266059SGregory Neil Shapiro timeout = fp->f_timeout;
13840266059SGregory Neil Shapiro if (timeout == SM_TIME_IMMEDIATE)
13940266059SGregory Neil Shapiro {
14040266059SGregory Neil Shapiro /*
14140266059SGregory Neil Shapiro ** Filling the buffer will take time and we are wanted to
14240266059SGregory Neil Shapiro ** return immediately. So...
14340266059SGregory Neil Shapiro */
14440266059SGregory Neil Shapiro
14540266059SGregory Neil Shapiro errno = EAGAIN;
14640266059SGregory Neil Shapiro return SM_IO_EOF;
14740266059SGregory Neil Shapiro }
14840266059SGregory Neil Shapiro
14940266059SGregory Neil Shapiro if (timeout != SM_TIME_FOREVER)
15040266059SGregory Neil Shapiro {
15140266059SGregory Neil Shapiro if (setjmp(ScanTimeOut) != 0)
15240266059SGregory Neil Shapiro {
15340266059SGregory Neil Shapiro errno = EAGAIN;
15440266059SGregory Neil Shapiro return SM_IO_EOF;
15540266059SGregory Neil Shapiro }
15640266059SGregory Neil Shapiro
15740266059SGregory Neil Shapiro evt = sm_seteventm(timeout, scanalrm, 0);
15840266059SGregory Neil Shapiro }
15940266059SGregory Neil Shapiro
16040266059SGregory Neil Shapiro nassigned = 0;
16140266059SGregory Neil Shapiro nread = 0;
16240266059SGregory Neil Shapiro base = 0; /* XXX just to keep gcc happy */
16340266059SGregory Neil Shapiro ccfn = NULL; /* XXX just to keep gcc happy */
16440266059SGregory Neil Shapiro for (;;)
16540266059SGregory Neil Shapiro {
16640266059SGregory Neil Shapiro c = *fmt++;
16740266059SGregory Neil Shapiro if (c == 0)
16840266059SGregory Neil Shapiro {
16940266059SGregory Neil Shapiro if (evt != NULL)
17040266059SGregory Neil Shapiro sm_clrevent(evt); /* undo our timeout */
17140266059SGregory Neil Shapiro return nassigned;
17240266059SGregory Neil Shapiro }
17340266059SGregory Neil Shapiro if (isspace(c))
17440266059SGregory Neil Shapiro {
17540266059SGregory Neil Shapiro while ((fp->f_r > 0 || sm_refill(fp, SM_TIME_FOREVER)
17640266059SGregory Neil Shapiro == 0) &&
17740266059SGregory Neil Shapiro isspace(*fp->f_p))
17840266059SGregory Neil Shapiro nread++, fp->f_r--, fp->f_p++;
17940266059SGregory Neil Shapiro continue;
18040266059SGregory Neil Shapiro }
18140266059SGregory Neil Shapiro if (c != '%')
18240266059SGregory Neil Shapiro goto literal;
18340266059SGregory Neil Shapiro width = 0;
18440266059SGregory Neil Shapiro flags = 0;
18540266059SGregory Neil Shapiro
18640266059SGregory Neil Shapiro /*
18740266059SGregory Neil Shapiro ** switch on the format. continue if done;
18840266059SGregory Neil Shapiro ** break once format type is derived.
18940266059SGregory Neil Shapiro */
19040266059SGregory Neil Shapiro
19140266059SGregory Neil Shapiro again: c = *fmt++;
19240266059SGregory Neil Shapiro switch (c)
19340266059SGregory Neil Shapiro {
19440266059SGregory Neil Shapiro case '%':
19540266059SGregory Neil Shapiro literal:
19640266059SGregory Neil Shapiro if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
19740266059SGregory Neil Shapiro goto input_failure;
19840266059SGregory Neil Shapiro if (*fp->f_p != c)
19940266059SGregory Neil Shapiro goto match_failure;
20040266059SGregory Neil Shapiro fp->f_r--, fp->f_p++;
20140266059SGregory Neil Shapiro nread++;
20240266059SGregory Neil Shapiro continue;
20340266059SGregory Neil Shapiro
20440266059SGregory Neil Shapiro case '*':
20540266059SGregory Neil Shapiro flags |= SUPPRESS;
20640266059SGregory Neil Shapiro goto again;
20740266059SGregory Neil Shapiro case 'h':
20840266059SGregory Neil Shapiro flags |= SHORT;
20940266059SGregory Neil Shapiro goto again;
21040266059SGregory Neil Shapiro case 'l':
21140266059SGregory Neil Shapiro if (*fmt == 'l')
21240266059SGregory Neil Shapiro {
21340266059SGregory Neil Shapiro fmt++;
21440266059SGregory Neil Shapiro flags |= QUAD;
21540266059SGregory Neil Shapiro }
21640266059SGregory Neil Shapiro else
21740266059SGregory Neil Shapiro {
21840266059SGregory Neil Shapiro flags |= LONG;
21940266059SGregory Neil Shapiro }
22040266059SGregory Neil Shapiro goto again;
22140266059SGregory Neil Shapiro case 'q':
22240266059SGregory Neil Shapiro flags |= QUAD;
22340266059SGregory Neil Shapiro goto again;
22440266059SGregory Neil Shapiro
22540266059SGregory Neil Shapiro case '0': case '1': case '2': case '3': case '4':
22640266059SGregory Neil Shapiro case '5': case '6': case '7': case '8': case '9':
22740266059SGregory Neil Shapiro width = width * 10 + c - '0';
22840266059SGregory Neil Shapiro goto again;
22940266059SGregory Neil Shapiro
23040266059SGregory Neil Shapiro /*
23140266059SGregory Neil Shapiro ** Conversions.
23240266059SGregory Neil Shapiro ** Those marked `compat' are for 4.[123]BSD compatibility.
23340266059SGregory Neil Shapiro **
23440266059SGregory Neil Shapiro ** (According to ANSI, E and X formats are supposed
23540266059SGregory Neil Shapiro ** to the same as e and x. Sorry about that.)
23640266059SGregory Neil Shapiro */
23740266059SGregory Neil Shapiro
23840266059SGregory Neil Shapiro case 'D': /* compat */
23940266059SGregory Neil Shapiro flags |= LONG;
24040266059SGregory Neil Shapiro /* FALLTHROUGH */
24140266059SGregory Neil Shapiro case 'd':
24240266059SGregory Neil Shapiro c = CT_INT;
24340266059SGregory Neil Shapiro ccfn = (ULONGLONG_T (*)())sm_strtoll;
24440266059SGregory Neil Shapiro base = 10;
24540266059SGregory Neil Shapiro break;
24640266059SGregory Neil Shapiro
24740266059SGregory Neil Shapiro case 'i':
24840266059SGregory Neil Shapiro c = CT_INT;
24940266059SGregory Neil Shapiro ccfn = (ULONGLONG_T (*)())sm_strtoll;
25040266059SGregory Neil Shapiro base = 0;
25140266059SGregory Neil Shapiro break;
25240266059SGregory Neil Shapiro
25340266059SGregory Neil Shapiro case 'O': /* compat */
25440266059SGregory Neil Shapiro flags |= LONG;
25540266059SGregory Neil Shapiro /* FALLTHROUGH */
25640266059SGregory Neil Shapiro case 'o':
25740266059SGregory Neil Shapiro c = CT_INT;
25840266059SGregory Neil Shapiro ccfn = sm_strtoull;
25940266059SGregory Neil Shapiro base = 8;
26040266059SGregory Neil Shapiro break;
26140266059SGregory Neil Shapiro
26240266059SGregory Neil Shapiro case 'u':
26340266059SGregory Neil Shapiro c = CT_INT;
26440266059SGregory Neil Shapiro ccfn = sm_strtoull;
26540266059SGregory Neil Shapiro base = 10;
26640266059SGregory Neil Shapiro break;
26740266059SGregory Neil Shapiro
26840266059SGregory Neil Shapiro case 'X':
26940266059SGregory Neil Shapiro case 'x':
27040266059SGregory Neil Shapiro flags |= PFXOK; /* enable 0x prefixing */
27140266059SGregory Neil Shapiro c = CT_INT;
27240266059SGregory Neil Shapiro ccfn = sm_strtoull;
27340266059SGregory Neil Shapiro base = 16;
27440266059SGregory Neil Shapiro break;
27540266059SGregory Neil Shapiro
27640266059SGregory Neil Shapiro case 'E':
27740266059SGregory Neil Shapiro case 'G':
27840266059SGregory Neil Shapiro case 'e':
27940266059SGregory Neil Shapiro case 'f':
28040266059SGregory Neil Shapiro case 'g':
28140266059SGregory Neil Shapiro c = CT_FLOAT;
28240266059SGregory Neil Shapiro break;
28340266059SGregory Neil Shapiro
28440266059SGregory Neil Shapiro case 's':
28540266059SGregory Neil Shapiro c = CT_STRING;
28640266059SGregory Neil Shapiro break;
28740266059SGregory Neil Shapiro
28840266059SGregory Neil Shapiro case '[':
28940266059SGregory Neil Shapiro fmt = sm_sccl(ccltab, fmt);
29040266059SGregory Neil Shapiro flags |= NOSKIP;
29140266059SGregory Neil Shapiro c = CT_CCL;
29240266059SGregory Neil Shapiro break;
29340266059SGregory Neil Shapiro
29440266059SGregory Neil Shapiro case 'c':
29540266059SGregory Neil Shapiro flags |= NOSKIP;
29640266059SGregory Neil Shapiro c = CT_CHAR;
29740266059SGregory Neil Shapiro break;
29840266059SGregory Neil Shapiro
29940266059SGregory Neil Shapiro case 'p': /* pointer format is like hex */
30040266059SGregory Neil Shapiro flags |= POINTER | PFXOK;
30140266059SGregory Neil Shapiro c = CT_INT;
30240266059SGregory Neil Shapiro ccfn = sm_strtoull;
30340266059SGregory Neil Shapiro base = 16;
30440266059SGregory Neil Shapiro break;
30540266059SGregory Neil Shapiro
30640266059SGregory Neil Shapiro case 'n':
30740266059SGregory Neil Shapiro if (flags & SUPPRESS) /* ??? */
30840266059SGregory Neil Shapiro continue;
30940266059SGregory Neil Shapiro if (flags & SHORT)
31040266059SGregory Neil Shapiro *SM_VA_ARG(ap, short *) = nread;
31140266059SGregory Neil Shapiro else if (flags & LONG)
31240266059SGregory Neil Shapiro *SM_VA_ARG(ap, long *) = nread;
31340266059SGregory Neil Shapiro else
31440266059SGregory Neil Shapiro *SM_VA_ARG(ap, int *) = nread;
31540266059SGregory Neil Shapiro continue;
31640266059SGregory Neil Shapiro
31740266059SGregory Neil Shapiro /* Disgusting backwards compatibility hacks. XXX */
31840266059SGregory Neil Shapiro case '\0': /* compat */
31940266059SGregory Neil Shapiro if (evt != NULL)
32040266059SGregory Neil Shapiro sm_clrevent(evt); /* undo our timeout */
32140266059SGregory Neil Shapiro return SM_IO_EOF;
32240266059SGregory Neil Shapiro
32340266059SGregory Neil Shapiro default: /* compat */
32440266059SGregory Neil Shapiro if (isupper(c))
32540266059SGregory Neil Shapiro flags |= LONG;
32640266059SGregory Neil Shapiro c = CT_INT;
32740266059SGregory Neil Shapiro ccfn = (ULONGLONG_T (*)()) sm_strtoll;
32840266059SGregory Neil Shapiro base = 10;
32940266059SGregory Neil Shapiro break;
33040266059SGregory Neil Shapiro }
33140266059SGregory Neil Shapiro
33240266059SGregory Neil Shapiro /* We have a conversion that requires input. */
33340266059SGregory Neil Shapiro if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
33440266059SGregory Neil Shapiro goto input_failure;
33540266059SGregory Neil Shapiro
33640266059SGregory Neil Shapiro /*
33740266059SGregory Neil Shapiro ** Consume leading white space, except for formats
33840266059SGregory Neil Shapiro ** that suppress this.
33940266059SGregory Neil Shapiro */
34040266059SGregory Neil Shapiro
34140266059SGregory Neil Shapiro if ((flags & NOSKIP) == 0)
34240266059SGregory Neil Shapiro {
34340266059SGregory Neil Shapiro while (isspace(*fp->f_p))
34440266059SGregory Neil Shapiro {
34540266059SGregory Neil Shapiro nread++;
34640266059SGregory Neil Shapiro if (--fp->f_r > 0)
34740266059SGregory Neil Shapiro fp->f_p++;
34840266059SGregory Neil Shapiro else if (sm_refill(fp, SM_TIME_FOREVER))
34940266059SGregory Neil Shapiro goto input_failure;
35040266059SGregory Neil Shapiro }
35140266059SGregory Neil Shapiro /*
35240266059SGregory Neil Shapiro ** Note that there is at least one character in
35340266059SGregory Neil Shapiro ** the buffer, so conversions that do not set NOSKIP
35440266059SGregory Neil Shapiro ** can no longer result in an input failure.
35540266059SGregory Neil Shapiro */
35640266059SGregory Neil Shapiro }
35740266059SGregory Neil Shapiro
35840266059SGregory Neil Shapiro /* Do the conversion. */
35940266059SGregory Neil Shapiro switch (c)
36040266059SGregory Neil Shapiro {
36140266059SGregory Neil Shapiro case CT_CHAR:
36240266059SGregory Neil Shapiro /* scan arbitrary characters (sets NOSKIP) */
36340266059SGregory Neil Shapiro if (width == 0)
36440266059SGregory Neil Shapiro width = 1;
36540266059SGregory Neil Shapiro if (flags & SUPPRESS)
36640266059SGregory Neil Shapiro {
36740266059SGregory Neil Shapiro size_t sum = 0;
36840266059SGregory Neil Shapiro for (;;)
36940266059SGregory Neil Shapiro {
37040266059SGregory Neil Shapiro if ((size_t) (n = fp->f_r) < width)
37140266059SGregory Neil Shapiro {
37240266059SGregory Neil Shapiro sum += n;
37340266059SGregory Neil Shapiro width -= n;
37440266059SGregory Neil Shapiro fp->f_p += n;
37540266059SGregory Neil Shapiro if (sm_refill(fp,
37640266059SGregory Neil Shapiro SM_TIME_FOREVER))
37740266059SGregory Neil Shapiro {
37840266059SGregory Neil Shapiro if (sum == 0)
37940266059SGregory Neil Shapiro goto input_failure;
38040266059SGregory Neil Shapiro break;
38140266059SGregory Neil Shapiro }
38240266059SGregory Neil Shapiro }
38340266059SGregory Neil Shapiro else
38440266059SGregory Neil Shapiro {
38540266059SGregory Neil Shapiro sum += width;
38640266059SGregory Neil Shapiro fp->f_r -= width;
38740266059SGregory Neil Shapiro fp->f_p += width;
38840266059SGregory Neil Shapiro break;
38940266059SGregory Neil Shapiro }
39040266059SGregory Neil Shapiro }
39140266059SGregory Neil Shapiro nread += sum;
39240266059SGregory Neil Shapiro }
39340266059SGregory Neil Shapiro else
39440266059SGregory Neil Shapiro {
39540266059SGregory Neil Shapiro size_t r;
39640266059SGregory Neil Shapiro
39740266059SGregory Neil Shapiro r = sm_io_read(fp, SM_TIME_FOREVER,
39840266059SGregory Neil Shapiro (void *) SM_VA_ARG(ap, char *),
39940266059SGregory Neil Shapiro width);
40040266059SGregory Neil Shapiro if (r == 0)
40140266059SGregory Neil Shapiro goto input_failure;
40240266059SGregory Neil Shapiro nread += r;
40340266059SGregory Neil Shapiro nassigned++;
40440266059SGregory Neil Shapiro }
40540266059SGregory Neil Shapiro break;
40640266059SGregory Neil Shapiro
40740266059SGregory Neil Shapiro case CT_CCL:
40840266059SGregory Neil Shapiro /* scan a (nonempty) character class (sets NOSKIP) */
40940266059SGregory Neil Shapiro if (width == 0)
41040266059SGregory Neil Shapiro width = (size_t)~0; /* `infinity' */
41140266059SGregory Neil Shapiro
41240266059SGregory Neil Shapiro /* take only those things in the class */
41340266059SGregory Neil Shapiro if (flags & SUPPRESS)
41440266059SGregory Neil Shapiro {
41540266059SGregory Neil Shapiro n = 0;
41640266059SGregory Neil Shapiro while (ccltab[*fp->f_p] != '\0')
41740266059SGregory Neil Shapiro {
41840266059SGregory Neil Shapiro n++, fp->f_r--, fp->f_p++;
41940266059SGregory Neil Shapiro if (--width == 0)
42040266059SGregory Neil Shapiro break;
42140266059SGregory Neil Shapiro if (fp->f_r <= 0 &&
42240266059SGregory Neil Shapiro sm_refill(fp, SM_TIME_FOREVER))
42340266059SGregory Neil Shapiro {
42440266059SGregory Neil Shapiro if (n == 0) /* XXX how? */
42540266059SGregory Neil Shapiro goto input_failure;
42640266059SGregory Neil Shapiro break;
42740266059SGregory Neil Shapiro }
42840266059SGregory Neil Shapiro }
42940266059SGregory Neil Shapiro if (n == 0)
43040266059SGregory Neil Shapiro goto match_failure;
43140266059SGregory Neil Shapiro }
43240266059SGregory Neil Shapiro else
43340266059SGregory Neil Shapiro {
43440266059SGregory Neil Shapiro p0 = p = SM_VA_ARG(ap, char *);
43540266059SGregory Neil Shapiro while (ccltab[*fp->f_p] != '\0')
43640266059SGregory Neil Shapiro {
43740266059SGregory Neil Shapiro fp->f_r--;
43840266059SGregory Neil Shapiro *p++ = *fp->f_p++;
43940266059SGregory Neil Shapiro if (--width == 0)
44040266059SGregory Neil Shapiro break;
44140266059SGregory Neil Shapiro if (fp->f_r <= 0 &&
44240266059SGregory Neil Shapiro sm_refill(fp, SM_TIME_FOREVER))
44340266059SGregory Neil Shapiro {
44440266059SGregory Neil Shapiro if (p == p0)
44540266059SGregory Neil Shapiro goto input_failure;
44640266059SGregory Neil Shapiro break;
44740266059SGregory Neil Shapiro }
44840266059SGregory Neil Shapiro }
44940266059SGregory Neil Shapiro n = p - p0;
45040266059SGregory Neil Shapiro if (n == 0)
45140266059SGregory Neil Shapiro goto match_failure;
45240266059SGregory Neil Shapiro *p = 0;
45340266059SGregory Neil Shapiro nassigned++;
45440266059SGregory Neil Shapiro }
45540266059SGregory Neil Shapiro nread += n;
45640266059SGregory Neil Shapiro break;
45740266059SGregory Neil Shapiro
45840266059SGregory Neil Shapiro case CT_STRING:
45940266059SGregory Neil Shapiro /* like CCL, but zero-length string OK, & no NOSKIP */
46040266059SGregory Neil Shapiro if (width == 0)
46140266059SGregory Neil Shapiro width = (size_t)~0;
46240266059SGregory Neil Shapiro if (flags & SUPPRESS)
46340266059SGregory Neil Shapiro {
46440266059SGregory Neil Shapiro n = 0;
46540266059SGregory Neil Shapiro while (!isspace(*fp->f_p))
46640266059SGregory Neil Shapiro {
46740266059SGregory Neil Shapiro n++, fp->f_r--, fp->f_p++;
46840266059SGregory Neil Shapiro if (--width == 0)
46940266059SGregory Neil Shapiro break;
47040266059SGregory Neil Shapiro if (fp->f_r <= 0 &&
47140266059SGregory Neil Shapiro sm_refill(fp, SM_TIME_FOREVER))
47240266059SGregory Neil Shapiro break;
47340266059SGregory Neil Shapiro }
47440266059SGregory Neil Shapiro nread += n;
47540266059SGregory Neil Shapiro }
47640266059SGregory Neil Shapiro else
47740266059SGregory Neil Shapiro {
47840266059SGregory Neil Shapiro p0 = p = SM_VA_ARG(ap, char *);
47940266059SGregory Neil Shapiro while (!isspace(*fp->f_p))
48040266059SGregory Neil Shapiro {
48140266059SGregory Neil Shapiro fp->f_r--;
48240266059SGregory Neil Shapiro *p++ = *fp->f_p++;
48340266059SGregory Neil Shapiro if (--width == 0)
48440266059SGregory Neil Shapiro break;
48540266059SGregory Neil Shapiro if (fp->f_r <= 0 &&
48640266059SGregory Neil Shapiro sm_refill(fp, SM_TIME_FOREVER))
48740266059SGregory Neil Shapiro break;
48840266059SGregory Neil Shapiro }
48940266059SGregory Neil Shapiro *p = 0;
49040266059SGregory Neil Shapiro nread += p - p0;
49140266059SGregory Neil Shapiro nassigned++;
49240266059SGregory Neil Shapiro }
49340266059SGregory Neil Shapiro continue;
49440266059SGregory Neil Shapiro
49540266059SGregory Neil Shapiro case CT_INT:
49640266059SGregory Neil Shapiro /* scan an integer as if by strtoll/strtoull */
49740266059SGregory Neil Shapiro #if SM_CONF_BROKEN_SIZE_T
49840266059SGregory Neil Shapiro if (width == 0 || width > sizeof(buf) - 1)
49940266059SGregory Neil Shapiro width = sizeof(buf) - 1;
50040266059SGregory Neil Shapiro #else /* SM_CONF_BROKEN_SIZE_T */
50140266059SGregory Neil Shapiro /* size_t is unsigned, hence this optimisation */
50240266059SGregory Neil Shapiro if (--width > sizeof(buf) - 2)
50340266059SGregory Neil Shapiro width = sizeof(buf) - 2;
50440266059SGregory Neil Shapiro width++;
50540266059SGregory Neil Shapiro #endif /* SM_CONF_BROKEN_SIZE_T */
50640266059SGregory Neil Shapiro flags |= SIGNOK | NDIGITS | NZDIGITS;
50740266059SGregory Neil Shapiro for (p = buf; width > 0; width--)
50840266059SGregory Neil Shapiro {
50940266059SGregory Neil Shapiro c = *fp->f_p;
51040266059SGregory Neil Shapiro
51140266059SGregory Neil Shapiro /*
51240266059SGregory Neil Shapiro ** Switch on the character; `goto ok'
51340266059SGregory Neil Shapiro ** if we accept it as a part of number.
51440266059SGregory Neil Shapiro */
51540266059SGregory Neil Shapiro
51640266059SGregory Neil Shapiro switch (c)
51740266059SGregory Neil Shapiro {
51840266059SGregory Neil Shapiro
51940266059SGregory Neil Shapiro /*
52040266059SGregory Neil Shapiro ** The digit 0 is always legal, but is
52140266059SGregory Neil Shapiro ** special. For %i conversions, if no
52240266059SGregory Neil Shapiro ** digits (zero or nonzero) have been
52340266059SGregory Neil Shapiro ** scanned (only signs), we will have
52440266059SGregory Neil Shapiro ** base==0. In that case, we should set
52540266059SGregory Neil Shapiro ** it to 8 and enable 0x prefixing.
52640266059SGregory Neil Shapiro ** Also, if we have not scanned zero digits
52740266059SGregory Neil Shapiro ** before this, do not turn off prefixing
52840266059SGregory Neil Shapiro ** (someone else will turn it off if we
52940266059SGregory Neil Shapiro ** have scanned any nonzero digits).
53040266059SGregory Neil Shapiro */
53140266059SGregory Neil Shapiro
53240266059SGregory Neil Shapiro case '0':
53340266059SGregory Neil Shapiro if (base == 0)
53440266059SGregory Neil Shapiro {
53540266059SGregory Neil Shapiro base = 8;
53640266059SGregory Neil Shapiro flags |= PFXOK;
53740266059SGregory Neil Shapiro }
53840266059SGregory Neil Shapiro if (flags & NZDIGITS)
53940266059SGregory Neil Shapiro flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
54040266059SGregory Neil Shapiro else
54140266059SGregory Neil Shapiro flags &= ~(SIGNOK|PFXOK|NDIGITS);
54240266059SGregory Neil Shapiro goto ok;
54340266059SGregory Neil Shapiro
54440266059SGregory Neil Shapiro /* 1 through 7 always legal */
54540266059SGregory Neil Shapiro case '1': case '2': case '3':
54640266059SGregory Neil Shapiro case '4': case '5': case '6': case '7':
54740266059SGregory Neil Shapiro base = basefix[base];
54840266059SGregory Neil Shapiro flags &= ~(SIGNOK | PFXOK | NDIGITS);
54940266059SGregory Neil Shapiro goto ok;
55040266059SGregory Neil Shapiro
55140266059SGregory Neil Shapiro /* digits 8 and 9 ok iff decimal or hex */
55240266059SGregory Neil Shapiro case '8': case '9':
55340266059SGregory Neil Shapiro base = basefix[base];
55440266059SGregory Neil Shapiro if (base <= 8)
55540266059SGregory Neil Shapiro break; /* not legal here */
55640266059SGregory Neil Shapiro flags &= ~(SIGNOK | PFXOK | NDIGITS);
55740266059SGregory Neil Shapiro goto ok;
55840266059SGregory Neil Shapiro
55940266059SGregory Neil Shapiro /* letters ok iff hex */
56040266059SGregory Neil Shapiro case 'A': case 'B': case 'C':
56140266059SGregory Neil Shapiro case 'D': case 'E': case 'F':
56240266059SGregory Neil Shapiro case 'a': case 'b': case 'c':
56340266059SGregory Neil Shapiro case 'd': case 'e': case 'f':
56440266059SGregory Neil Shapiro
56540266059SGregory Neil Shapiro /* no need to fix base here */
56640266059SGregory Neil Shapiro if (base <= 10)
56740266059SGregory Neil Shapiro break; /* not legal here */
56840266059SGregory Neil Shapiro flags &= ~(SIGNOK | PFXOK | NDIGITS);
56940266059SGregory Neil Shapiro goto ok;
57040266059SGregory Neil Shapiro
57140266059SGregory Neil Shapiro /* sign ok only as first character */
57240266059SGregory Neil Shapiro case '+': case '-':
57340266059SGregory Neil Shapiro if (flags & SIGNOK)
57440266059SGregory Neil Shapiro {
57540266059SGregory Neil Shapiro flags &= ~SIGNOK;
57640266059SGregory Neil Shapiro goto ok;
57740266059SGregory Neil Shapiro }
57840266059SGregory Neil Shapiro break;
57940266059SGregory Neil Shapiro
58040266059SGregory Neil Shapiro /* x ok iff flag still set & 2nd char */
58140266059SGregory Neil Shapiro case 'x': case 'X':
58240266059SGregory Neil Shapiro if (flags & PFXOK && p == buf + 1)
58340266059SGregory Neil Shapiro {
58440266059SGregory Neil Shapiro base = 16; /* if %i */
58540266059SGregory Neil Shapiro flags &= ~PFXOK;
58640266059SGregory Neil Shapiro goto ok;
58740266059SGregory Neil Shapiro }
58840266059SGregory Neil Shapiro break;
58940266059SGregory Neil Shapiro }
59040266059SGregory Neil Shapiro
59140266059SGregory Neil Shapiro /*
59240266059SGregory Neil Shapiro ** If we got here, c is not a legal character
59340266059SGregory Neil Shapiro ** for a number. Stop accumulating digits.
59440266059SGregory Neil Shapiro */
59540266059SGregory Neil Shapiro
59640266059SGregory Neil Shapiro break;
59740266059SGregory Neil Shapiro ok:
59840266059SGregory Neil Shapiro /* c is legal: store it and look at the next. */
59940266059SGregory Neil Shapiro *p++ = c;
60040266059SGregory Neil Shapiro if (--fp->f_r > 0)
60140266059SGregory Neil Shapiro fp->f_p++;
60240266059SGregory Neil Shapiro else if (sm_refill(fp, SM_TIME_FOREVER))
60340266059SGregory Neil Shapiro break; /* SM_IO_EOF */
60440266059SGregory Neil Shapiro }
60540266059SGregory Neil Shapiro
60640266059SGregory Neil Shapiro /*
60740266059SGregory Neil Shapiro ** If we had only a sign, it is no good; push
60840266059SGregory Neil Shapiro ** back the sign. If the number ends in `x',
60940266059SGregory Neil Shapiro ** it was [sign] '0' 'x', so push back the x
61040266059SGregory Neil Shapiro ** and treat it as [sign] '0'.
61140266059SGregory Neil Shapiro */
61240266059SGregory Neil Shapiro
61340266059SGregory Neil Shapiro if (flags & NDIGITS)
61440266059SGregory Neil Shapiro {
61540266059SGregory Neil Shapiro if (p > buf)
61640266059SGregory Neil Shapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
61740266059SGregory Neil Shapiro *(unsigned char *)--p);
61840266059SGregory Neil Shapiro goto match_failure;
61940266059SGregory Neil Shapiro }
62040266059SGregory Neil Shapiro c = ((unsigned char *)p)[-1];
62140266059SGregory Neil Shapiro if (c == 'x' || c == 'X')
62240266059SGregory Neil Shapiro {
62340266059SGregory Neil Shapiro --p;
62440266059SGregory Neil Shapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
62540266059SGregory Neil Shapiro }
62640266059SGregory Neil Shapiro if ((flags & SUPPRESS) == 0)
62740266059SGregory Neil Shapiro {
62840266059SGregory Neil Shapiro ULONGLONG_T res;
62940266059SGregory Neil Shapiro
63040266059SGregory Neil Shapiro *p = 0;
63140266059SGregory Neil Shapiro res = (*ccfn)(buf, (char **)NULL, base);
63240266059SGregory Neil Shapiro if (flags & POINTER)
63340266059SGregory Neil Shapiro *SM_VA_ARG(ap, void **) =
63440266059SGregory Neil Shapiro (void *)(long) res;
63540266059SGregory Neil Shapiro else if (flags & QUAD)
63640266059SGregory Neil Shapiro *SM_VA_ARG(ap, LONGLONG_T *) = res;
63740266059SGregory Neil Shapiro else if (flags & LONG)
63840266059SGregory Neil Shapiro *SM_VA_ARG(ap, long *) = res;
63940266059SGregory Neil Shapiro else if (flags & SHORT)
64040266059SGregory Neil Shapiro *SM_VA_ARG(ap, short *) = res;
64140266059SGregory Neil Shapiro else
64240266059SGregory Neil Shapiro *SM_VA_ARG(ap, int *) = res;
64340266059SGregory Neil Shapiro nassigned++;
64440266059SGregory Neil Shapiro }
64540266059SGregory Neil Shapiro nread += p - buf;
64640266059SGregory Neil Shapiro break;
64740266059SGregory Neil Shapiro
64840266059SGregory Neil Shapiro case CT_FLOAT:
64940266059SGregory Neil Shapiro /* scan a floating point number as if by strtod */
65040266059SGregory Neil Shapiro if (width == 0 || width > sizeof(buf) - 1)
65140266059SGregory Neil Shapiro width = sizeof(buf) - 1;
65240266059SGregory Neil Shapiro flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
65340266059SGregory Neil Shapiro for (p = buf; width; width--)
65440266059SGregory Neil Shapiro {
65540266059SGregory Neil Shapiro c = *fp->f_p;
65640266059SGregory Neil Shapiro
65740266059SGregory Neil Shapiro /*
658*d39bd2c1SGregory Neil Shapiro ** This code mimics the integer conversion
65940266059SGregory Neil Shapiro ** code, but is much simpler.
66040266059SGregory Neil Shapiro */
66140266059SGregory Neil Shapiro
66240266059SGregory Neil Shapiro switch (c)
66340266059SGregory Neil Shapiro {
66440266059SGregory Neil Shapiro
66540266059SGregory Neil Shapiro case '0': case '1': case '2': case '3':
66640266059SGregory Neil Shapiro case '4': case '5': case '6': case '7':
66740266059SGregory Neil Shapiro case '8': case '9':
66840266059SGregory Neil Shapiro flags &= ~(SIGNOK | NDIGITS);
66940266059SGregory Neil Shapiro goto fok;
67040266059SGregory Neil Shapiro
67140266059SGregory Neil Shapiro case '+': case '-':
67240266059SGregory Neil Shapiro if (flags & SIGNOK)
67340266059SGregory Neil Shapiro {
67440266059SGregory Neil Shapiro flags &= ~SIGNOK;
67540266059SGregory Neil Shapiro goto fok;
67640266059SGregory Neil Shapiro }
67740266059SGregory Neil Shapiro break;
67840266059SGregory Neil Shapiro case '.':
67940266059SGregory Neil Shapiro if (flags & DPTOK)
68040266059SGregory Neil Shapiro {
68140266059SGregory Neil Shapiro flags &= ~(SIGNOK | DPTOK);
68240266059SGregory Neil Shapiro goto fok;
68340266059SGregory Neil Shapiro }
68440266059SGregory Neil Shapiro break;
68540266059SGregory Neil Shapiro case 'e': case 'E':
68640266059SGregory Neil Shapiro
68740266059SGregory Neil Shapiro /* no exponent without some digits */
68840266059SGregory Neil Shapiro if ((flags&(NDIGITS|EXPOK)) == EXPOK)
68940266059SGregory Neil Shapiro {
69040266059SGregory Neil Shapiro flags =
69140266059SGregory Neil Shapiro (flags & ~(EXPOK|DPTOK)) |
69240266059SGregory Neil Shapiro SIGNOK | NDIGITS;
69340266059SGregory Neil Shapiro goto fok;
69440266059SGregory Neil Shapiro }
69540266059SGregory Neil Shapiro break;
69640266059SGregory Neil Shapiro }
69740266059SGregory Neil Shapiro break;
69840266059SGregory Neil Shapiro fok:
69940266059SGregory Neil Shapiro *p++ = c;
70040266059SGregory Neil Shapiro if (--fp->f_r > 0)
70140266059SGregory Neil Shapiro fp->f_p++;
70240266059SGregory Neil Shapiro else if (sm_refill(fp, SM_TIME_FOREVER))
70340266059SGregory Neil Shapiro break; /* SM_IO_EOF */
70440266059SGregory Neil Shapiro }
70540266059SGregory Neil Shapiro
70640266059SGregory Neil Shapiro /*
70740266059SGregory Neil Shapiro ** If no digits, might be missing exponent digits
70840266059SGregory Neil Shapiro ** (just give back the exponent) or might be missing
70940266059SGregory Neil Shapiro ** regular digits, but had sign and/or decimal point.
71040266059SGregory Neil Shapiro */
71140266059SGregory Neil Shapiro
71240266059SGregory Neil Shapiro if (flags & NDIGITS)
71340266059SGregory Neil Shapiro {
71440266059SGregory Neil Shapiro if (flags & EXPOK)
71540266059SGregory Neil Shapiro {
71640266059SGregory Neil Shapiro /* no digits at all */
71740266059SGregory Neil Shapiro while (p > buf)
71840266059SGregory Neil Shapiro (void) sm_io_ungetc(fp,
71940266059SGregory Neil Shapiro SM_TIME_DEFAULT,
72040266059SGregory Neil Shapiro *(unsigned char *)--p);
72140266059SGregory Neil Shapiro goto match_failure;
72240266059SGregory Neil Shapiro }
72340266059SGregory Neil Shapiro
72440266059SGregory Neil Shapiro /* just a bad exponent (e and maybe sign) */
72540266059SGregory Neil Shapiro c = *(unsigned char *) --p;
72640266059SGregory Neil Shapiro if (c != 'e' && c != 'E')
72740266059SGregory Neil Shapiro {
72840266059SGregory Neil Shapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
72940266059SGregory Neil Shapiro c); /* sign */
73040266059SGregory Neil Shapiro c = *(unsigned char *)--p;
73140266059SGregory Neil Shapiro }
73240266059SGregory Neil Shapiro (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
73340266059SGregory Neil Shapiro }
73440266059SGregory Neil Shapiro if ((flags & SUPPRESS) == 0)
73540266059SGregory Neil Shapiro {
73640266059SGregory Neil Shapiro double res;
73740266059SGregory Neil Shapiro
73840266059SGregory Neil Shapiro *p = 0;
73940266059SGregory Neil Shapiro res = strtod(buf, (char **) NULL);
74040266059SGregory Neil Shapiro if (flags & LONG)
74140266059SGregory Neil Shapiro *SM_VA_ARG(ap, double *) = res;
74240266059SGregory Neil Shapiro else
74340266059SGregory Neil Shapiro *SM_VA_ARG(ap, float *) = res;
74440266059SGregory Neil Shapiro nassigned++;
74540266059SGregory Neil Shapiro }
74640266059SGregory Neil Shapiro nread += p - buf;
74740266059SGregory Neil Shapiro break;
74840266059SGregory Neil Shapiro }
74940266059SGregory Neil Shapiro }
75040266059SGregory Neil Shapiro input_failure:
75140266059SGregory Neil Shapiro if (evt != NULL)
75240266059SGregory Neil Shapiro sm_clrevent(evt); /* undo our timeout */
75340266059SGregory Neil Shapiro return nassigned ? nassigned : -1;
75440266059SGregory Neil Shapiro match_failure:
75540266059SGregory Neil Shapiro if (evt != NULL)
75640266059SGregory Neil Shapiro sm_clrevent(evt); /* undo our timeout */
75740266059SGregory Neil Shapiro return nassigned;
75840266059SGregory Neil Shapiro }
75940266059SGregory Neil Shapiro
76040266059SGregory Neil Shapiro /*
76140266059SGregory Neil Shapiro ** SM_SCCL -- sequenced character comparison list
76240266059SGregory Neil Shapiro **
76340266059SGregory Neil Shapiro ** Fill in the given table from the scanset at the given format
76440266059SGregory Neil Shapiro ** (just after `['). Return a pointer to the character past the
76540266059SGregory Neil Shapiro ** closing `]'. The table has a 1 wherever characters should be
76640266059SGregory Neil Shapiro ** considered part of the scanset.
76740266059SGregory Neil Shapiro **
76840266059SGregory Neil Shapiro ** Parameters:
76940266059SGregory Neil Shapiro ** tab -- array flagging "active" char's to match (returned)
77040266059SGregory Neil Shapiro ** fmt -- character list (within "[]")
77140266059SGregory Neil Shapiro **
77240266059SGregory Neil Shapiro ** Results:
77340266059SGregory Neil Shapiro */
77440266059SGregory Neil Shapiro
77540266059SGregory Neil Shapiro static unsigned char *
sm_sccl(tab,fmt)77640266059SGregory Neil Shapiro sm_sccl(tab, fmt)
77740266059SGregory Neil Shapiro register char *tab;
77840266059SGregory Neil Shapiro register unsigned char *fmt;
77940266059SGregory Neil Shapiro {
78040266059SGregory Neil Shapiro register int c, n, v;
78140266059SGregory Neil Shapiro
78240266059SGregory Neil Shapiro /* first `clear' the whole table */
78340266059SGregory Neil Shapiro c = *fmt++; /* first char hat => negated scanset */
78440266059SGregory Neil Shapiro if (c == '^')
78540266059SGregory Neil Shapiro {
78640266059SGregory Neil Shapiro v = 1; /* default => accept */
78740266059SGregory Neil Shapiro c = *fmt++; /* get new first char */
78840266059SGregory Neil Shapiro }
78940266059SGregory Neil Shapiro else
79040266059SGregory Neil Shapiro v = 0; /* default => reject */
79140266059SGregory Neil Shapiro
79240266059SGregory Neil Shapiro /* should probably use memset here */
79340266059SGregory Neil Shapiro for (n = 0; n < 256; n++)
79440266059SGregory Neil Shapiro tab[n] = v;
79540266059SGregory Neil Shapiro if (c == 0)
79640266059SGregory Neil Shapiro return fmt - 1; /* format ended before closing ] */
79740266059SGregory Neil Shapiro
79840266059SGregory Neil Shapiro /*
79940266059SGregory Neil Shapiro ** Now set the entries corresponding to the actual scanset
80040266059SGregory Neil Shapiro ** to the opposite of the above.
80140266059SGregory Neil Shapiro **
80240266059SGregory Neil Shapiro ** The first character may be ']' (or '-') without being special;
80340266059SGregory Neil Shapiro ** the last character may be '-'.
80440266059SGregory Neil Shapiro */
80540266059SGregory Neil Shapiro
80640266059SGregory Neil Shapiro v = 1 - v;
80740266059SGregory Neil Shapiro for (;;)
80840266059SGregory Neil Shapiro {
80940266059SGregory Neil Shapiro tab[c] = v; /* take character c */
81040266059SGregory Neil Shapiro doswitch:
81140266059SGregory Neil Shapiro n = *fmt++; /* and examine the next */
81240266059SGregory Neil Shapiro switch (n)
81340266059SGregory Neil Shapiro {
81440266059SGregory Neil Shapiro
81540266059SGregory Neil Shapiro case 0: /* format ended too soon */
81640266059SGregory Neil Shapiro return fmt - 1;
81740266059SGregory Neil Shapiro
81840266059SGregory Neil Shapiro case '-':
81940266059SGregory Neil Shapiro /*
82040266059SGregory Neil Shapiro ** A scanset of the form
82140266059SGregory Neil Shapiro ** [01+-]
82240266059SGregory Neil Shapiro ** is defined as `the digit 0, the digit 1,
82340266059SGregory Neil Shapiro ** the character +, the character -', but
82440266059SGregory Neil Shapiro ** the effect of a scanset such as
82540266059SGregory Neil Shapiro ** [a-zA-Z0-9]
82640266059SGregory Neil Shapiro ** is implementation defined. The V7 Unix
82740266059SGregory Neil Shapiro ** scanf treats `a-z' as `the letters a through
82840266059SGregory Neil Shapiro ** z', but treats `a-a' as `the letter a, the
82940266059SGregory Neil Shapiro ** character -, and the letter a'.
83040266059SGregory Neil Shapiro **
8315b0945b5SGregory Neil Shapiro ** For compatibility, the `-' is not considered
83240266059SGregory Neil Shapiro ** to define a range if the character following
83340266059SGregory Neil Shapiro ** it is either a close bracket (required by ANSI)
83440266059SGregory Neil Shapiro ** or is not numerically greater than the character
83540266059SGregory Neil Shapiro ** we just stored in the table (c).
83640266059SGregory Neil Shapiro */
83740266059SGregory Neil Shapiro
83840266059SGregory Neil Shapiro n = *fmt;
83940266059SGregory Neil Shapiro if (n == ']' || n < c)
84040266059SGregory Neil Shapiro {
84140266059SGregory Neil Shapiro c = '-';
84240266059SGregory Neil Shapiro break; /* resume the for(;;) */
84340266059SGregory Neil Shapiro }
84440266059SGregory Neil Shapiro fmt++;
84540266059SGregory Neil Shapiro do
84640266059SGregory Neil Shapiro {
84740266059SGregory Neil Shapiro /* fill in the range */
84840266059SGregory Neil Shapiro tab[++c] = v;
84940266059SGregory Neil Shapiro } while (c < n);
85040266059SGregory Neil Shapiro #if 1 /* XXX another disgusting compatibility hack */
85140266059SGregory Neil Shapiro
85240266059SGregory Neil Shapiro /*
85340266059SGregory Neil Shapiro ** Alas, the V7 Unix scanf also treats formats
85440266059SGregory Neil Shapiro ** such as [a-c-e] as `the letters a through e'.
85540266059SGregory Neil Shapiro ** This too is permitted by the standard....
85640266059SGregory Neil Shapiro */
85740266059SGregory Neil Shapiro
85840266059SGregory Neil Shapiro goto doswitch;
85940266059SGregory Neil Shapiro #else
86040266059SGregory Neil Shapiro c = *fmt++;
86140266059SGregory Neil Shapiro if (c == 0)
86240266059SGregory Neil Shapiro return fmt - 1;
86340266059SGregory Neil Shapiro if (c == ']')
86440266059SGregory Neil Shapiro return fmt;
86540266059SGregory Neil Shapiro break;
86640266059SGregory Neil Shapiro #endif
86740266059SGregory Neil Shapiro
86840266059SGregory Neil Shapiro case ']': /* end of scanset */
86940266059SGregory Neil Shapiro return fmt;
87040266059SGregory Neil Shapiro
87140266059SGregory Neil Shapiro default: /* just another character */
87240266059SGregory Neil Shapiro c = n;
87340266059SGregory Neil Shapiro break;
87440266059SGregory Neil Shapiro }
87540266059SGregory Neil Shapiro }
87640266059SGregory Neil Shapiro /* NOTREACHED */
87740266059SGregory Neil Shapiro }
878