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