/* $Id$ */ #include #include #include union ptr_union { char *chr_p; unsigned short *ushort_p; unsigned int *uint_p; unsigned long *ulong_p; #ifndef NOFLOAT float *float_p; double *double_p; #endif }; static char Xtable[128]; /* * the routine that does the job */ _doscanf (iop, format, ap) register FILE *iop; char *format; /* the format control string */ va_list ap; { int done = 0; /* number of items done */ int base; /* conversion base */ long val; /* an integer value */ int sign; /* sign flag */ int do_assign; /* assignment suppression flag */ unsigned width; /* width of field */ int widflag; /* width was specified */ int longflag; /* true if long */ int shortflag; /* true if short */ int done_some; /* true if we have seen some data */ int reverse; /* reverse the checking in [...] */ int kind; register int ic; #ifndef NOFLOAT extern double atof(); int dotseen; int expseen; char buffer[128]; #endif ic = getc(iop); if (ic == EOF) { done = EOF; goto quit; } while (1) { if (isspace(*format)) { while (isspace (*format)) ++format; /* skip whitespace */ while (isspace (ic)) ic = getc(iop); } if (!*format) goto all_done; /* end of format */ if (ic < 0) goto quit; /* seen an error */ if (*format != '%') { if (ic != *format) goto all_done; ++format; ic = getc(iop); continue; } ++format; do_assign = 1; if (*format == '*') { ++format; do_assign = 0; } if (isdigit (*format)) { widflag = 1; for (width = 0; isdigit (*format);) width = width * 10 + *format++ - '0'; } else widflag = 0; /* no width spec */ if (longflag = (*format == 'L' || *format == 'l')) ++format; else if (shortflag = (*format == 'H' || *format == 'h')) ++format; if (isupper(*format)) { kind = tolower(*format); longflag = 1; } else kind = *format; if (kind != 'c') while (isspace (ic)) ic = getc(iop); done_some = 0; /* nothing yet */ switch (kind) { case 'o': base = 8; goto decimal; case 'u': case 'd': base = 10; goto decimal; case 'x': base = 16; if (((!widflag) || width >= 2) && ic == '0') { ic = getc(iop); if (tolower (ic) == 'x') { width -= 2; done_some = 1; ic = getc(iop); } else { ungetc(ic, iop); ic = '0'; } } decimal: val = 0L; /* our result value */ sign = 0; /* assume positive */ if (!widflag) width = 0xffff; /* very wide */ if (width && ic == '+') ic = getc(iop); else if (width && ic == '-') { sign = 1; ic = getc(iop); } while (width--) { if (isdigit (ic) && ic - '0' < base) ic -= '0'; else if (base == 16 && tolower (ic) >= 'a' && tolower (ic) <= 'f') ic = 10 + tolower (ic) - 'a'; else break; val = val * base + ic; ic = getc(iop); done_some = 1; } if (do_assign) { if (sign) val = -val; if (longflag) *va_arg(ap, unsigned long *) = (unsigned long) val; else if (shortflag) *va_arg(ap, unsigned short *) = (unsigned short) val; else *va_arg(ap, unsigned *) = (unsigned) val; } if (done_some) { if (do_assign) ++done; } else goto all_done; break; case 'c': if (!widflag) width = 1; { register char *p; if (do_assign) p = va_arg(ap, char *); while (width-- && ic >= 0) { if (do_assign) *p++ = (char) ic; ic = getc(iop); done_some = 1; } } if (do_assign) { if (done_some) ++done; } break; case 's': if (!widflag) width = 0xffff; { register char *p; if (do_assign) p = va_arg(ap, char *); while (width-- && !isspace (ic) && ic > 0) { if (do_assign) *p++ = (char) ic; ic = getc(iop); done_some = 1; } if (do_assign) /* terminate the string */ *p = '\0'; } if (done_some) { if (do_assign) ++done; } else goto all_done; break; case '[': if (!widflag) width = 0xffff; if ( *(++format) == '^' ) { reverse = 1; format++; } else reverse = 0; { register char *c; for (c = Xtable; c < &Xtable[128]; c++) *c = 0; } while (*format && *format != ']') { Xtable[*format++] = 1; } if (!*format) goto quit; { register char *p; if (do_assign) p = va_arg(ap, char *); while (width-- && !isspace (ic) && ic > 0 && (Xtable[ic] ^ reverse)) { if (do_assign) *p++ = (char) ic; ic = getc(iop); done_some = 1; } if (do_assign) /* terminate the string */ *p = '\0'; } if (done_some) { if (do_assign) ++done; } else goto all_done; break; #ifndef NOFLOAT: case 'e': case 'f': { register char *c = buffer; if (!widflag) width = 127; if (width >= 128) width = 127; if (width && (ic == '+' || ic == '-')) { *c++ = ic; width--; ic = getc(iop); } while (isdigit(ic) && width) { width--; *c++ = ic; ic = getc(iop); } if (ic == '.' && width) { width--; *c++ = ic; ic = getc(iop); } while (isdigit(ic) && width) { width--; *c++ = ic; ic = getc(iop); } if (width && (ic == 'e' || ic == 'E')) { width--; *c++ = ic; ic = getc(iop); if (width && (ic == '+' || ic == '-')) { width--; *c++ = ic; ic = getc(iop); } } while (isdigit(ic) && width) { width--; *c++ = ic; ic = getc(iop); } if (c == buffer) goto all_done; *c = 0; if (do_assign) { done++; if (longflag) *va_arg(ap, double *) = atof(buffer); else *va_arg(ap, float *) = atof(buffer); } } break; #endif } /* end switch */ ++format; } all_done: if (ic >= 0) ungetc(ic, iop); quit: return done; }