
/*
 *  SFMT.C	*scanf()
 *
 *  (c)Copyright 1990, Matthew Dillon, All Rights Reserved
 *
 *  func format same as fgetc: func(desc)
 *  unfunc format same as ungetc: func(c,desc)
 */

#include <stdarg.h>
#include <stdio.h>

#define F_SPAC	    1
#define F_PLUS	    2
#define F_MINUS     4
#define F_HASH	    8
#define F_ZERO	    16

#define F_SHORT     32
#define F_LONG	    64
#define F_DLONG     128

int
_sfmt(ctl, va, func, unfunc, desc, pcnt)
unsigned char *ctl;
va_list va;
int (*func)();
void (*unfunc)();
int *pcnt;
void *desc;
{
    int error = 0;
    short flags;
    short v;
    short i1;
    void *stor;

    *pcnt = 0;
    v = (*func)(desc);
    for (;;) {
	while (*ctl && *ctl != '%') {
	    if (*ctl == ' ') {
		if (v != ' ' && v != '\t' && v != '\n')
		    goto done;
		while (v == ' ' || v == '\t' || v == '\n')
		    v = (*func)(desc);
		while (*ctl == ' ')
		    ++ctl;
	    } else {
		if (v != *ctl)
		    goto done;
		v = (*func)(desc);
		++ctl;
	    }
	    if (v == 0)
		goto done;
	}
	if (*ctl++ == 0)
	    goto done;
	if (*ctl == '%') {      /*  match a %   */
	    if (v != '%')
		goto done;
	    v = (*func)(desc);
	    ++ctl;
	    continue;
	}

	/*
	 *  %[flags][width]c
	 */

	if (*ctl == '*') {
	    stor = NULL;
	    ++ctl;
	} else {
	    stor = *va_arg(va, void *);
	}
	i1 = -1;
	if (*ctl >= '0' && *ctl <= '9') {
	    char c = *ctl;
	    i1 = 0;
	    while (c >= '0' && c <= '9') {
		i1 = i1 * 10 + (c - '0');
		c = *++ctl;
	    }
	}
	flags = 0;
	for (;;) {
	    char c = *ctl;
	    if (c == 'h') {
		++ctl;
		flags |= F_SHORT;   /*	only if sizeof(int) != 4 */
		continue;
	    }
	    if (c == 'l') {
		++ctl;
		flags |= F_LONG;
		continue;
	    }
	    if (c == 'L') {
		++ctl;
		flags |= F_DLONG;
		continue;
	    }
	    break;
	}
	error = _sfmtone(*ctl++, &v, stor, func, desc, flags, i1);
	if (error)
	    break;
	++*pcnt;
    }
done:
    if (v != EOF)
	(*unfunc)(v, desc);

    if (error && *pcnt == 0)
	return(EOF);
    return(0);
}

_sfmtone(c, pv, stor, func, desc, flags, i1)
char c; 	/*  conversion specifier    */
short *pv;	/*  last read value	    */
void *stor;	/*  pointer into storage    */
int (*func)();  /*  fgetc type function     */
void *desc;	/*  stdio/custom descriptor */
short flags;	/*  conversion flags	    */
short i1;	/*  maximum field width     */
{
    short v = *pv;
    int len = 0;
    char buf[32];
    char *ptr = buf;

    while (v == ' ' || v == '\t' || v == '\n')
	v = (*func)(desc);

    if (i1 == 0)
	return(0);
    if (v == 0 || v == EOF)
	return(EOF);

    switch(c) {
    case 'c':
	if (i1 == -1)
	    i1 = 1;
	while (v != EOF && v != '\n' && i1) {
	    if (stor)
		*(char *)stor = v;
	    v = (*func)(desc);
	    if (stor)
		stor = (void *)((char *)stor + 1);
	    --i1;
	}
	break;
    case 'd':
    case 'u':
	{
	    long n = 0;
	    short neg = 0;

	    if (v != '-' && (v < '0' || v > '9'))
		return(EOF);

	    if (v == '-') {
		neg = 1;
		v = (*func)(desc);
		--i1;
	    }
	    while (i1 && v >= '0' && v <= '9') {
		n = n * 10 + v - '0';
		v = (*func)(desc);
		--i1;
	    }
	    if (neg)
		n = -n;
	    if (stor)
		*(int *)stor = n;
	}
	break;
    case 'e':
    case 'E':
    case 'f':
    case 'g':
    case 'G':
    case 'i':
    case 'n':
	break;
    case 'o':
	{
	    long n = 0;
	    short neg = 0;

	    if (v != '-' && (v < '0' || v > '7'))
		return(EOF);
	    if (v == '-') {
		neg = 1;
		v = (*func)(desc);
		--i1;
	    }
	    while (i1 && v >= '0' && v <= '7') {
		n = (n << 3) + v - '0';
		v = (*func)(desc);
		--i1;
	    }
	    if (neg)
		n = -n;
	    if (stor)
		*(int *)stor = n;
	}
	break;
    case 'p':
	break;
    case 's':
	while (i1 && v != ' ' && v != '\t' && v != '\n' && v != EOF) {
	    if (stor)
		*(char *)stor = v;
	    v = (*func)(desc);
	    if (stor)
		stor = (void *)((char *)stor + 1);
	    --i1;
	}
	if (stor)
	    *(char *)stor = 0;
	break;
    case 'x':
    case 'X':
	{
	    long n = 0;
	    short neg = 0;
	    long oldi1 = i1;

	    if (v == '-') {
		neg = 1;
		v = (*func)(desc);
		--i1;
	    }
	    while (i1) {
		if (v >= '0' && v <= '9') {
		    n = (n << 4) + v - '0';
		} else if (v >= 'a' && v <= 'f') {
		    n = (n << 4) + v - 'a' + 10;
		} else if (v >= 'A' && v <= 'F') {
		    n = (n << 4) + v - 'A' + 10;
		} else {
		    break;
		}
		v = (*func)(desc);
		--i1;
	    }
	    if (i1 == oldi1)    /*  nada    */
		return(EOF);
	    if (neg)
		n = -n;
	    if (stor)
		*(int *)stor = n;
	}
	break;
    default:
	return(-2);
    }
    *pv = v;
    return(0);
}

