Page 159
Write a private version of scanf
analogous to minprintf
from the previous
section.
#include <stdbool.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#define MAX_FMT 100
enum state { NORMAL, FORMAT };
int minscanf(char *fmt, ...)
{
va_list ap;
char scanf_fmt[MAX_FMT];
char *p = scanf_fmt;
int c;
int num_found = 0;
bool suppress;
enum state state;
int *iptr;
unsigned *uiptr;
char *cptr;
double *dptr;
va_start(ap, fmt);
for (state = NORMAL; *fmt != '\0' && c != EOF; fmt++) {
switch (state) {
case NORMAL:
if (*fmt == '%') {
state = FORMAT;
*p++ = '%';
} else if ((c = getchar()) != *fmt) {
return num_found;
}
break;
case FORMAT:
suppress = *fmt == '*';
for (; isdigit(*p = *fmt); p++, fmt++)
;
for (; (*p = *fmt) == 'h' || *p == 'l' || *p == 'L';
p++, fmt++)
;
*(p + 1) = '\0';
switch (*p) {
case 'd':
case 'i':
case 'o':
case 'x':
iptr = va_arg(ap, int *);
num_found += scanf(scanf_fmt, iptr);
break;
case 'e':
case 'f':
case 'g':
dptr = va_arg(ap, double *);
num_found += scanf(scanf_fmt, dptr);
break;
case 's':
cptr = va_arg(ap, char *);
num_found += scanf(scanf_fmt, cptr);
break;
case 'u':
uiptr = va_arg(ap, unsigned *);
num_found += scanf(scanf_fmt, uiptr);
break;
default:
return num_found;
}
state = NORMAL;
break;
}
}
va_end(ap);
return num_found;
}
int main()
{
/* Has not been tested with other inputs and does not have any error handling. */
int i = 0;
int count = minscanf("Hello %d world", &i);
printf("%d %d\n", count, i);
}