mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 15:38:22 +00:00
Further improve scanf
This commit is contained in:
parent
6ef2a471e4
commit
7e08a97cea
3 changed files with 76 additions and 37 deletions
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue