Subject: [PATCH 1/3] Enhanced sq_quote()

From: "H. Peter Anvin" <[email-masked]>
Date: Mon, 10 Oct 2005 13:49:34 -0700

Create function to sq_quote into a buffer
Handle !'s for csh-based shells

Signed-off-by: H. Peter Anvin <[email-masked]>

---
commit cc114823f72bd8d912abf7f7a7515853c554a9f3
tree 9766b638ae175b9206855f2613e07507ed51fbca
parent d5b0c9ea178dab3599674ccff50645c0464b8c31
author Peter Anvin <[email-masked]> Mon, 10 Oct 2005 12:21:35 -0700
committer Peter Anvin <[email-masked]> Mon, 10 Oct 2005 12:21:35 -0700

 quote.c |   56 ++++++++++++++++++++++++++++++++++----------------------
 quote.h |   11 +++++++++--
 2 files changed, 43 insertions(+), 24 deletions(-)

diff --git a/quote.c b/quote.c
index 5e6fda3..9d5d0bc 100644
--- a/quote.c
+++ b/quote.c
@@ -2,40 +2,52 @@
 #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)
+#define EMIT(x) ( (++len < n) && (*bp++ = (x)) )
+
+size_t sq_quote_buf(char *dst, size_t n, const char *src)
 {
-	static char *buf = NULL;
-	int cnt, c;
-	const char *cp;
-	char *bp;
-
-	/* count bytes needed to store the quoted string. */
-	for (cnt = 3, cp = src; *cp; cnt++, cp++)
-		if (*cp == '\'')
-			cnt += 3;
+	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 (c == '\'' || 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;
 }
 
diff --git a/quote.h b/quote.h
index c8cfb3a..50ce1df 100644
--- a/quote.h
+++ b/quote.h
@@ -1,10 +1,12 @@
 #ifndef QUOTE_H
 #define QUOTE_H
 
+#include <stddef.h>
 
 /* Help to copy the thing properly quoted for the shell safety.
- * any single quote is replaced with '\'', and the whole thing
- * is enclosed in a single quote pair.
+ * any single quote is replaced with '\'', any exclamation point
+ * is replaced with '\!', and the whole thing is enclosed in a
+ * single quote pair.
  *
  * For example, if you are passing the result to system() as an
  * argument:
@@ -19,8 +21,13 @@
  *
  * Note that the above examples leak memory!  Remember to free result from
  * sq_quote() in a real application.
+ *
+ * sq_quote_buf() writes to an existing buffer of specified size; it
+ * will return the number of characters that would have been written
+ * excluding the final null regardless of the buffer size.
  */
 
 char *sq_quote(const char *src);
+size_t sq_quote_buf(char *dst, size_t n, const char *src);
 
 #endif