summaryrefslogtreecommitdiff
path: root/src/buffer.c
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@microsoft.com>2015-09-23 16:30:48 -0400
committerEdward Thomson <ethomson@github.com>2016-05-26 13:01:06 -0500
commitd3d95d5ae2c0c06724d040713a04202073114041 (patch)
tree230acabe28ae3b49cc291d1ae90de5ce658bbced /src/buffer.c
parent72806f4cca7602460d19fbee8be98449304e92a2 (diff)
downloadlibgit2-d3d95d5ae2c0c06724d040713a04202073114041.tar.gz
git_buf_quote: quote ugly characters
Diffstat (limited to 'src/buffer.c')
-rw-r--r--src/buffer.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/buffer.c b/src/buffer.c
index c2a54a5bd..31341c4b5 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -858,6 +858,72 @@ int git_buf_splice(
return 0;
}
+/* Quote per http://marc.info/?l=git&m=112927316408690&w=2 */
+int git_buf_quote(git_buf *buf)
+{
+ const char whitespace[] = { 'a', 'b', 't', 'n', 'v', 'f', 'r' };
+ git_buf quoted = GIT_BUF_INIT;
+ size_t i = 0;
+ bool quote = false;
+ int error = 0;
+
+ /* walk to the first char that needs quoting */
+ if (buf->size && buf->ptr[0] == '!')
+ quote = true;
+
+ for (i = 0; !quote && i < buf->size; i++) {
+ if (buf->ptr[i] == '"' || buf->ptr[i] == '\\' ||
+ buf->ptr[i] < ' ' || buf->ptr[i] > '~') {
+ quote = true;
+ break;
+ }
+ }
+
+ if (!quote)
+ goto done;
+
+ git_buf_putc(&quoted, '"');
+ git_buf_put(&quoted, buf->ptr, i);
+
+ for (; i < buf->size; i++) {
+ /* whitespace - use the map above, which is ordered by ascii value */
+ if (buf->ptr[i] >= '\a' && buf->ptr[i] <= '\r') {
+ git_buf_putc(&quoted, '\\');
+ git_buf_putc(&quoted, whitespace[buf->ptr[i] - '\a']);
+ }
+
+ /* double quote and backslash must be escaped */
+ else if (buf->ptr[i] == '"' || buf->ptr[i] == '\\') {
+ git_buf_putc(&quoted, '\\');
+ git_buf_putc(&quoted, buf->ptr[i]);
+ }
+
+ /* escape anything unprintable as octal */
+ else if (buf->ptr[i] != ' ' &&
+ (buf->ptr[i] < '!' || buf->ptr[i] > '~')) {
+ git_buf_printf(&quoted, "\\%03o", buf->ptr[i]);
+ }
+
+ /* yay, printable! */
+ else {
+ git_buf_putc(&quoted, buf->ptr[i]);
+ }
+ }
+
+ git_buf_putc(&quoted, '"');
+
+ if (git_buf_oom(&quoted)) {
+ error = -1;
+ goto done;
+ }
+
+ git_buf_swap(&quoted, buf);
+
+done:
+ git_buf_free(&quoted);
+ return error;
+}
+
/* Unquote per http://marc.info/?l=git&m=112927316408690&w=2 */
int git_buf_unquote(git_buf *buf)
{