summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-09-01 20:36:52 -0700
committerKaz Kylheku <kaz@kylheku.com>2023-09-01 20:36:52 -0700
commita5d5536fcf2fe616b8c0941df0bc92f3bd9761ba (patch)
tree59d522eb4ec987ed034707d2644827cb4bc051e8
parent9c0e5743188588ece98197880a3f1174170dc563 (diff)
downloadtxr-a5d5536fcf2fe616b8c0941df0bc92f3bd9761ba.tar.gz
txr-a5d5536fcf2fe616b8c0941df0bc92f3bd9761ba.tar.bz2
txr-a5d5536fcf2fe616b8c0941df0bc92f3bd9761ba.zip
New functions for shell escaping.
* stream.c (sh_esc, sh_esc_all, sh_esc_dq, sh_esc_sq): New static functions. (stream_init): sh-esc, sh-esc-all, sh-esc-dq, sh-esc-sq: Intrinsics registered. * tests/018/sh-esc.tl: New file. * txr.1: Documented.
-rw-r--r--stream.c24
-rw-r--r--tests/018/sh-esc.tl11
-rw-r--r--txr.190
3 files changed, 125 insertions, 0 deletions
diff --git a/stream.c b/stream.c
index f948e988..02aec9ee 100644
--- a/stream.c
+++ b/stream.c
@@ -4838,6 +4838,26 @@ static val sh(val command)
#endif
+static val sh_esc(val string)
+{
+ return str_esc(lit("|&;<>()$`\\\"' \t\n*?[#~"), chr('\\'), string);
+}
+
+static val sh_esc_all(val string)
+{
+ return str_esc(lit("|&;<>()$`\\\"' \t\n*?[#~=%"), chr('\\'), string);
+}
+
+static val sh_esc_dq(val string)
+{
+ return str_esc(lit("$`\\\"\n"), chr('\\'), string);
+}
+
+static val sh_esc_sq(val string)
+{
+ return str_esc(lit("'"), lit("'\\'"), string);
+}
+
val remove_path(val path, val throw_on_error)
{
val self = lit("remove-path");
@@ -5556,6 +5576,10 @@ void stream_init(void)
reg_fun(intern(lit("sh"), user_package), func_n1(sh));
reg_fun(intern(lit("run"), user_package), func_n2o(run, 1));
#endif
+ reg_fun(intern(lit("sh-esc"), user_package), func_n1(sh_esc));
+ reg_fun(intern(lit("sh-esc-all"), user_package), func_n1(sh_esc_all));
+ reg_fun(intern(lit("sh-esc-dq"), user_package), func_n1(sh_esc_dq));
+ reg_fun(intern(lit("sh-esc-sq"), user_package), func_n1(sh_esc_sq));
reg_fun(intern(lit("remove-path"), user_package), func_n2o(remove_path, 1));
reg_fun(intern(lit("rename-path"), user_package), func_n2(rename_path));
reg_fun(intern(lit("open-files"), user_package), func_n3o(open_files, 1));
diff --git a/tests/018/sh-esc.tl b/tests/018/sh-esc.tl
new file mode 100644
index 00000000..3466ee76
--- /dev/null
+++ b/tests/018/sh-esc.tl
@@ -0,0 +1,11 @@
+(load "../common")
+
+(mtest
+ (sh-esc "|&;<>()$`\\\"' \t\n*?[#~=%abc")
+ "\\|\\&\\;\\<\\>\\(\\)\\$\\`\\\\\\\"\\'\\ \\\t\\\n\\*\\?\\[\\#\\~=%abc"
+ (sh-esc-all "|&;<>()$`\\\"' \t\n*?[#~=%abc")
+ "\\|\\&\\;\\<\\>\\(\\)\\$\\`\\\\\\\"\\'\\ \\\t\\\n\\*\\?\\[\\#\\~\\=\\%abc"
+ (sh-esc-dq "$`\\\"\n'abc()*~")
+ "\\$\\`\\\\\\\"\\\n'abc()*~"
+ (sh-esc-sq "$`\\\"\n'abc()*~")
+ "$`\\\"\n'\\''abc()*~")
diff --git a/txr.1 b/txr.1
index f54fe323..2a772c76 100644
--- a/txr.1
+++ b/txr.1
@@ -72684,6 +72684,96 @@ and expected to support
.onom
as a way of specifying a command to execute.
+.coNP Functions @, sh-esc @, sh-esc-all @ sh-esc-dq and @ sh-esc-sq
+.synb
+.mets (sh-esc << str )
+.mets (sh-esc-all << str )
+.mets (sh-esc-dq << str )
+.mets (sh-esc-sq << str )
+.syne
+.desc
+The functions
+.codn sh-esc ,
+.codn sh-esc-all ,
+.code sh-esc-dq
+and
+.code sh-esc-sq
+transform the argument string
+.code str
+for safe insertion into commands. These functions are intended
+for use on POSIX systems, where the
+command interpreter used by the functions
+.code sh
+and
+.code open-command
+and related functions is the POSIX Shell Command Language.
+
+The
+.code sh-esc
+function escapes its argument in such a way that the resulting
+string may be inserted as an argument into a command.
+
+The
+.code sh-esc-all
+function performs a stricter escaping, such that the transformed
+string may be inserted into any syntactic context where a
+textual operand is required for any reason, such as the
+.meta pattern
+in the
+.mono
+.meti <2> ${ var % pattern }
+.onom
+construct, or
+
+The
+.code sh-esc-dq
+function escapes its argument for insertion into a double-quoted field in a
+shell command line. It does not add the double quotes themselves.
+
+The
+.code sh-esc-dq
+function escapes its argument for insertion into a single-quoted field in a
+shell command line. It does not add the single quotes themselves.
+
+The precise set of characters which are escaped by a backslash by the
+.code sh-esc
+function is the following:
+
+.verb
+ | & ; < > ( ) $ ` \e " ' tab newline space * ? [ # ~
+.brev
+
+The
+.code sh-esc-all
+function escapes all the above characters, and also these:
+
+.verb
+ = %
+.brev
+
+The
+.code sh-esc-dq
+function escapes the following characters:
+
+.verb
+ $ ` \e " newline
+.brev
+
+To escape with a backslash means to precede every occurrence of the
+specified characters with the character
+.codn \e .
+
+The
+.code sh-esc-sq
+function replaces every occurrence of the
+.code '
+character (single quote, apostrophe) with the sequence
+.code '\e''
+(single quote, backslash, single quotes, single quote).
+This sequence has the effect of terminating the enclosing single-quoted
+field, then producing a single quote via a backslash escape,
+and then opening a single-quoted field.
+
.SS* Unix Filesystem Manipulation
.coNP Structure @ stat