
#include <stdio.h>

#define MAXINT	32767	/* maximum size integer */
#define MAXLINE 128
#define MAXSCAN 128
/* Read formatted input from stdin */
scanf(nargs)
	{
	return (_scan(stdin, &nargs + nargs));
	}
/* Read formatted input from a file */
fscanf(nargs)
	{
	register *p;

	p = &nargs + nargs;		/* first arg (file ptr) */
	return (_scan(*p, p - 1));	/* _scan does the work */
	}
/* Internal routine for scanf/fscanf */
_scan(fp, pargs)
register FILE *fp;
register char **pargs;
	{
	char ss[MAXSCAN+1], *index();
	static char *fmt, *s;
	static count, c, f, include, present, quit, suppress, width,
		base, d, maxd, sign, value;

	fmt = *pargs;
	count = 0;
	quit = FALSE;
	while (f = *fmt++) {
		if (isspace(f)) 	/* skip white space in format */
			continue;
		if (f != '%') { 	/* must match next input string */
			while (isspace(c=getc(fp)))
				;
			if (f == c)
				continue;
			else {		/* doesn't match so put it back */
				ungetc(c, fp);
				break;
				}
			}
		if (*fmt == '*') {
			suppress = TRUE;
			++fmt;
			}
		else
			suppress = FALSE;
		width = (isdigit(*fmt))? _atoi(&fmt): -1;
		if (*fmt == 'h')	/* ignore short int modifier */
			++fmt;
		switch (chupper(*fmt++)) {
		case '%':
			while (isspace(c=getc(fp)))
				;
			if (c == '%')
				continue;
			else {
				quit = TRUE;
				break;
				}
		case '[':
			if (*fmt != '^')
				include = TRUE; /* include chars in [] */
			else {
				include = FALSE;
				++fmt;
				}
			for (d = 0; d < MAXSCAN; ++d) {
				f = *fmt++;	/* get char to incl/excl */
				if (f == ']')
					break;
				else if (f == '\0') {
					quit = TRUE;
					break;
					}
				else
					ss[d] = f;
				}
			ss[d] = '\0';
			if (quit)
				break;		/* format didn't end with ] */
			while (isspace(c=getc(fp)))
				;
			if (c == EOF)
				break;
			if (!suppress) {
				++count;
				s = *--pargs;
				}
			while (width--) {
				present = (index(ss, c) != NULL);
				if ((include && !present)
				   || (!include && present))
					break;	/* doesn't meet %[s] */
				if (!suppress)
					*s++ = c;
				if ((c = getc(fp)) == EOF)
					break;	/* end of input string */
				}
			if (!suppress)
				*s = '\0';
			break;
		case 'X':
			base = 16;
			maxd = 'F';
			sign = 1;
			goto getnum;
		case 'O':
			base = 8;
			maxd = '7';
			sign = 1;
			goto getnum;
		case 'D':
			base = 10;
			maxd = '9';
			while (isspace(c=getc(fp)))
				;
			if (c == '-') {
				sign = -1;
				c = getc(fp);
				}
			else
				sign = 1;
			goto getnum1;
		getnum:
			while (isspace(c=getc(fp)))
				;
		getnum1:
			d = chupper(c);
			if (isalnum(d) && d <= maxd) {
				if (!suppress)
					++count;
				}
			else {
				quit = TRUE;
				break;
				}
			value = 0;
			while (width--) {
				d = chupper(c);
				if (isdigit(d) && d <= maxd)
					d -= '0';
				else if (isalpha(d) && d <= maxd)
					d -= ('A' - 10);
				else
					break;
				value = base * value + d;
				c = getc(fp);
				}
			if (!suppress)
				*(int *)*--pargs = sign * value;
			break;
		case 'C':
			if ((c=getc(fp)) == EOF)
				break;
			if (suppress) {
				if (width == -1)
					continue; /* no char to unget */
				while (width--) {
					if ((c=getc(fp)) == EOF)
						break;
					}
				break;
				}
			++count;
			if (width == -1) { /* get single char */
				**--pargs = c;
				continue;
				}
			else {		/* get string */
				s = *--pargs;
				while (width--) {
					*s++ = c;
					if ((c=getc(fp)) == EOF)
						break;
					}
				*s = '\0';
				}
			break;
		case 'S':
			while (isspace(c=getc(fp)))
				;
			if (c == EOF)
				break;
			if (!suppress) {
				++count;
				s = *--pargs;
				}
			while (width--) {
				if (!suppress)
					*s++ = c;
				if (isspace(c=getc(fp)) || c == EOF)
					break;
				}
			if (!suppress)
				*s = '\0';
			break;
		default:		/* can't figure this out */
			quit = TRUE;
			break;
			}
		if (c == EOF)
			break;
		else
			ungetc(c, fp);	/* put back unused character */
		if (quit == TRUE)
			break;
		}
	return ((count == 0 && c == EOF)? EOF: count);
	}
