wordexp.ha (1922B)
1 // SPDX-License-Identifier: MIT 2 // (c) Hare authors <https://harelang.org> 3 // (c) 2005-2020 Rich Felker, et al 4 // Based on the musl libc implementation 5 6 use bufio; 7 use io; 8 use os; 9 use os::exec; 10 use strings; 11 12 // Flags applicable to a [[wordexp]] operation. 13 export type flag = enum uint { 14 NONE = 0, 15 // DOOFFS = (1 << 0), // not implemented 16 // APPEND = (1 << 1), // not implemented 17 // REUSE = (1 << 3), // not implemented 18 // NOCMD = (1 << 2), // not implemented 19 SHOWERR = (1 << 4), 20 UNDEF = (1 << 5), 21 }; 22 23 // Performs shell expansion and word splitting on the provided string, returning 24 // a list of expanded words, similar to POSIX wordexp(3). Note that this 25 // function, by design, will execute arbitrary commands from the input string. 26 // 27 // Pass the return value to [[strings::freeall]] to free resources associated 28 // with the return value. 29 export fn wordexp(s: str, flags: flag = flag::NONE) ([]str | error) = { 30 const (rd, wr) = exec::pipe(); 31 32 // "x" is added to handle the list of expanded words being empty 33 const cmd = exec::cmd("/bin/sh", 34 if (flags & flag::UNDEF != 0) "-uc" else "-c", 35 `eval "printf %s\\\\0 x $1"`, "sh", s)!; 36 exec::unsetenv(&cmd, "IFS")!; 37 exec::addfile(&cmd, os::stdout_file, wr); 38 if (flags & flag::SHOWERR == 0) { 39 exec::addfile(&cmd, os::stderr_file, exec::nullfd); 40 }; 41 const child = exec::start(&cmd)!; 42 io::close(wr)!; 43 44 const scan = bufio::newscanner(rd); 45 defer bufio::finish(&scan); 46 47 match (bufio::scan_string(&scan, "\0")?) { 48 case io::EOF => 49 return sh_error; 50 case => void; // Discard the first "x" argument 51 }; 52 53 let words: []str = []; 54 for (true) { 55 match (bufio::scan_string(&scan, "\0")?) { 56 case io::EOF => break; 57 case let word: const str => 58 append(words, strings::dup(word)); 59 }; 60 }; 61 62 io::close(rd)!; 63 const st = exec::wait(&child)!; 64 match (exec::check(&st)) { 65 case !exec::exit_status => 66 return sh_error; 67 case void => 68 return words; 69 }; 70 };