Something went wrong. Try again.
A rewrite of the Plan 9 rc shell in Goose for UNIX-like systems and with structured CLI args
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293import data;
fn raw_pattern(s: u8[:]) -> Span { let start = text.len; for c in s { if c == '\\' { text.push(c); } text.push(c); } return Span { start, text.len - start };}fn rune(s: u8[:], at: i64) -> i64, i64 { let first = s[at]; var width = 1; var code = first as i64; if first >= 0xc2 && first < 0xe0 { width = 2; code = first & 0x1f; } else if first >= 0xe0 && first < 0xf0 { width = 3; code = first & 0x0f; } else if first >= 0xf0 && first < 0xf5 { width = 4; code = first & 7; } if at + width > s.len { return first, at + 1; } for i in 1..width { let byte = s[at + i]; if byte < 0x80 || byte >= 0xc0 { return first, at + 1; } code = (code << 6) | (byte & 0x3f); } return code, at + width;}fn class_match(p: u8[:], start: i64, code: i64) -> bool, i64 { var i = start + 1; let complement = i < p.len && p[i] == '~'; if complement { i += 1; } var hit = false; while i < p.len && p[i] != ']' { if p[i] == '\\' && i + 1 < p.len { i += 1; } let lo, next = rune(p, i); i = next; var hi = lo; if i < p.len && p[i] == '-' { i += 1; if i >= p.len { return false, start; } let end, after = rune(p, i); hi = end; i = after; } if code >= min(lo, hi) && code <= max(lo, hi) { hit = true; } } if i >= p.len { return false, start; } return if complement { !hit } else { hit }, i + 1;}fn pattern_match(p: u8[:], s: u8[:]) -> bool { // Retry only the last star. This avoids exponential recursion on hostile patterns. var pi = 0; var si = 0; var star = -1; var retry = 0; loop { if pi == p.len && si == s.len { return true; } if pi < p.len && p[pi] == '*' { star = pi; retry = si; pi += 1; continue; } if pi < p.len && si < s.len { let code, next = rune(s, si); var after = pi + 1; var hit = p[pi] == '?'; if p[pi] == '[' { hit, after = class_match(p, pi, code); } else if p[pi] != '?' { var at = pi; if p[at] == '\\' && at + 1 < p.len { at += 1; } let literal, end = rune(p, at); hit = literal == code; after = end; } if hit { pi = after; si = next; continue; } } if star < 0 || retry == s.len { return false; } let code, next = rune(s, retry); retry = next; si = retry; pi = star + 1; } return false;}fn match_text(pattern: u8[:], subject: u8[:]) -> bool { return pattern_match(view(raw_pattern(pattern)), subject);}fn has_glob(p: u8[:]) -> bool { var i = 0; while i < p.len { if p[i] == '\\' { i += 2; continue; } if contains("*?[", p[i]) { return true; } i += 1; } return false;}fn unescape_pattern(p: u8[:]) -> Span { let start = text.len; var i = 0; while i < p.len { if p[i] == '\\' && i + 1 < p.len { i += 1; } text.push(p[i]); i += 1; } return Span { start, text.len - start };}