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 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; 113*5b0945b5SGregory 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 /* 65840266059SGregory Neil Shapiro ** This code mimicks 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 * 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 ** 831*5b0945b5SGregory 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