commit f679ee1c3a82b2b0b2612e1c38859ff0039f7742
parent 76af771721b0fc611633b2c97b1f0e9bfdcb33e7
Author: Alexey Yerin <yyp@disroot.org>
Date: Sun, 7 Nov 2021 15:00:55 +0300
shlex: fix whitespace folding
Previously this caused split("hello '' world") to return
["hello", "world"] without the empty string in between.
Signed-off-by: Alexey Yerin <yyp@disroot.org>
Diffstat:
2 files changed, 39 insertions(+), 10 deletions(-)
diff --git a/shlex/+test.ha b/shlex/+test.ha
@@ -19,6 +19,13 @@
assert(len(s) == 1);
assert(s[0] == "hello \"world\"");
+ const s = split("hello '' world")!;
+ defer splitfree(s);
+ assert(len(s) == 3);
+ assert(s[0] == "hello");
+ assert(s[1] == "");
+ assert(s[2] == "world");
+
const s = split("with\\ backslashes 'single quoted' \"double quoted\"")!;
defer splitfree(s);
assert(len(s) == 3);
diff --git a/shlex/split.ha b/shlex/split.ha
@@ -24,19 +24,28 @@ export fn split(in: const str) ([]str | syntaxerr) = {
};
switch (r) {
- case '\\' =>
- scan_backslash(s, in)?;
- case '"' =>
- scan_double(s, in)?;
- case '\'' =>
- scan_single(s, in)?;
case ' ', '\t', '\n' =>
- if (len(strio::string(s)) > 0) {
- append(slice, strio::finish(s));
- s = strio::dynamic();
+ let r = :out {
+ for (true) match (bufio::scanrune(in)!) {
+ case r: rune =>
+ if (r != ' ' && r != '\t' && r != '\n') {
+ yield :out, r;
+ };
+ case io::EOF =>
+ yield :out, void;
+ };
+ abort(); // Unreachable
+ };
+ append(slice, strio::finish(s));
+ s = strio::dynamic();
+
+ match (r) {
+ case void => void;
+ case r: rune =>
+ process(s, in, r)?;
};
case =>
- strio::appendrune(s, r)!;
+ process(s, in, r)?;
};
};
@@ -48,6 +57,19 @@ export fn split(in: const str) ([]str | syntaxerr) = {
return slice;
};
+fn process(out: io::handle, in: io::handle, r: rune) (void | syntaxerr) = {
+ switch (r) {
+ case '\\' =>
+ scan_backslash(out, in)?;
+ case '"' =>
+ scan_double(out, in)?;
+ case '\'' =>
+ scan_single(out, in)?;
+ case =>
+ strio::appendrune(out, r)!;
+ };
+};
+
fn scan_backslash(out: io::handle, in: io::handle) (void | syntaxerr) = {
const r = match (bufio::scanrune(in)!) {
case r: rune =>