summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c1
-rw-r--r--lib.c20
-rw-r--r--lib.h1
-rw-r--r--tests/015/esc.tl39
-rw-r--r--txr.137
5 files changed, 98 insertions, 0 deletions
diff --git a/eval.c b/eval.c
index adfd6d69..c04a443a 100644
--- a/eval.c
+++ b/eval.c
@@ -7597,6 +7597,7 @@ void eval_init(void)
reg_fun(intern(lit("tok-where"), user_package), func_n2(tok_where));
reg_fun(intern(lit("list-str"), user_package), func_n1(list_str));
reg_fun(intern(lit("trim-str"), user_package), func_n1(trim_str));
+ reg_fun(intern(lit("str-esc"), user_package), func_n3(str_esc));
reg_fun(intern(lit("cmp-str"), user_package), func_n2(cmp_str));
reg_fun(intern(lit("string-lt"), user_package), func_n2(str_lt));
reg_fun(intern(lit("str="), user_package), func_n2(str_eq));
diff --git a/lib.c b/lib.c
index e5d01387..422dbe57 100644
--- a/lib.c
+++ b/lib.c
@@ -6400,6 +6400,26 @@ val trim_str(val str)
}
}
+val str_esc(val escset, val escchr, val str)
+{
+ val self = lit("shell-escape");
+ val out = mkstring(zero, chr(' '));
+ const wchar_t *s = c_str(str, self);
+ const wchar_t *es = c_str(escset, self);
+ wchar_t ch;
+
+ while ((ch = *s++)) {
+ if (wcschr(es, ch)) {
+ string_extend(out, escchr, nil);
+ string_extend(out, chr(ch), nil);
+ } else {
+ string_extend(out, chr(ch), nil);
+ }
+ }
+
+ return string_finish(out);
+}
+
val cmp_str(val astr, val bstr)
{
val self = lit("cmp-str");
diff --git a/lib.h b/lib.h
index c7e4165d..911fb3e8 100644
--- a/lib.h
+++ b/lib.h
@@ -1077,6 +1077,7 @@ val tokn(val count, val tok_regex, val arg1, val arg2);
val tok_where(val str, val tok_regex);
val list_str(val str);
val trim_str(val str);
+val str_esc(val escset, val escchr, val str);
val cmp_str(val astr, val bstr);
val str_eq(val astr, val bstr);
val str_lt(val astr, val bstr);
diff --git a/tests/015/esc.tl b/tests/015/esc.tl
new file mode 100644
index 00000000..cf3619c8
--- /dev/null
+++ b/tests/015/esc.tl
@@ -0,0 +1,39 @@
+(load "../common")
+
+(mtest
+ (str-esc "$*." "~" "") ""
+ (str-esc "$*." "~" "a") "a"
+ (str-esc "$*." "~" "~") "~"
+ (str-esc "$*." "~" "*") "~*"
+ (str-esc "$*." "~" ".") "~.")
+
+(mtest
+ (str-esc "$*." "~" "aa") "aa"
+ (str-esc "$*." "~" "a~") "a~"
+ (str-esc "$*." "~" "a$") "a~$"
+ (str-esc "$*." "~" "a*") "a~*"
+ (str-esc "$*." "~" "a.") "a~.")
+
+(mtest
+ (str-esc "$*." "~" "~a") "~a"
+ (str-esc "$*." "~" "$a") "~$a"
+ (str-esc "$*." "~" "*a") "~*a"
+ (str-esc "$*." "~" ".a") "~.a")
+
+(mtest
+ (str-esc "$*." "~" "a~b") "a~b"
+ (str-esc "$*." "~" "a$b") "a~$b"
+ (str-esc "$*." "~" "a*b") "a~*b"
+ (str-esc "$*." "~" "a.b") "a~.b")
+
+(mtest
+ (str-esc "$*." "~" "~a~") "~a~"
+ (str-esc "$*." "~" "$a$") "~$a~$"
+ (str-esc "$*." "~" "*a*") "~*a~*"
+ (str-esc "$*." "~" ".a.") "~.a~.")
+
+(test
+ (str-esc "$*." "~" "$*.a$*.b") "~$~*~.a~$~*~.b")
+
+(test
+ (str-esc "<>" "<" "(<<>>)") "(<<<<<><>)")
diff --git a/txr.1 b/txr.1
index 4ac510d9..f54fe323 100644
--- a/txr.1
+++ b/txr.1
@@ -26480,6 +26480,43 @@ function produces a copy of
from which leading and
trailing tabs, spaces and newlines are removed.
+.coNP Function @ str-esc
+.synb
+.mets (str-esc < esc-set < esc-tok << str )
+.syne
+.desc
+The
+.code str-esc
+function performs a
+.I "character escaping"
+transformation on the input string
+.metn str .
+
+The argument
+.meta esc-set
+is a string containing zero or more characters.
+
+The
+.meta esc-tok
+argument is a character or string.
+
+The function returns a transformed version of
+.meta str
+in which every character of
+.meta str
+which occurs in
+.meta esc-set
+is preceded by
+.metn esc-tok .
+
+.TP* Examples;
+
+.verb
+ (str-esc "$@#" "$" "$foo @abc #1") -> "$$foo $@abc $#1"
+
+ (str-esc "'" "'\e\e'" "foo 'bar' baz") -> "foo '\e\e''bar'\e\e'' baz"
+.brev
+
.coNP Functions @ string-set-code and @ string-get-code
.synb
.mets (string-set-code < string << value )