hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit b8f06c95d64eec548cbb6785816f20e55423671a
parent f679ee1c3a82b2b0b2612e1c38859ff0039f7742
Author: Alexey Yerin <yyp@disroot.org>
Date:   Sun,  7 Nov 2021 17:31:01 +0300

shlex: rewrite and fix some regressions

Instead of using bufio::fixed, iterate through input with strings::iter.
This also fixes a few issues with empty quoted strings.

Signed-off-by: Alexey Yerin <yyp@disroot.org>

Diffstat:
Mshlex/+test.ha | 6++++++
Mshlex/split.ha | 77+++++++++++++++++++++++++++++++----------------------------------------------
2 files changed, 37 insertions(+), 46 deletions(-)

diff --git a/shlex/+test.ha b/shlex/+test.ha @@ -26,6 +26,12 @@ assert(s[1] == ""); assert(s[2] == "world"); + const s = split("Empty ''")!; + defer splitfree(s); + assert(len(s) == 2); + assert(s[0] == "Empty"); + assert(s[1] == ""); + 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 @@ -1,4 +1,3 @@ -use bufio; use io; use strings; use strio; @@ -9,72 +8,58 @@ export type syntaxerr = !void; // Splits a string of arguments according to shell quoting. The result must be // freed using [[splitfree]] when the caller is done processing it. export fn split(in: const str) ([]str | syntaxerr) = { - let in = bufio::fixed(strings::toutf8(in), io::mode::READ); - defer io::close(in); + let iter = strings::iter(in); let s = strio::dynamic(); let slice: []str = []; + let dirty = false; for (true) { - const r = match (bufio::scanrune(in)!) { + const r = match (strings::next(&iter)) { case r: rune => yield r; - case io::EOF => + case void => break; }; + dirty = true; switch (r) { case ' ', '\t', '\n' => - 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; + for (true) match (strings::next(&iter)) { + case r: rune => + if (r != ' ' && r != '\t' && r != '\n') { + strings::prev(&iter); // Unget + break; }; - abort(); // Unreachable + case void => + break; }; append(slice, strio::finish(s)); s = strio::dynamic(); - - match (r) { - case void => void; - case r: rune => - process(s, in, r)?; - }; + dirty = false; + case '\\' => + scan_backslash(s, &iter)?; + case '"' => + scan_double(s, &iter)?; + case '\'' => + scan_single(s, &iter)?; case => - process(s, in, r)?; + strio::appendrune(s, r)!; }; }; - const buf = strio::finish(s); - if (len(buf) > 0) { - append(slice, buf); + if (dirty) { + append(slice, strio::finish(s)); }; 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)!) { +fn scan_backslash(out: io::handle, in: *strings::iterator) (void | syntaxerr) = { + const r = match (strings::next(in)) { case r: rune => yield r; - case io::EOF => + case void => return syntaxerr; }; @@ -89,12 +74,12 @@ fn scan_backslash(out: io::handle, in: io::handle) (void | syntaxerr) = { strio::appendrune(out, r)!; }; -fn scan_double(out: io::handle, in: io::handle) (void | syntaxerr) = { +fn scan_double(out: io::handle, in: *strings::iterator) (void | syntaxerr) = { for (true) { - const r = match (bufio::scanrune(in)!) { + const r = match (strings::next(in)) { case r: rune => yield r; - case io::EOF => + case void => return syntaxerr; }; @@ -109,12 +94,12 @@ fn scan_double(out: io::handle, in: io::handle) (void | syntaxerr) = { }; }; -fn scan_single(out: io::handle, in: io::handle) (void | syntaxerr) = { +fn scan_single(out: io::handle, in: *strings::iterator) (void | syntaxerr) = { for (true) { - const r = match (bufio::scanrune(in)!) { + const r = match (strings::next(in)) { case r: rune => yield r; - case io::EOF => + case void => return syntaxerr; };