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) { int ungetc_unlocked(int c, FILE *f) {
if (c == -1) return -1; if (c == -1) return -1;
if (f->beg) { 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) { } else if (f->end < f->size) {
memmove(f->buf + 1, f->buf, f->end++); memmove(f->buf + 1, f->buf, f->end++);
f->buf[0] = c; f->buf[0] = c;

View file

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

View file

@ -21,7 +21,10 @@
#include "libc/intrin/bits.h" #include "libc/intrin/bits.h"
#include "libc/inttypes.h" #include "libc/inttypes.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/internal.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#define sscanf1(STR, FMT) \ #define sscanf1(STR, FMT) \
@ -336,3 +339,31 @@ TEST(sscanf, lupluser) {
EXPECT_EQ(1, sscanf("+123", "%li", &x)); EXPECT_EQ(1, sscanf("+123", "%li", &x));
EXPECT_EQ(123, 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);
}