aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-06-26 22:27:58 -0700
committerKaz Kylheku <kaz@kylheku.com>2023-06-26 22:27:58 -0700
commit0907050e35c9887dcf961bda2111bd34c3eeb0e8 (patch)
tree5c7a6494195460be9eed1360fb4cbfc236434dbd
parentc9f4b29927db3499e6b2d0b7ac0399447bca073a (diff)
downloadcppawk-0907050e35c9887dcf961bda2111bd34c3eeb0e8.tar.gz
cppawk-0907050e35c9887dcf961bda2111bd34c3eeb0e8.tar.bz2
cppawk-0907050e35c9887dcf961bda2111bd34c3eeb0e8.zip
Add function for shell quoting.
* README.md: Mention <quote.h> and cppawk-quote man page. * share/cppawk/include/quote.h, * share/cppawk/include/quote-priv.h: New files. * testcases-quote: New file. * cppawk-quote.1: New file. * runtests: Add testcases-quote.
-rw-r--r--README.md3
-rw-r--r--cppawk-quote.1119
-rwxr-xr-xruntests5
-rw-r--r--share/cppawk/include/quote-priv.h69
-rw-r--r--share/cppawk/include/quote.h37
-rw-r--r--testcases-quote36
6 files changed, 269 insertions, 0 deletions
diff --git a/README.md b/README.md
index 921b01d..8fa661c 100644
--- a/README.md
+++ b/README.md
@@ -151,6 +151,9 @@ There are currently
* [`<field.h>`](../tree/cppawk-field.1): utilities for manipulating
the Awk positional parameters ("fields").
+* [`<quote.h>`](../tree/cppawk-quote.1): provides the `q` function for
+ quoting text for safe insertion into shells cripts.
+
Several unreleased headers are in the development queue:
* `<array.h>`: some associative array utilities.
diff --git a/cppawk-quote.1 b/cppawk-quote.1
new file mode 100644
index 0000000..29af8e6
--- /dev/null
+++ b/cppawk-quote.1
@@ -0,0 +1,119 @@
+.\" cppawk: C preprocessor wrapper around awk
+.\" Copyright 2023 Kaz Kylheku <kaz@kylheku.com>
+.\"
+.\" BSD-2 License
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright notice,
+.\" this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above copyright notice,
+.\" this list of conditions and the following disclaimer in the documentation
+.\" and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+.\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.de bk
+.IP " "
+.PP
+..
+.TH CPPAWK-QUOTE 1 "26 June 2023" "cppawk Libraries" "Shell Quoting"
+
+.SH NAME
+q \- Function for shell quoting.
+
+.SH SYNOPSIS
+
+.ft B
+ #include <quote.h>
+
+ q(str) \fI// return str, shell-escaped\fP
+.ft R
+
+.SH DESCRIPTION
+.bk
+The
+.B q
+function shell-escapes its argument
+.IR str .
+This means that if the argument contains
+special characters, it is transformed such that the resulting string
+can safely be inserted into a shell command as an argument. That argument,
+when interpreted by the shell, will be interpreted as the original text
+which was input to
+.BR q .
+
+If
+.I str
+contains any of the following special characters, it will be single-quoted
+(turned into a string which begins and ends with the single quote,
+also known as the ASCII apostrophe character).
+
+.ft B
+ \e * ? $ ` ~
+.ft R
+
+Otherwise, if it contains single quotes
+it will be double-quoted (surrounded in double quotes).
+
+Otherwise, if it contains double quotes, it will be
+single-quoted.
+
+Otherwise, if it contains spaces, tabs or newlines, it will
+be double-quoted.
+
+If none of the above cases apply,
+.I str
+is returned unmodified.
+
+If single quoting is applied to a string which contains single quote
+characters, those characters are replaced by the sequence
+.BR '\e'' .
+
+If double quoting is applied to a string which contains double quotes,
+those characters are replaced by
+.BR \e" .
+
+.B Examples:
+
+.ft B
+ // safely execute mv
+
+ function mv(from, to)
+ {
+ system("mv -- " q(from) " " q(to))
+ }
+
+ // code // output
+ print q("abc") abc
+ print q("ab cd") "ab cd"
+ print q("ab\enc") "ab
+ c"
+ print q("ab'cd") "ab'cd"
+ print q("ab\e"cd") 'ab"cd'
+ print q("abc*") 'abc*'
+.ft R
+
+
+.SH "SEE ALSO"
+
+cppawk(1)
+
+.SH BUGS
+
+.SH AUTHOR
+Kaz Kylheku <kaz@kylheku.com>
+
+.SH COPYRIGHT
+Copyright 2023, BSD2 License.
diff --git a/runtests b/runtests
index 961bc19..91ff3c6 100755
--- a/runtests
+++ b/runtests
@@ -41,3 +41,8 @@ if [ -z "$suite" -o "$suite" = "array" ] ; then
cppawk=./bin/cppawk ./testsuite.awk testcases-array
cppawk="./bin/cppawk --awk=mawk" ./testsuite.awk -v skip=5,6 testcases-array
fi
+
+if [ -z "$suite" -o "$suite" = "quote" ] ; then
+ cppawk=./bin/cppawk ./testsuite.awk testcases-quote
+ cppawk="./bin/cppawk --awk=mawk" ./testsuite.awk testcases-quote
+fi
diff --git a/share/cppawk/include/quote-priv.h b/share/cppawk/include/quote-priv.h
new file mode 100644
index 0000000..1dd635d
--- /dev/null
+++ b/share/cppawk/include/quote-priv.h
@@ -0,0 +1,69 @@
+// cppawk: C preprocessor wrapper around awk
+// Copyright 2023 Kaz Kylheku <kaz@kylheku.com>
+//
+// BSD-2 License
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef __CPPAWK_QUOTE_PRIV_H
+#define __CPPAWK_QUOTE_PRIV_H
+
+function __squote(__str)
+{
+ gsub("'", "'\\''", __str)
+ return "'" __str "'"
+}
+
+function __dquote(__str)
+{
+ gsub("\"", "\\\"", __str)
+ return "\"" __str "\""
+}
+
+function __quote(__str,
+ __dquot_present,
+ __squot_present,
+ __meta_present,
+ __space_present)
+{
+ __dquot_present = __str ~ "\""
+ __squot_present = __str ~ "'"
+ __meta_present = __str ~ "[\\\\*?$`~]"
+ __space_present = __str ~ "[\\t\\n ]"
+
+ if (__meta_present)
+ return __squote(__str)
+
+ if (__squot_present)
+ return __dquote(__str)
+
+ if (__dquot_present)
+ return "'" __str "'"
+
+ if (__space_present)
+ return __dquote(__str)
+
+ return __str
+}
+
+#endif
diff --git a/share/cppawk/include/quote.h b/share/cppawk/include/quote.h
new file mode 100644
index 0000000..9b91568
--- /dev/null
+++ b/share/cppawk/include/quote.h
@@ -0,0 +1,37 @@
+// cppawk: C preprocessor wrapper around awk
+// Copyright 2023 Kaz Kylheku <kaz@kylheku.com>
+//
+// BSD-2 License
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef __CPPAWK_QUOTE_H
+#define __CPPAWK_QUOTE_H
+
+#ifndef __CPPAWK_QUOTE_PRIV_H
+#include "quote-priv.h"
+#endif
+
+#define q(str) __quote(str)
+
+#endif
diff --git a/testcases-quote b/testcases-quote
new file mode 100644
index 0000000..272261b
--- /dev/null
+++ b/testcases-quote
@@ -0,0 +1,36 @@
+1:
+$cppawk '
+#include <quote.h>
+
+BEGIN {
+ print q("")
+ print q("abc")
+ print q("abc\\def")
+ print q("'\''foo'\''")
+ print q("\"foo\"")
+ print q("\"fo'\''o\"")
+ print q("abc\ndef")
+ print q("abc*def")
+ print q("abc?def")
+ print q("abc`def")
+ print q("abc`de'\''f")
+ print q("a b c")
+ print q("a\tb\tc")
+ print q("~bob/foo")
+}'
+:
+
+abc
+'abc\def'
+"'foo'"
+'"foo"'
+"\"fo'o\""
+"abc
+def"
+'abc*def'
+'abc?def'
+'abc`def'
+'abc`de'\''f'
+"a b c"
+"a b c"
+'~bob/foo'