ref: db1eb844461b07a25ca49117851fa874fd88e065
parent: 15e065df12bf7ad79000d150cefa5038ee7416b3
author: henesy <devnull@localhost>
date: Wed Jun 2 20:27:57 EDT 2021
string.m: add qtokenize() to make whitespace/quote tokens similar to sh(1)/attrdb(2)
--- a/appl/lib/string.b
+++ b/appl/lib/string.b
@@ -50,7 +50,7 @@
return containscl(s, wscl);
}
-# Does 's' contain any characters in class 'cl'
+# Does 's' contain any characters in class 'cl'?
containscl(s: string, cl: string): int {
for(i := 0; i < len s; i++)
if(in(s[i], cl))
@@ -58,6 +58,14 @@
return 0;
}
+countcl(s: string, cl: string): int {
+ count := 0;
+ for(i := 0; i < len s; i++)
+ if(in(s[i], cl))
+ count++;
+ return count;
+}
+
in(c: int, s: string): int
{
n := len s;
@@ -567,3 +575,45 @@
return out;
}
+# Quote and whitespace tokenize input
+# Similar to sh(2) conventions, but permitting double quotes
+qtokenize(s: string): (list of string, string) {
+ out: list of string;
+ quote := 0;
+ word := "";
+
+ for(i := 0; i < len s; i++) {
+ if(quote) {
+ if(s[i] == quote) {
+ if(i+1 >= len s || s[i+1] != quote){
+ quote = 0;
+ continue;
+ }
+ i++;
+ }
+ word[len word] = s[i];
+ continue;
+ }
+
+ case s[i] {
+ '\'' or '\"' =>
+ quote = s[i];
+
+ ' ' or '\t' or '\n' =>
+ if(word == nil)
+ continue;
+ out = word :: out;
+ word = nil;
+
+ * =>
+ word[len word] = s[i];
+ }
+ }
+ if(quote)
+ return (nil, "missing quote");
+
+ if(word != nil)
+ out = word :: out;
+
+ return (out, nil);
+}
--- a/module/string.m
+++ b/module/string.m
@@ -17,6 +17,7 @@
take: fn(s, cl: string): string;
in: fn(c: int, cl: string): int;
containscl: fn(s, cl: string): int;
+ countcl: fn(s: string, cl: string): int;
# in these, the second string is a string to match, not a class
splitstrl: fn(s, t: string): (string, string);
@@ -42,4 +43,5 @@
quotedc: fn(argv: list of string, cl: string): string;
unquoted: fn(args: string): list of string;
fields: fn(s: string): list of string;
+ qtokenize: fn(s: string): (list of string, string);
};