int __cdecl fscanf()

in sys/wince/celib.c [541:759]


int __cdecl fscanf(FILE *f, const char *format, ...)
{
    /* Format spec:  %[*] [width] [l] type ] */
    int ch;
    int sch;
    int matched = 0;
    int width = 65535;
    int modifier = -1;
    int skip_flag = 0;
    int n_read = 0;
    char buf[BUFSZ];
    TCHAR wbuf[BUFSZ];
    char *p;
    va_list args;

#define RETURN_SCANF(i) \
    {                   \
        va_end(args);   \
        return i;       \
    }
#define NEXT_CHAR(f) (n_read++, fgetc(f))

    va_start(args, format);

    ch = *format++;
    sch = NEXT_CHAR(f);
    while (ch && sch != EOF) {
        if (isspace(ch)) {
            while (ch && isspace(ch))
                ch = *format++;
            while (sch != EOF && isspace(sch))
                sch = NEXT_CHAR(f);
            format--;
            goto next_spec;
        }

        /* read % */
        if (ch != '%') {
            if (sch != ch)
                RETURN_SCANF(matched);
            sch = NEXT_CHAR(f);
            goto next_spec;
        } else {
            /* process '%%' */
            ch = *format++;
            if (ch == '%') {
                if (sch != '%')
                    RETURN_SCANF(matched);
                sch = NEXT_CHAR(f);
                goto next_spec;
            }

            if (ch == '*') {
                /* read skip flag - '*' */
                skip_flag = 1;
                ch = *format++;
            }

            /* get width */
            if (isdigit(ch)) {
                width = 0;
                while (ch && isdigit(ch)) {
                    width = width * 10 + (ch - '0');
                    ch = *format++;
                }
            }

            /* get modifier */
            if (ch == 'l') {
                modifier = 'l';
                ch = *format++;
            }

            /* get type */
            switch (ch) {
            case 'c':
                if (!skip_flag) {
                    *(va_arg(args, char *) ) = sch;
                    matched++;
                }
                sch = NEXT_CHAR(f);
                goto next_spec;
            case 'd':
                p = buf;
                /* skip space */
                while (sch != EOF && isspace(sch))
                    sch = NEXT_CHAR(f);
                while (sch != EOF && isdigit(sch) && --width >= 0) {
                    *p++ = sch;
                    sch = NEXT_CHAR(f);
                }
                *p = '\x0';
                if (!skip_flag) {
                    matched++;
                    if (modifier == 'l') {
                        *(va_arg(args, long *) ) =
                            wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 10);
                    } else {
                        *(va_arg(args, int *) ) =
                            wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 10);
                    }
                }
                goto next_spec;
            case 'x':
                p = buf;
                while (sch != EOF && isspace(sch))
                    sch = NEXT_CHAR(f);
                while (sch != EOF && isxdigit(sch) && --width >= 0) {
                    *p++ = sch;
                    sch = NEXT_CHAR(f);
                }
                *p = '\x0';
                if (!skip_flag) {
                    matched++;
                    if (modifier == 'l') {
                        *(va_arg(args, long *) ) =
                            wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 16);
                    } else {
                        *(va_arg(args, int *) ) =
                            wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 16);
                    }
                }
                goto next_spec;
            case 'n':
                *(va_arg(args, int *) ) = n_read;
                matched++;
                goto next_spec;
            case 's':
                if (skip_flag) {
                    while (sch != EOF && !isspace(sch) && --width >= 0) {
                        sch = NEXT_CHAR(f);
                    }
                } else {
                    p = va_arg(args, char *);
                    while (sch != EOF && !isspace(sch) && --width >= 0) {
                        *p++ = sch;
                        sch = NEXT_CHAR(f);
                    }
                    *p = '\x0';
                    matched++;
                }
                goto next_spec;
            case '[': {
                char pattern[256];
                int start, end;
                int negate;

                ZeroMemory(pattern, sizeof(pattern));
                p = pattern;

                /* try to parse '^' modifier */
                ch = *format++;
                if (ch == '^') {
                    negate = 1;
                    ch = *format++;
                } else {
                    negate = 0;
                }
                if (ch == 0)
                    RETURN_SCANF(EOF);

                for (; ch && ch != ']'; ch = *format++) {
                    /* try to parse range: a-z */
                    if (format[0] == '-' && format[1] && format[1] != ']') {
                        start = ch;
                        format++;
                        end = *format++;
                        while (start <= end) {
                            if (!strchr(pattern, (char) start))
                                *p++ = (char) start;
                            start++;
                        }
                    } else {
                        if (!strchr(pattern, (char) ch))
                            *p++ = (char) ch;
                    }
                }

                if (skip_flag) {
                    while (sch != EOF && strchr(pattern, sch)
                           && --width >= 0) {
                        sch = NEXT_CHAR(f);
                    }
                } else {
                    p = va_arg(args, char *);
                    if (negate)
                        while (sch != EOF && !strchr(pattern, sch)
                               && --width >= 0) {
                            *p++ = sch;
                            sch = NEXT_CHAR(f);
                        }
                    else
                        while (sch != EOF && strchr(pattern, sch)
                               && --width >= 0) {
                            *p++ = sch;
                            sch = NEXT_CHAR(f);
                        }
                    *p = '\x0';
                    matched++;
                }
            }
                goto next_spec;
            default:
                RETURN_SCANF(EOF);
            }
        }

    next_spec:
        width = 65535;
        modifier = -1;
        skip_flag = 0;
        ch = *format++;
    }
    fseek(f, -1, SEEK_CUR);
    RETURN_SCANF(matched);

#undef RETURN_SCANF
#undef NEXT_CHAR
}