/* * d o s c a n . c */ /*)LIBRARY */ #ifdef DOCUMENTATION title c_doscan Formatted Input Processor index Formatted input processor synopsis .s.nf int c_doscan(iop, fmt, args) FILE *iov; /* File descriptor */ char *fmt; /* Format string */ int *arg[]; /* Arg vector */ .s.f Description c_doscan() does parsing for scanf(), etc. See the description of scanf() for more details. c_doscan() returns the number of items matched. Bugs Character classes and float/double are not supported. #endif #include #include #define FALSE 0 #define TRUE 1 #define EOS 0 #define HUGE 32767 /* Infinite width field */ typedef char * POINTER; int c_doscan(fd, format, args) FILE *fd; register char *format; POINTER *args; { register int c; /* Current character */ int nmatch; /* Nbr. formats matched */ int len; /* Field size */ register POINTER store_ptr; /* -> result storage */ int fileended; /* TRUE at eof */ extern int convert(); nmatch = 0; fileended = FALSE; for (;;) { switch (c = *format++) { case EOS: /* End of format */ return (nmatch); case '%': /* Format starts */ if ((c = *format++) == '%') /* But, "%%" is a char */ goto any_char; if (c == '*') { /* '*' means don't */ store_ptr = NULL; /* store a result. */ c = *format++; } else { store_ptr = *args++; } len = 0; /* Get field lenth */ while (isdigit(c)) { len = len*10 + (c - '0'); c = *format++; } if (len == 0) len = HUGE; /* Big field */ if (c == 'l' || c == 'L') { /* Long? */ c = *format++; if (islower(c)) c = toupper(c); } if (c == EOS) /* Format stopped in */ return (-2); /* mid-stream, so die */ if (convert(store_ptr, c, len, fd, &fileended) != FALSE && store_ptr != NULL) nmatch++; /* Count a conversion */ if (fileended) return ((nmatch) ? nmatch : -1); break; case ' ': case '\n': case '\t': break; /* Ignore whitespace */ default: /* Random text must */ any_char: /* Match input stream */ if (c != (len = getc(fd))) { return((len == EOF) ? -1 : nmatch); } break; } } } static int convert(store_ptr, type, len, fd, eofptr) POINTER store_ptr; /* Result pointer (or NULL) */ int type; /* Conversion type (character) */ int len; /* Field length */ FILE *fd; /* Input file */ int *eofptr; /* Set TRUE on eof */ /* * Do the actual conversion. */ { register char *np; register int c; register int base; /* -1/0/+1 for 8/10/16 */ int negative; long value; int ndigit; int size; /* TRUE if long */ extern int getstring(); /* * first decide whether it's a string or numeric type */ if (type=='c' || type=='s') { return (getstring(store_ptr, type, len, fd, eofptr)); } /* * else, process a number */ value = 0; ndigit = 0; size = FALSE; if (isupper(type)) { size++; type += ('a' - 'A'); } base = 0; if (type == 'o') --base; else if (type == 'x') ++base; negative = FALSE; while ((c = getc(fd)), isspace(c)) ; if (c == '-') { negative++; c = getc(fd); len--; } else if (c == '+') { len--; c = getc(fd); } while (--len >= 0 && (isdigit(c) || (base > 0 && isxdigit(c)))) { switch (base) { case -1: /* Octal */ value <<= 3; break; case 0: /* Decimal */ value *= 10; break; case 1: /* Hex */ value <<= 4; break; } c -= (isdigit(c)) ? '0' : (islower(c)) ? ('a' - 10) : ('A' - 10); value += c; c = getc(fd); ndigit++; } if (negative) value = (-value); if (c != EOF) { ungetc(c, fd); *eofptr = FALSE; } else { *eofptr = TRUE; } if (store_ptr != NULL && ndigit > 0) { if (size) *((long *) store_ptr) = value; else *((int *) store_ptr) = value; return (TRUE); } else return (FALSE); } static int getstring(store_ptr, type, len, fd, eofptr) register char *store_ptr; /* Result pointer (or NULL) */ int type; /* Conversion type (character) */ int len; /* Field length */ FILE *fd; /* Input file */ int *eofptr; /* Set TRUE on eof */ { register int c; char *store_start; *eofptr = FALSE; store_start = store_ptr; if (type == 'c' && len == HUGE) len = 1; if (type == 'c') c = getc(fd); else { /* * Skip leading whitespace in a string */ while ((c = getc(fd)) != EOF && isspace(c)) ; } while (--len >= 0 && c != EOF) { if (store_ptr != NULL) { *store_ptr++ = c; } c = getc(fd); } if (c != EOF) { ungetc(c, fd); *eofptr = FALSE; } else { *eofptr = TRUE; } if (store_ptr != NULL && store_ptr != store_start) { if (type != 'c') *store_ptr = EOS; return(TRUE); } return (FALSE); }