code: purgatorio

Download patch

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);
 };