diff --git a/libc/stdio/vcscanf.c b/libc/stdio/vcscanf.c index 3c784727a..cb890edb4 100644 --- a/libc/stdio/vcscanf.c +++ b/libc/stdio/vcscanf.c @@ -37,18 +37,18 @@ }) #define FP_BUFFER_GROW 48 -#define BUFFER \ - ({ \ - int c = READ; \ - if (fpbufcur >= fpbufsize - 1) { \ - fpbufsize = fpbufsize + FP_BUFFER_GROW; \ - fpbuf = realloc(fpbuf, fpbufsize); \ - } \ - if (c != -1) { \ - fpbuf[fpbufcur++] = c; \ - fpbuf[fpbufcur] = '\0'; \ - } \ - c; \ +#define BUFFER \ + ({ \ + int c = READ; \ + if (fpbufcur >= fpbufsize - 1) { \ + fpbufsize = fpbufsize + FP_BUFFER_GROW; \ + fpbuf = realloc(fpbuf, fpbufsize); \ + } \ + if (c != -1) { \ + fpbuf[fpbufcur++] = c; \ + fpbuf[fpbufcur] = '\0'; \ + } \ + c; \ }) /** @@ -236,8 +236,9 @@ int __vcscanf(int callback(void *), // case 'f': case 'F': case 'g': - case 'G': // floating point number - if (!(charbytes == sizeof(char) || charbytes == sizeof(wchar_t))) { + case 'G': // floating point number + if (!(charbytes == sizeof(char) || + charbytes == sizeof(wchar_t))) { items = -1; goto Done; } @@ -361,7 +362,8 @@ int __vcscanf(int callback(void *), // c = BUFFER; do { bool isdigit = c >= '0' && c <= '9'; - bool isletter = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + bool isletter = + (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); if (!(c == '_' || isdigit || isletter)) { goto Done; } @@ -420,72 +422,76 @@ int __vcscanf(int callback(void *), // goto Done; } } - BufferFloatingPointNumber: - enum { INTEGER, FRACTIONAL, SIGN, EXPONENT } state = INTEGER; - do { - bool isdecdigit = c >= '0' && c <= '9'; - bool ishexdigit = (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); - bool ispoint = c == '.' || c == ','; - bool isdecexp = c == 'e' || c == 'E'; - bool ishexp = c == 'p' || c == 'P'; - bool issign = c == '+' || c == '-'; + BufferFloatingPointNumber: + enum { INTEGER, FRACTIONAL, SIGN, EXPONENT } state = INTEGER; + do { + bool isdecdigit = c >= '0' && c <= '9'; + bool ishexdigit = (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); + bool ispoint = c == '.' || c == ','; + bool isdecexp = c == 'e' || c == 'E'; + bool ishexp = c == 'p' || c == 'P'; + bool issign = c == '+' || c == '-'; - switch (state) { - case INTEGER: - case FRACTIONAL: - if (isdecdigit || (hexadecimal && ishexdigit)) { - goto Continue; - } else if (state == INTEGER && ispoint) { - state = FRACTIONAL; - goto Continue; - } else if (isdecexp || (hexadecimal && ishexp)) { - state = SIGN; - goto Continue; - } else { - goto Break; - } - case SIGN: - if (issign) { - state = EXPONENT; - goto Continue; - } - state = EXPONENT; - // fallthrough - case EXPONENT: - if (isdecdigit) { - goto Continue; - } else { - goto Break; - } - default: + switch (state) { + case INTEGER: + case FRACTIONAL: + if (isdecdigit || (hexadecimal && ishexdigit)) { + goto Continue; + } else if (state == INTEGER && ispoint) { + state = FRACTIONAL; + goto Continue; + } else if (isdecexp || (hexadecimal && ishexp)) { + state = SIGN; + goto Continue; + } else { goto Break; - } - Continue: - continue; - Break: - if (c != -1 && unget) { - unget(c, arg); } - break; - } while ((c = BUFFER) != -1); - GotFloatingPointNumber: - fp = strtod((char *)fpbuf, NULL); - if (!discard) { - ++items; - void *out = va_arg(va, void *); - if (charbytes == sizeof(char)) { - *(float *)out = (float)fp; - } else { - *(double *)out = (double)fp; - } + case SIGN: + if (issign) { + state = EXPONENT; + goto Continue; + } + state = EXPONENT; + // fallthrough + case EXPONENT: + if (isdecdigit) { + goto Continue; + } else { + goto Break; + } + default: + goto Break; } + Continue: + continue; + Break: + if (c != -1 && unget) { + unget(c, arg); + } + break; + } while ((c = BUFFER) != -1); + GotFloatingPointNumber: + fp = strtod((char *)fpbuf, NULL); + if (!discard) { + ++items; + void *out = va_arg(va, void *); + if (charbytes == sizeof(char)) { + *(float *)out = (float)fp; + } else { + *(double *)out = (double)fp; + } + } free(fpbuf); fpbuf = NULL; fpbufcur = fpbufsize = 0; continue; ReportConsumed: n_ptr = va_arg(va, int *); - *n_ptr = consumed - 1; // minus lookahead + if (c != -1) { + *n_ptr = consumed - 1; // minus lookahead + } else { + *n_ptr = consumed; + } continue; DecodeString: bufsize = !width ? 32 : rawmode ? width : width + 1; @@ -545,7 +551,7 @@ int __vcscanf(int callback(void *), // } ++items; if (ismalloc) { - *va_arg(va, char **) = (void *) buf; + *va_arg(va, char **) = (void *)buf; } buf = NULL; } else { diff --git a/test/libc/stdio/sscanf_test.c b/test/libc/stdio/sscanf_test.c index 450bee87f..571617715 100644 --- a/test/libc/stdio/sscanf_test.c +++ b/test/libc/stdio/sscanf_test.c @@ -383,7 +383,8 @@ TEST(sscanf, floating_point_infinity) { TEST(sscanf, floating_point_infinity_double_precision) { double a = 666.666, b = a, c = b, d = c, e = d, f = e, g = f; EXPECT_EQ(4, sscanf("inf +INF -iNf InF", "%lf %lf %lf %lf", &a, &b, &c, &d)); - EXPECT_EQ(3, sscanf("+infinity -INFINITY iNfInItY", "%lf %lf %lf", &e, &f, &g)); + EXPECT_EQ(3, + sscanf("+infinity -INFINITY iNfInItY", "%lf %lf %lf", &e, &f, &g)); EXPECT_TRUE(isinf(a)); EXPECT_TRUE(isinf(b)); EXPECT_TRUE(isinf(c)); @@ -394,11 +395,14 @@ TEST(sscanf, floating_point_infinity_double_precision) { } TEST(sscanf, floating_point_documentation_examples) { - float a = 666.666f, b = a, c = b, d = c, e = d, f = e, g = f, h = g, i = h, j = i; + float a = 666.666f, b = a, c = b, d = c, e = d, f = e, g = f, h = g, i = h, + j = i; EXPECT_EQ(2, sscanf("111.11 -2.22", "%f %f", &a, &b)); EXPECT_EQ(3, sscanf("Nan nan(2) inF", "%f %f %f", &c, &d, &e)); - EXPECT_EQ(5, sscanf("0X1.BC70A3D70A3D7P+6 1.18973e+4932zzz -0.0000000123junk junk", "%f %f %f %f %f", &f, &g, &h, &i, &j)); + EXPECT_EQ( + 5, sscanf("0X1.BC70A3D70A3D7P+6 1.18973e+4932zzz -0.0000000123junk junk", + "%f %f %f %f %f", &f, &g, &h, &i, &j)); EXPECT_EQ(111.11f, a); EXPECT_EQ(-2.22f, b); @@ -413,11 +417,14 @@ TEST(sscanf, floating_point_documentation_examples) { } TEST(sscanf, floating_point_documentation_examples_double_precision) { - double a = 666.666, b = a, c = b, d = c, e = d, f = e, g = f, h = g, i = h, j = i; + double a = 666.666, b = a, c = b, d = c, e = d, f = e, g = f, h = g, i = h, + j = i; EXPECT_EQ(2, sscanf("111.11 -2.22", "%lf %lf", &a, &b)); EXPECT_EQ(3, sscanf("Nan nan(2) inF", "%lf %lf %lf", &c, &d, &e)); - EXPECT_EQ(5, sscanf("0X1.BC70A3D70A3D7P+6 1.18973e+4932zzz -0.0000000123junk junk", "%lf %lf %lf %lf %lf", &f, &g, &h, &i, &j)); + EXPECT_EQ( + 5, sscanf("0X1.BC70A3D70A3D7P+6 1.18973e+4932zzz -0.0000000123junk junk", + "%lf %lf %lf %lf %lf", &f, &g, &h, &i, &j)); EXPECT_EQ(111.11, a); EXPECT_EQ(-2.22, b); @@ -470,3 +477,16 @@ TEST(fscanf, wantDecimalButGotLetter_returnsZeroMatches) { EXPECT_EQ(666, x); fclose(f); } + +TEST(scanf, n) { + int rc; + unsigned int a, b, c, d, port, len; + rc = sscanf("1.2.3.4:1848", "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len); + ASSERT_EQ(5, rc); + ASSERT_EQ(1, a); + ASSERT_EQ(2, b); + ASSERT_EQ(3, c); + ASSERT_EQ(4, d); + ASSERT_EQ(1848, port); + ASSERT_EQ(12, len); +}