Further improve scanf

This commit is contained in:
Justine Tunney 2023-08-21 16:55:29 -07:00
parent 6ef2a471e4
commit 7e08a97cea
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
3 changed files with 76 additions and 37 deletions

View file

@ -26,7 +26,9 @@
int ungetc_unlocked(int c, FILE *f) {
if (c == -1) return -1;
if (f->beg) {
f->buf[--f->beg] = c;
if (c != f->buf[--f->beg]) {
f->buf[f->beg] = c;
}
} else if (f->end < f->size) {
memmove(f->buf + 1, f->buf, f->end++);
f->buf[0] = c;

View file

@ -156,26 +156,34 @@ int __vcscanf(int callback(void *), //
case 'b': // binary
base = 2;
prefix = 'b';
while (isspace(c)) {
c = READ;
}
goto ConsumeBasePrefix;
case 'p': // pointer
case 'p': // pointer (NexGen32e)
bits = 48;
// fallthrough
case 'x':
case 'X': // hexadecimal
base = 16;
prefix = 'x';
while (isspace(c)) {
c = READ;
}
goto ConsumeBasePrefix;
case 'o': // octal
base = 8;
goto SetupNumber;
case 'i': // flexidecimal
goto HandleNumber;
case 'n':
goto ReportConsumed;
case 'd': // decimal
issigned = true;
// fallthrough
case 'u':
base = 10;
HandleNumber:
while (isspace(c)) {
c = READ;
}
if (c == '+' || (isneg = c == '-')) {
c = READ;
}
goto DecodeNumber;
case 'i': // flexidecimal
while (isspace(c)) {
c = READ;
}
@ -184,57 +192,46 @@ int __vcscanf(int callback(void *), //
}
if (c == '0') {
c = READ;
if (c == -1) {
number = 0;
goto GotNumber;
}
if (c == 'x' || c == 'X') {
c = READ;
base = 16;
} else if (c == 'b' || c == 'B') {
c = READ;
base = 2;
} else {
} else if ('0' <= c && c <= '7') {
base = 8;
} else {
number = 0;
goto GotNumber;
}
} else {
base = 10;
}
goto DecodeNumber;
case 'n':
goto ReportConsumed;
case 'd': // decimal
issigned = true;
// fallthrough
case 'u':
base = 10;
SetupNumber:
while (isspace(c)) {
c = READ;
}
if (c == '+' || (isneg = c == '-')) {
c = READ;
}
goto DecodeNumber;
default:
items = einval();
goto Done;
}
}
ReportConsumed:
n_ptr = va_arg(va, int *);
*n_ptr = consumed - 1; // minus lookahead
continue;
ConsumeBasePrefix:
while (isspace(c)) {
c = READ;
}
if (c == '+' || (isneg = c == '-')) {
c = READ;
}
if (c == '0') {
c = READ;
if (c == prefix || c == prefix + ('a' - 'A')) {
c = READ;
} else if (c == -1) {
c = '0';
number = 0;
goto GotNumber;
}
}
DecodeNumber:
if (c != -1 && kBase36[(unsigned char)c] <= base) {
if (c != -1 && (1 <= kBase36[(unsigned char)c] &&
kBase36[(unsigned char)c] <= base)) {
number = 0;
width = !width ? bits : width;
do {
@ -286,11 +283,20 @@ int __vcscanf(int callback(void *), //
items = -1;
goto Done;
}
} else if (!items) {
} else if (c == -1 && !items) {
items = -1;
goto Done;
} else {
if (c != -1 && unget) {
unget(c, arg);
}
goto Done;
}
continue;
ReportConsumed:
n_ptr = va_arg(va, int *);
*n_ptr = consumed - 1; // minus lookahead
continue;
DecodeString:
bufsize = !width ? 32 : rawmode ? width : width + 1;
if (discard) {

View file

@ -21,7 +21,10 @@
#include "libc/intrin/bits.h"
#include "libc/inttypes.h"
#include "libc/limits.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h"
#include "libc/stdio/internal.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
#define sscanf1(STR, FMT) \
@ -336,3 +339,31 @@ TEST(sscanf, lupluser) {
EXPECT_EQ(1, sscanf("+123", "%li", &x));
EXPECT_EQ(123, x);
}
TEST(fscanf, stuff) {
int x;
char *s = "1 12 123\n"
"4 44\n";
FILE *f = fmemopen(s, strlen(s), "r+");
EXPECT_EQ(1, fscanf(f, "%d", &x));
EXPECT_EQ(1, x);
EXPECT_EQ(1, fscanf(f, "%d", &x));
EXPECT_EQ(12, x);
EXPECT_EQ(1, fscanf(f, "%d", &x));
EXPECT_EQ(123, x);
EXPECT_EQ(1, fscanf(f, "%d", &x));
EXPECT_EQ(4, x);
EXPECT_EQ(1, fscanf(f, "%d", &x));
EXPECT_EQ(44, x);
EXPECT_EQ(-1, fscanf(f, "%d", &x));
fclose(f);
}
TEST(fscanf, wantDecimalButGotLetter_returnsZeroMatches) {
int x = 666;
char *s = "a1\n";
FILE *f = fmemopen(s, strlen(s), "r+");
EXPECT_EQ(0, fscanf(f, "%d", &x));
EXPECT_EQ(666, x);
fclose(f);
}