mirror of
git://git.musl-libc.org/musl
synced 2025-03-06 03:37:29 +00:00
refactor scanf core to use common code path for all string formats
the concept here is that %s and %c are essentially special-cases of %[, with some minimal additional special-casing. aside from simplifying the code and reducing the number of complex code-paths that would need changing to make optimizations later, the main purpose of this change is to simplify addition of the 'm' modifier which causes scanf to allocate storage for the string being read.
This commit is contained in:
parent
a6d272127b
commit
f18846dd3a
@ -88,6 +88,7 @@ int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap)
|
||||
unsigned long long x;
|
||||
long double y;
|
||||
off_t pos = 0;
|
||||
unsigned char scanset[257];
|
||||
|
||||
FLOCK(f);
|
||||
|
||||
@ -170,104 +171,92 @@ int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap)
|
||||
|
||||
switch (t) {
|
||||
case 'C':
|
||||
if (width < 1) width = 1;
|
||||
case 'S':
|
||||
t |= 32;
|
||||
size = SIZE_l;
|
||||
break;
|
||||
case 'c':
|
||||
if (width < 1) width = 1;
|
||||
case 's':
|
||||
if (size == SIZE_l) t &= ~0x20;
|
||||
case 'd': case 'i': case 'o': case 'u': case 'x':
|
||||
case 'a': case 'e': case 'f': case 'g':
|
||||
case 'A': case 'E': case 'F': case 'G': case 'X':
|
||||
case '[': case 'S':
|
||||
case '[': case 's':
|
||||
case 'p': case 'n':
|
||||
if (width < 1) width = 0;
|
||||
break;
|
||||
default:
|
||||
goto fmt_fail;
|
||||
}
|
||||
|
||||
shlim(f, width);
|
||||
|
||||
if (t != 'n') {
|
||||
if (shgetc(f) < 0) goto input_fail;
|
||||
shunget(f);
|
||||
}
|
||||
|
||||
switch (t) {
|
||||
case 'n':
|
||||
if (t == 'n') {
|
||||
store_int(dest, size, pos);
|
||||
/* do not increment match count, etc! */
|
||||
continue;
|
||||
case 'C':
|
||||
wcs = dest;
|
||||
st = (mbstate_t){ 0 };
|
||||
while ((c=shgetc(f)) >= 0) {
|
||||
if (readwc(c, &wcs, &st) < 0)
|
||||
goto input_fail;
|
||||
}
|
||||
if (!mbsinit(&st)) goto input_fail;
|
||||
if (shcnt(f) != width) goto match_fail;
|
||||
break;
|
||||
}
|
||||
|
||||
if (t != '[' && (t|32) != 'c') {
|
||||
shlim(f, 0);
|
||||
while (isspace(shgetc(f)));
|
||||
shunget(f);
|
||||
pos += shcnt(f);
|
||||
}
|
||||
|
||||
shlim(f, width);
|
||||
if (shgetc(f) < 0) goto input_fail;
|
||||
shunget(f);
|
||||
|
||||
switch (t) {
|
||||
case 's':
|
||||
case 'c':
|
||||
if (dest) {
|
||||
s = dest;
|
||||
while ((c=shgetc(f)) >= 0) *s++ = c;
|
||||
} else {
|
||||
while (shgetc(f)>=0);
|
||||
}
|
||||
if (shcnt(f) < width) goto match_fail;
|
||||
break;
|
||||
case '[':
|
||||
s = dest;
|
||||
wcs = dest;
|
||||
|
||||
if (*++p == '^') p++, invert = 1;
|
||||
else invert = 0;
|
||||
|
||||
unsigned char scanset[257];
|
||||
memset(scanset, invert, sizeof scanset);
|
||||
|
||||
scanset[0] = 0;
|
||||
if (*p == '-') p++, scanset[1+'-'] = 1-invert;
|
||||
else if (*p == ']') p++, scanset[1+']'] = 1-invert;
|
||||
for (; *p != ']'; p++) {
|
||||
if (!*p) goto fmt_fail;
|
||||
if (*p=='-' && p[1] && p[1] != ']')
|
||||
for (c=p++[-1]; c<*p; c++)
|
||||
scanset[1+c] = 1-invert;
|
||||
scanset[1+*p] = 1-invert;
|
||||
if (t == 'c' || t == 's') {
|
||||
memset(scanset, -1, sizeof scanset);
|
||||
scanset[0] = 0;
|
||||
if (t == 's') {
|
||||
scanset[1+'\t'] = 0;
|
||||
scanset[1+'\n'] = 0;
|
||||
scanset[1+'\v'] = 0;
|
||||
scanset[1+'\f'] = 0;
|
||||
scanset[1+'\r'] = 0;
|
||||
scanset[1+' '] = 0;
|
||||
}
|
||||
} else {
|
||||
if (*++p == '^') p++, invert = 1;
|
||||
else invert = 0;
|
||||
memset(scanset, invert, sizeof scanset);
|
||||
scanset[0] = 0;
|
||||
if (*p == '-') p++, scanset[1+'-'] = 1-invert;
|
||||
else if (*p == ']') p++, scanset[1+']'] = 1-invert;
|
||||
for (; *p != ']'; p++) {
|
||||
if (!*p) goto fmt_fail;
|
||||
if (*p=='-' && p[1] && p[1] != ']')
|
||||
for (c=p++[-1]; c<*p; c++)
|
||||
scanset[1+c] = 1-invert;
|
||||
scanset[1+*p] = 1-invert;
|
||||
}
|
||||
}
|
||||
|
||||
wcs = 0;
|
||||
s = 0;
|
||||
if (size == SIZE_l) {
|
||||
wcs = dest;
|
||||
st = (mbstate_t){0};
|
||||
while (scanset[(c=shgetc(f))+1]) {
|
||||
if (readwc(c, &wcs, &st) < 0)
|
||||
goto input_fail;
|
||||
}
|
||||
if (!mbsinit(&st)) goto input_fail;
|
||||
s = 0;
|
||||
} else if (s) {
|
||||
} else if ((s = dest)) {
|
||||
while (scanset[(c=shgetc(f))+1])
|
||||
*s++ = c;
|
||||
wcs = 0;
|
||||
} else {
|
||||
while (scanset[(c=shgetc(f))+1]);
|
||||
}
|
||||
shunget(f);
|
||||
if (!shcnt(f)) goto match_fail;
|
||||
if (s) *s = 0;
|
||||
if (t == 'c' && shcnt(f) != width) goto match_fail;
|
||||
if (wcs) *wcs = 0;
|
||||
if (s) *s = 0;
|
||||
break;
|
||||
default:
|
||||
shlim(f, 0);
|
||||
while (isspace(shgetc(f)));
|
||||
shunget(f);
|
||||
pos += shcnt(f);
|
||||
shlim(f, width);
|
||||
if (shgetc(f) < 0) goto input_fail;
|
||||
shunget(f);
|
||||
}
|
||||
|
||||
switch (t) {
|
||||
case 'p':
|
||||
case 'X':
|
||||
case 'x':
|
||||
@ -306,28 +295,6 @@ int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
wcs = dest;
|
||||
st = (mbstate_t){ 0 };
|
||||
while (!isspace(c=shgetc(f)) && c!=EOF) {
|
||||
if (readwc(c, &wcs, &st) < 0)
|
||||
goto input_fail;
|
||||
}
|
||||
shunget(f);
|
||||
if (!mbsinit(&st)) goto input_fail;
|
||||
if (dest) *wcs++ = 0;
|
||||
break;
|
||||
case 's':
|
||||
if (dest) {
|
||||
s = dest;
|
||||
while (!isspace(c=shgetc(f)) && c!=EOF)
|
||||
*s++ = c;
|
||||
*s = 0;
|
||||
} else {
|
||||
while (!isspace(c=shgetc(f)) && c!=EOF);
|
||||
}
|
||||
shunget(f);
|
||||
break;
|
||||
}
|
||||
|
||||
pos += shcnt(f);
|
||||
|
Loading…
Reference in New Issue
Block a user