Fix bug in scanf where EOF would be ignored
This commit is contained in:
@@ -111,6 +111,10 @@ unsafe fn inner_scanf<R: Read>(
|
||||
}
|
||||
};
|
||||
|
||||
// When an EOF occurs, eof is set, stuff is marked matched
|
||||
// as usual, and finally it is returned
|
||||
let mut eof = false;
|
||||
|
||||
let mut kind = IntKind::Int;
|
||||
loop {
|
||||
kind = match c {
|
||||
@@ -195,7 +199,7 @@ unsafe fn inner_scanf<R: Read>(
|
||||
}
|
||||
width = width.map(|w| w - 1);
|
||||
if !read!() {
|
||||
break;
|
||||
return Ok(matched);
|
||||
}
|
||||
if width.map(|w| w > 0).unwrap_or(true)
|
||||
&& (byte == b'x' || byte == b'X')
|
||||
@@ -203,7 +207,7 @@ unsafe fn inner_scanf<R: Read>(
|
||||
radix = 16;
|
||||
width = width.map(|w| w - 1);
|
||||
if width.map(|w| w > 0).unwrap_or(true) && !read!() {
|
||||
break;
|
||||
return Ok(matched);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@@ -215,7 +219,7 @@ unsafe fn inner_scanf<R: Read>(
|
||||
n.push(byte as char);
|
||||
width = width.map(|w| w - 1);
|
||||
if width.map(|w| w > 0).unwrap_or(true) && !read!() {
|
||||
break;
|
||||
return Ok(matched);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,6 +338,7 @@ unsafe fn inner_scanf<R: Read>(
|
||||
}
|
||||
width = width.map(|w| w - 1);
|
||||
if width.map(|w| w > 0).unwrap_or(true) && !read!() {
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -352,6 +357,7 @@ unsafe fn inner_scanf<R: Read>(
|
||||
}
|
||||
width = width.map(|w| w - 1);
|
||||
if width.map(|w| w > 0).unwrap_or(true) && !read!() {
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -396,14 +402,18 @@ unsafe fn inner_scanf<R: Read>(
|
||||
|
||||
let mut ptr: Option<*mut c_char> = if ignore { None } else { Some(ap.get()) };
|
||||
|
||||
while width.map(|w| w > 0).unwrap_or(true) && !invert == matches.contains(&byte)
|
||||
{
|
||||
// While we haven't used up all the width, and it matches
|
||||
while width.map(|w| w > 0).unwrap_or(true) && !invert == matches.contains(&byte) {
|
||||
if let Some(ref mut ptr) = ptr {
|
||||
**ptr = byte as c_char;
|
||||
*ptr = ptr.offset(1);
|
||||
}
|
||||
// Decrease the width, and read a new character unless the width is 0
|
||||
width = width.map(|w| w - 1);
|
||||
if width.map(|w| w > 0).unwrap_or(true) && !read!() {
|
||||
// Reading a new character has failed, return after
|
||||
// actually marking this as matched
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -412,7 +422,7 @@ unsafe fn inner_scanf<R: Read>(
|
||||
*ptr = 0;
|
||||
matched += 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
b'n' => {
|
||||
if !ignore {
|
||||
*ap.get::<*mut c_int>() = count as c_int;
|
||||
@@ -421,6 +431,10 @@ unsafe fn inner_scanf<R: Read>(
|
||||
_ => return Err(-1),
|
||||
}
|
||||
|
||||
if eof {
|
||||
return Ok(matched);
|
||||
}
|
||||
|
||||
if width != Some(0) && c != b'n' {
|
||||
// It didn't hit the width, so an extra character was read and matched.
|
||||
// But this character did not match so let's reuse it.
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
2, { sa: 12, ia: 345, ib: 0, ic: 0, fa: 0.000000, da: 0.000000, ptr: (nil), char: a, string: }
|
||||
3, { sa: 12, ia: 18, ib: 837, ic: 8, fa: 0.000000, da: 0.000000, ptr: (nil), char: a, string: }
|
||||
2, { sa: 12, ia: 18, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: (nil), char: a, string: }
|
||||
1, { sa: 12, ia: 18, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: a, string: }
|
||||
1, { sa: 12, ia: 18, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: a, string: Hello }
|
||||
1, { sa: 12, ia: 15, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: a, string: Hello }
|
||||
2, { sa: 12, ia: 15, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string: elllo }
|
||||
1, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string: elllo }
|
||||
0, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string: elllo }
|
||||
1, { sa: 12, ia: 0, ib: 0, ic: 0, fa: 0.000000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4: }
|
||||
2, { sa: 12, ia: 18, ib: 837, ic: 0, fa: 0.000000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4: }
|
||||
1, { sa: 12, ia: 18, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4: }
|
||||
0, { sa: 12, ia: 18, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4: }
|
||||
1, { sa: 12, ia: 18, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: a, string1: Hello, string2: , string3: , string4: }
|
||||
1, { sa: 12, ia: 15, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: a, string1: Hello, string2: , string3: , string4: }
|
||||
2, { sa: 12, ia: 15, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: elllo, string2: , string3: , string4: }
|
||||
1, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: elllo, string2: , string3: , string4: }
|
||||
0, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: elllo, string2: , string3: , string4: }
|
||||
4, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: e, string2: o, string3: l, string4: d }
|
||||
4, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: a, string2: e, string3: f, string4: dddddd }
|
||||
4, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: a, string2: e, string3: f, string4: dddddd }
|
||||
1, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: testbbbb, string2: e, string3: f, string4: dddddd }
|
||||
3 "https" "//" "redox-os.org" ""
|
||||
|
||||
+26
-5
@@ -12,7 +12,10 @@ struct params {
|
||||
double da;
|
||||
int *ptr;
|
||||
char c;
|
||||
char string[20];
|
||||
char string1[20];
|
||||
char string2[20];
|
||||
char string3[20];
|
||||
char string4[20];
|
||||
};
|
||||
|
||||
void test(char* fmt_in, char* input, struct params *p, ...) {
|
||||
@@ -22,8 +25,8 @@ void test(char* fmt_in, char* input, struct params *p, ...) {
|
||||
va_end(args);
|
||||
|
||||
printf(
|
||||
"%d, { sa: %hhd, ia: %d, ib: %d, ic: %d, fa: %f, da: %lf, ptr: %p, char: %c, string: %s }\n",
|
||||
ret, p->sa, p->ia, p->ib, p->ic, p->fa, p->da, p->ptr, p->c, p->string
|
||||
"%d, { sa: %hhd, ia: %d, ib: %d, ic: %d, fa: %f, da: %lf, ptr: %p, char: %c, string1: %s, string2: %s, string3: %s, string4: %s }\n",
|
||||
ret, p->sa, p->ia, p->ib, p->ic, p->fa, p->da, p->ptr, p->c, p->string1, p->string2, p->string3, p->string4
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,9 +37,27 @@ int main(void) {
|
||||
test("%x %i %i", "12 0x345 010", &p, &p.ia, &p.ib, &p.ic);
|
||||
test("%f.%lf", "0.1.0.2", &p, &p.fa, &p.da);
|
||||
test("%p", "0xABCDEF", &p, &p.ptr);
|
||||
test("%s", "Hello World", &p, &p.string);
|
||||
test("%s", "Hello World", &p, &p.string1);
|
||||
test("%3i", "0xFF", &p, &p.ia);
|
||||
test("%c%3c", "hello", &p, &p.c, &p.string);
|
||||
test("%c%3c", "hello", &p, &p.c, &p.string1);
|
||||
test("test: %2i%n", "test: 0xFF", &p, &p.ia, &p.ib);
|
||||
test("hello world%%", "hello world%", &p);
|
||||
test("h%1[ae]ll%1[^a] wor%1[^\n]%[d]", "hello world", &p, &p.string1, &p.string2, &p.string3, &p.string4);
|
||||
test("h%1[ae]ll%1[^a] wor%1[^\n]%[d]", "halle worfdddddd", &p, &p.string1, &p.string2, &p.string3, &p.string4);
|
||||
test("h%1[ae]ll%1[^a] wor%1[^\n]%[d]", "halle worfdddddd", &p, &p.string1, &p.string2, &p.string3, &p.string4);
|
||||
test("%[^a]%[b]", "testbbbb", &p, &p.string1, &p.string2);
|
||||
|
||||
|
||||
// Scanf stolen from the url parsing in curl
|
||||
char protobuf[16];
|
||||
char slashbuf[4];
|
||||
char hostbuf[100];
|
||||
char pathbuf[100];
|
||||
|
||||
int ret = sscanf(
|
||||
"https://redox-os.org", "%15[^\n/:]:%3[/]%[^\n/?#]%[^\n]",
|
||||
&protobuf, &slashbuf, &hostbuf, &pathbuf
|
||||
);
|
||||
|
||||
printf("%d \"%s\" \"%s\" \"%s\" \"%s\"\n", ret, &protobuf, &slashbuf, &hostbuf, &pathbuf);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user