#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, argp) register FILE *iop; char *format; /* the format control string */ union ptr_union *argp; /* our argument list */ { 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); ++done; 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 = (tolower (*format) == 'l')) ++format; else if (shortflag = (tolower(*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) *(argp++)->ulong_p = (unsigned long) val; else if (shortflag) *(argp++)->ushort_p = (unsigned short) val; else *(argp++)->uint_p = (unsigned) val; } if (done_some) ++done; else goto all_done; break; case 'c': if (!widflag) width = 1; while (width-- && ic >= 0) { if (do_assign) *(argp)->chr_p++ = (char) ic; ic = getc(iop); done_some = 1; } if (do_assign) argp++; /* done with this one */ if (done_some) ++done; break; case 's': if (!widflag) width = 0xffff; while (width-- && !isspace (ic) && ic > 0) { if (do_assign) *(argp)->chr_p++ = (char) ic; ic = getc(iop); done_some = 1; } if (do_assign) /* terminate the string */ *(argp++)->chr_p = '\0'; if (done_some) ++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; while (width-- && !isspace (ic) && ic > 0 && (Xtable[ic] ^ reverse)) { if (do_assign) *(argp)->chr_p++ = (char) ic; ic = getc(iop); done_some = 1; } if (do_assign) /* terminate the string */ *(argp++)->chr_p = '\0'; if (done_some) ++done; else goto all_done; break; #ifndef NOFLOAT: case 'e': case 'f': { register char *c = buffer; 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; done++; if (do_assign) { if (longflag) *(argp++)->double_p = atof(buffer); else *(argp++)->float_p = atof(buffer); } } break; #endif } /* end switch */ ++format; } all_done: if (ic >= 0) ungetc(ic, iop); quit: return done; }