summaryrefslogtreecommitdiff
path: root/quote.c
diff options
context:
space:
mode:
Diffstat (limited to 'quote.c')
-rw-r--r--quote.c94
1 files changed, 73 insertions, 21 deletions
diff --git a/quote.c b/quote.c
index 92e07f0..e662a7d 100644
--- a/quote.c
+++ b/quote.c
@@ -2,43 +2,95 @@
#include "quote.h"
/* Help to copy the thing properly quoted for the shell safety.
- * any single quote is replaced with '\'', and the caller is
- * expected to enclose the result within a single quote pair.
+ * any single quote is replaced with '\'', any exclamation point
+ * is replaced with '\!', and the whole thing is enclosed in a
*
* E.g.
* original sq_quote result
* name ==> name ==> 'name'
* a b ==> a b ==> 'a b'
* a'b ==> a'\''b ==> 'a'\''b'
+ * a!b ==> a'\!'b ==> 'a'\!'b'
*/
-char *sq_quote(const char *src)
+#undef EMIT
+#define EMIT(x) ( (++len < n) && (*bp++ = (x)) )
+
+static inline int need_bs_quote(char c)
{
- static char *buf = NULL;
- int cnt, c;
- const char *cp;
- char *bp;
+ return (c == '\'' || c == '!');
+}
- /* count bytes needed to store the quoted string. */
- for (cnt = 3, cp = src; *cp; cnt++, cp++)
- if (*cp == '\'')
- cnt += 3;
+size_t sq_quote_buf(char *dst, size_t n, const char *src)
+{
+ char c;
+ char *bp = dst;
+ size_t len = 0;
- buf = xmalloc(cnt);
- bp = buf;
- *bp++ = '\'';
+ EMIT('\'');
while ((c = *src++)) {
- if (c != '\'')
- *bp++ = c;
- else {
- bp = strcpy(bp, "'\\''");
- bp += 4;
+ if (need_bs_quote(c)) {
+ EMIT('\'');
+ EMIT('\\');
+ EMIT(c);
+ EMIT('\'');
+ } else {
+ EMIT(c);
}
}
- *bp++ = '\'';
- *bp = 0;
+ EMIT('\'');
+
+ if ( n )
+ *bp = 0;
+
+ return len;
+}
+
+char *sq_quote(const char *src)
+{
+ char *buf;
+ size_t cnt;
+
+ cnt = sq_quote_buf(NULL, 0, src) + 1;
+ buf = xmalloc(cnt);
+ sq_quote_buf(buf, cnt, src);
+
return buf;
}
+char *sq_dequote(char *arg)
+{
+ char *dst = arg;
+ char *src = arg;
+ char c;
+
+ if (*src != '\'')
+ return NULL;
+ for (;;) {
+ c = *++src;
+ if (!c)
+ return NULL;
+ if (c != '\'') {
+ *dst++ = c;
+ continue;
+ }
+ /* We stepped out of sq */
+ switch (*++src) {
+ case '\0':
+ *dst = 0;
+ return arg;
+ case '\\':
+ c = *++src;
+ if (need_bs_quote(c) && *++src == '\'') {
+ *dst++ = c;
+ continue;
+ }
+ /* Fallthrough */
+ default:
+ return NULL;
+ }
+ }
+}
+
/*
* C-style name quoting.
*