/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1996, by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* System V.2 Emulation Stdio Library -- vfscanf
*
* Copyright 1985, 1992 by Mortice Kern Systems Inc. All rights reserved.
*
*/
#ifdef M_RCSID
#ifndef lint
#endif
#endif
#include <mks.h>
#include <ctype.h>
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#ifdef __FLOAT__
#include <math.h>
#endif
#define NOBASE 0
#define UNSIGNED 0
struct lexlist {
char name;
char type;
};
'*', STAR,
'%', PERCENT,
'l', MODCONVL,
'h', MODCONVH,
'n', NSCAN,
'[', BRACKET,
'd', CONVTYPE,
's', CONVTYPE,
'u', CONVTYPE,
'c', CONVTYPE,
'x', CONVTYPE,
'o', CONVTYPE,
'0', NUMBER,
'1', NUMBER,
'2', NUMBER,
'3', NUMBER,
'4', NUMBER,
'5', NUMBER,
'6', NUMBER,
'7', NUMBER,
'8', NUMBER,
'9', NUMBER,
'i', CONVTYPE,
'f', CONVTYPE,
'e', CONVTYPE,
'g', CONVTYPE,
0, 0
};
static int scan(int, const char *, const char *);
static int gettoken(void);
static void whitespace(void);
static int match(const char *, char *);
static long unsigned getnum(int, int, int);
static int getin(void);
static void unget(int);
#ifdef __FLOAT__
static double lstrtod(void);
#endif
/*
* Convert formatted input from given input.
* This is the workhorse for scanf, sscanf, and fscanf.
* Returns the number of matched and assigned input items.
*/
int
{
int nitems;
int ltoken;
int c;
from = 'X';
nitems = 0;
charcnt = 0;
for (;;) {
if (from == 'X') {
pflag = 0;
modconv = 0;
suppression = 0;
width = 0;
}
switch (ltoken) {
case 0:
goto retitems;
case MODCONVL:
case MODCONVH:
switch (from) {
case 'A':
case 'D':
case 'P':
from = 'E';
break;
default:
from = 'X';
break;
}
break;
case CONVTYPE:
switch (from) {
int intassign;
case 'E':
case 'P':
case 'D':
case 'A':
from = 'X';
intassign = 1;
pflag = 0;
case 'd':
if (gfail)
goto retitems;
break;
case 'u':
if (gfail)
goto retitems;
break;
case 'x':
if (gfail)
goto retitems;
break;
case 'o':
if (gfail)
goto retitems;
break;
case 'i':
if (gfail)
goto retitems;
break;
case 'c':
/* 'S' dummy entry (for multibyte characters) */
case 'S':
case 's': {
int gotitem = 0;
char *str;
if (!suppression)
/* Input whitespace is not skipped
* for %c, which implies that %c
* can return whitespace.
*/
whitespace();
for (;;) {
c = getin();
/* Only %s and %S stop on
* whitespace.
*/
unget(c);
break;
}
if (c == EOF) {
if(!gotitem)
goto retitems;
break;
}
gotitem = 1;
if (!suppression)
*str++ = c;
if (width) {
if (--width == 0)
break;
}
}
/*
* ANSI C states that %c does not
* terminate with a null character.
*/
*str = '\0';
intassign = 0;
break;
}
#ifdef __FLOAT__
case 'f':
case 'g':
case 'e': {
double fresult;
if(gfail)
goto retitems;
if(suppression)
break;
else
/*FALLTHROUGH*/
}
#else /* !__FLOAT__ */
case 'f':
case 'g':
case 'e':
#endif /* __FLOAT__ */
default:
intassign = 0;
break;
}
if (suppression)
break;
else
nitems++;
if (intassign == 0)
break;
switch (modconv) {
case MODCONVH:
break;
case MODCONVL:
break;
default:
break;
}
break;
default:
from = 'X';
break;
}
break;
case STAR:
if (from == 'P') {
from = 'A';
suppression = 1;
} else {
from = 'X';
}
break;
case PERCENT:
if (from == 'P') {
from = 'X';
pflag = 0;
c = getin();
if (c != '%')
goto retitems;
} else {
from = 'X';
}
break;
case NUMBER:
from = 'D';
} else {
from = 'X';
}
break;
case NSCAN:
if (from == 'P') {
pflag = 0;
if (!suppression) {
}
}
from = 'X';
break;
case BRACKET:
switch (from) {
case 'A':
case 'D':
case 'P': {
char *ptr;
pflag = 0;
if (width == 0)
&& !suppression)
nitems++;
while (*fmtptr++ != ']')
;
break;
}
default:
break;
}
from = 'X';
break;
default:
c = *(fmtptr-1);
if (c == ' ' || c == '\t' || c == '\n' || c == '\f')
whitespace();
else {
c = getin();
if (c != *(fmtptr-1))
goto retitems;
}
from = 'X';
break;
}
}
}
}
static int
gettoken()
{
char c;
if (*fmtptr == 0)
return 0; /* return 0 for end of string */
c = *fmtptr++;
if (pflag) {
fmtptr++;
} else if (c == 'c') {
/* No width specified for %c, default
* is one.
*/
width = 1;
}
}
}
return -1;
}
if (c == '%') {
pflag = 1;
from = 'P';
return gettoken();
}
return -1;
}
static void
{
register int c;
do {
c = getin();
} while (isspace(c));
unget(c);
}
static int
{
return 1;
return 0;
}
static int
{
int complement;
int i;
int c;
if (*str == '^') {
complement = 1;
str++;
} else
complement = 0;
end = 0;
if (*str == '-') {
}
while (*str++ != ']')
;
for (i=0; i<width; i++) {
return 0;
break;
*outstr++ = c;
}
} else {
for (i=0; i<width; i++) {
c = getin();
if (complement) {
break;
*outstr++ = c;
} else {
break;
*outstr++ = c;
}
}
}
if (i < width)
unget(c);
*outstr = '\0';
return (i > 1);
}
/*
* Get a number from the input stream.
* The base, if zero, will be determined by the nature of the number.
* A leading 0x means hexadecimal, a leading 0 for octal, otherwise decimal.
*
* if the width is 0 then the max input string length of number is used.
*
* The sign tell us that a signed number is expected (rather than the
* 'u' conversion type which is unsigned).
*/
static long unsigned
{
char *s;
int w;
register int c;
int neg;
long ret;
gfail = 0;
whitespace();
if (width == 0)
neg = 0;
if (sign) {
c = getin();
if (c == '+' || c == '-')
else
unget(c);
}
if (base == 0) {
base = 10;
c = getin();
if (c == '0') {
base = 8;
c = getin();
if (c == 'X' || c == 'x')
base = 16;
else
unget(c);
} else
unget(c);
}
if (base == 10) {
w = 0;
s = cbuf;
c = getin();
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
*s++ = c;
w++;
continue;
default:
unget(c);
w = width; /* force end of loop */
break;
}
}
*s = '\0';
goto retn;
}
if (base == 8) {
w = 0;
s = cbuf;
c = getin();
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
*s++ = c;
w++;
continue;
default:
unget(c);
w = width; /* force end of loop */
break;
}
}
*s = '\0';
goto retn;
}
if (base == 16) {
w = 0;
s = cbuf;
c = getin();
c = toupper(c);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
*s++ = c;
w++;
continue;
default:
unget(c);
w = width; /* force end of loop */
break;
}
}
*s = '\0';
goto retn;
}
/*
* if we get this far then a bad base was passed.
*/
gfail = -1;
retn:
gfail = -1;
if (neg)
return ret;
}
#ifdef __FLOAT__
static double
lstrtod()
{
int slen;
register int c;
gfail = 0;
whitespace();
c = getin();
if (c == '-' || c == '+')
if (c == '-') {
neg = -1;
c = getin();
}
while (c >= '0' && c <= '9') {
*sp++ = c;
c = getin();
}
if (c == '.') {
c = getin();
while (c >= '0' && c <= '9') {
*sp++ = c;
c = getin();
}
}
if (c == 'e' || c == 'E') {
c = getin();
if (c == '-' || c == '+')
if (c == '-') {
eneg = -1;
c = getin();
}
while (c >= '0' && c <= '9') {
*sp++ = c;
c = getin();
}
}
*sp = '\0';
gfail = -1;
return 0.0;
}
unget(c);
/*
* convert the three strings (integer, fraction, and exponent)
* into a floating point number.
*/
total = 0.0;
tens = 1.0;
tens *= 10.0;
}
tens = .1;
tens /= 10.0;
}
exp = 0.0;
tens = 1.0;
tens *= 10.0;
}
}
*sp = '\0';
return total;
}
#endif /* __FLOAT__ */
static int
getin()
{
int c;
c = ungot;
} else
charcnt++;
return c;
}
static void
unget(int c)
{
/* Dont' use ungetc because it doesn't work with m_fsopen */
ungot = c;
charcnt--;
}