/* * Alas, doscan is not documented, so people feel they have license to * change the parameters. The 3B implementation does not even look * callable from C, and without documentation is not comprehensible. * Since many systems have their own doprnt which is written in assembly * language, and thus faster, but callable from C, we try to use the * standard system version where possible. The ifdefs below attempt * to decide where it is possible - it may need to be updated later. */ #ifdef u3b #define NEEDDOSCAN #endif #ifdef NEEDDOSCAN /* @(#) doscan.c: 1.1 10/15/83 (1.2 9/29/82) */ /* @(#)doscan.c 2.5 */ /*LINTLIBRARY*/ #include <stdio.h> #include <ctype.h> #include <varargs.h> #include <values.h> #define NCHARS (1 << BITSPERBYTE) extern double atof(); extern char *memset(); extern int ungetc(); int _doscan(iop, fmt, va_alist) register FILE *iop; register unsigned char *fmt; va_list va_alist; { extern unsigned char *setup(); char tab[NCHARS]; register int ch; int nmatch = 0, len, inchar, stow, size; /******************************************************* * Main loop: reads format to determine a pattern, * and then goes to read input stream * in attempt to match the pattern. *******************************************************/ for( ; ; ) { if((ch = *fmt++) == '\0') return(nmatch); /* end of format */ if(isspace(ch)) { while(isspace(inchar = getc(iop))) ; if(ungetc(inchar, iop) != EOF) continue; break; } if(ch != '%' || (ch = *fmt++) == '%') { if((inchar = getc(iop)) == ch) continue; if(ungetc(inchar, iop) != EOF) return(nmatch); /* failed to match input */ break; } if(ch == '*') { stow = 0; ch = *fmt++; } else stow = 1; for(len = 0; isdigit(ch); ch = *fmt++) len = len * 10 + ch - '0'; if(len == 0) len = MAXINT; if((size = ch) == 'l' || size == 'h') ch = *fmt++; if(ch == '\0' || ch == '[' && (fmt = setup(fmt, tab)) == NULL) return(EOF); /* unexpected end of format */ if(isupper(ch)) { /* no longer documented */ size = 'l'; ch = _tolower(ch); } if(ch != 'c' && ch != '[') { while(isspace(inchar = getc(iop))) ; if(ungetc(inchar, iop) == EOF) break; } if((size = (ch == 'c' || ch == 's' || ch == '[') ? string(stow, ch, len, tab, iop, &va_alist) : number(stow, ch, len, size, iop, &va_alist)) != 0) nmatch += stow; if(va_alist == NULL) /* end of input */ break; if(size == 0) return(nmatch); /* failed to match input */ } return(nmatch != 0 ? nmatch : EOF); /* end of input */ } /*************************************************************** * Functions to read the input stream in an attempt to match incoming * data to the current pattern from the main loop of _doscan(). ***************************************************************/ static int number(stow, type, len, size, iop, listp) int stow, type, len, size; register FILE *iop; va_list *listp; { char numbuf[64]; register char *np = numbuf; register int c, base; int digitseen = 0, dotseen = 0, expseen = 0, floater = 0, negflg = 0; long lcval = 0; switch(type) { case 'e': case 'f': case 'g': floater++; case 'd': case 'u': base = 10; break; case 'o': base = 8; break; case 'x': base = 16; break; default: return(0); /* unrecognized conversion character */ } switch(c = getc(iop)) { case '-': negflg++; case '+': /* fall-through */ len--; c = getc(iop); } for( ; --len >= 0; *np++ = c, c = getc(iop)) { if(isdigit(c) || base == 16 && isxdigit(c)) { int digit = c - (isdigit(c) ? '0' : isupper(c) ? 'A' - 10 : 'a' - 10); if(digit >= base) break; if(stow && !floater) lcval = base * lcval + digit; digitseen++; continue; } if(!floater) break; if(c == '.' && !dotseen++) continue; if((c == 'e' || c == 'E') && digitseen && !expseen++) { *np++ = c; c = getc(iop); if(isdigit(c) || c == '+' || c == '-') continue; } break; } if(stow && digitseen) if(floater) { register double dval; *np = '\0'; dval = atof(numbuf); if(negflg) dval = -dval; if(size == 'l') *va_arg(*listp, double *) = dval; else *va_arg(*listp, float *) = (float)dval; } else { /* suppress possible overflow on 2's-comp negation */ if(negflg && lcval != HIBITL) lcval = -lcval; if(size == 'l') *va_arg(*listp, long *) = lcval; else if(size == 'h') *va_arg(*listp, short *) = (short)lcval; else *va_arg(*listp, int *) = (int)lcval; } if(ungetc(c, iop) == EOF) *listp = NULL; /* end of input */ return(digitseen); /* successful match if non-zero */ } static int string(stow, type, len, tab, iop, listp) register int stow, type, len; register char *tab; register FILE *iop; va_list *listp; { register int ch; register char *ptr; char *start; start = ptr = stow ? va_arg(*listp, char *) : NULL; if(type == 'c' && len == MAXINT) len = 1; while((ch = getc(iop)) != EOF && !(type == 's' && isspace(ch) || type == '[' && tab[ch])) { if(stow) *ptr = ch; ptr++; if(--len <= 0) break; } if(ch == EOF || len > 0 && ungetc(ch, iop) == EOF) *listp = NULL; /* end of input */ if(ptr == start) return(0); /* no match */ if(stow && type != 'c') *ptr = '\0'; return(1); /* successful match */ } static unsigned char * setup(fmt, tab) register unsigned char *fmt; register char *tab; { register int b, c, d, t = 0; if(*fmt == '^') { t++; fmt++; } (void)memset(tab, !t, NCHARS); if((c = *fmt) == ']' || c == '-') { /* first char is special */ tab[c] = t; fmt++; } while((c = *fmt++) != ']') { if(c == '\0') return(NULL); /* unexpected end of format */ if(c == '-' && (d = *fmt) != ']' && (b = fmt[-2]) < d) { (void)memset(&tab[b], t, d - b); fmt++; } else tab[c] = t; } return(fmt); } #else /* This is just to keep from getting a diagnostic from ranlib. */ __dsdummy__() { } #endif NEEDDOSCAN