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) {
|
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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue