threads / patch / 4905

patch, 2 partsadd git-quote: shell and C quoting tool

Subject: [PATCH 1/2] add git-quote: shell and C quoting tool

## tl;dr

3 messages between Jul 16, 2006 and Jul 24, 2006. Diffs are folded; open one to read it.

replies: 2people: 2as markdown or json

Alex Riesen· Jul 16, 2006, 22:27 UTC · lore
Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---

As git-stripspace, it may ne useful for something. As an example, the next patch converts git-bisect.sh to use of this tool.

In case anyone asks why isn't it a standalone tool nor is it put into git-stripspace: I don't know. Maybe it should be.

 Makefile        |    3 +-
 builtin-quote.c |  102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 builtin.h       |    2 +
 git.c           |    1 +
 4 files changed, 107 insertions(+), 1 deletions(-)
Show changes to 4 files +107 −1

Makefile, builtin-quote.c, builtin.h, git.c

diff --git a/Makefile b/Makefile
index 01fb9cf..9fcbf3b 100644
--- a/Makefile
+++ b/Makefile
@@ -234,7 +234,8 @@ BUILTIN_OBJS = \
 	builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
 	builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
 	builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
-	builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o
+	builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o \
+	builtin-quote.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 LIBS = $(GITLIBS) -lz
diff --git a/builtin-quote.c b/builtin-quote.c
new file mode 100644
index 0000000..cbd822d
--- /dev/null
+++ b/builtin-quote.c
@@ -0,0 +1,102 @@
+/*
+ * "git quote" builtin command
+ *
+ * DOES NOT QUOTE \0 (truncates lines at it)
+ */
+#include "cache.h"
+#include "builtin.h"
+#include "quote.h"
+
+enum {SHELL_QUOTE, C_QUOTE};
+static int style = SHELL_QUOTE,
+	   use_stdin = 0;
+static const char *separator = NULL; /* default is space */
+static unsigned sep_len = 0;
+
+static const char builtin_quote_usage[] =
+"git-quote [--c] [--sep=<c-quoted> | -z] ( [--stdin] | [--] ... )";
+
+static void print_quoted(const char *text)
+{
+	switch (style)
+	{
+	case SHELL_QUOTE:
+		sq_quote_print(stdout, text);
+		break;
+	case C_QUOTE:
+		quote_c_style(text, NULL, stdout, 0);
+		break;
+	}
+	fwrite(separator, 1, sep_len, stdout);
+}
+
+int cmd_quote(int argc, const char **argv, char **envp)
+{
+	int i;
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+
+		if (arg[0] != '-')
+			break;
+		if (!strcmp(arg, "--")) {
+			i++;
+			break;
+		}
+		if (!strcmp(arg, "--stdin")) {
+			use_stdin = 1;
+			if ( !separator ) {
+				separator = "\n";
+				sep_len = 1;
+			}
+			break;
+		}
+		if (!strcmp(arg, "--c")) {
+			style = C_QUOTE;
+			continue;
+		}
+		if (!strcmp(arg, "-z")) {
+			separator = "";
+			sep_len = 1;
+			continue;
+		}
+		if (!strncmp(arg, "--sep=", 6)) {
+			const char *end;
+			char *tmp;
+			arg += 6;
+			if ('"' == *arg)
+				tmp = strdup(arg);
+			else {
+				size_t l = strlen(arg);
+				tmp = malloc(l + 3);
+				sprintf(tmp, "\"%s\"", arg);
+			}
+			separator = unquote_c_style(tmp, &end);
+			sep_len = strlen(separator);
+			/* this will leak if multiple --sep= given */
+			continue;
+		}
+		die(builtin_quote_usage);
+	}
+	if (!separator) {
+		sep_len = 1;
+		separator = "\x20";
+	}
+	if (use_stdin) {
+		size_t size = BUFSIZ;
+		char *buf = xmalloc(size);
+		int ch, pos = 0;
+		while (EOF != (ch = fgetc(stdin))) {
+			if (pos == size)
+				buf = xrealloc(buf, size <<= 1);
+			buf[pos++] = ch;
+			if ('\n' == ch) {
+				buf[--pos] = '\0';
+				pos = 0;
+				print_quoted(buf);
+			}
+		}
+	} else
+		for (; argv[i]; ++i)
+			print_quoted(argv[i]);
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index 5339d86..9bd522e 100644
--- a/builtin.h
+++ b/builtin.h
@@ -64,4 +64,6 @@ extern int mailinfo(FILE *in, FILE *out,
 
 extern int cmd_stripspace(int argc, const char **argv, char **envp);
 extern void stripspace(FILE *in, FILE *out);
+
+extern int cmd_quote(int argc, const char **argv, char **envp);
 #endif
diff --git a/git.c b/git.c
index ee5a0e8..f94d25a 100644
--- a/git.c
+++ b/git.c
@@ -202,6 +202,7 @@ static void handle_internal_command(int 
 		{ "update-ref", cmd_update_ref },
 		{ "fmt-merge-msg", cmd_fmt_merge_msg },
 		{ "prune", cmd_prune },
+		{ "quote", cmd_quote },
 	};
 	int i;
 
-- 
1.4.1.gb944
Junio C Hamano· Jul 24, 2006, 05:49 UTC · re: Alex Riesen · lore

Re: [PATCH 1/2] add git-quote: shell and C quoting tool

fork0@t-online.de (Alex Riesen) writes:
> In case anyone asks why isn't it a standalone tool nor is it put into
> git-stripspace: I don't know. Maybe it should be.
This organization is fine by me.
 * unquote?
 * doc?
> +enum {SHELL_QUOTE, C_QUOTE};
> +static int style = SHELL_QUOTE,
> +	   use_stdin = 0;
Shouldn't style be of type which is that unnamed enum?
> +static const char *separator = NULL; /* default is space */
> +static unsigned sep_len = 0;

It is not clear if this is separator of input side or output side (after reading the code it becomes somewhat obvious that you are talking about output separator), and if the default is space wouldn't it make more sense to set that here?

Show 14 quoted lines
> +static const char builtin_quote_usage[] =
> +"git-quote [--c] [--sep=<c-quoted> | -z] ( [--stdin] | [--] ... )";
> +
> +static void print_quoted(const char *text)
> +{
> +	switch (style)
> +	{
> +	case SHELL_QUOTE:
> +		sq_quote_print(stdout, text);
> +		break;
> +	case C_QUOTE:
> +		quote_c_style(text, NULL, stdout, 0);
> +		break;
> +	}

Not a big deal but aren't these going to write out things quoted when they do not need to? To help scripts, it might be worth adding "check if this needs quoting" interface perhaps?

Show 21 quoted lines
> +int cmd_quote(int argc, const char **argv, char **envp)
> +{
> +	int i;
> +	for (i = 1; i < argc; i++) {
> +		const char *arg = argv[i];
> +
> +		if (arg[0] != '-')
> +			break;
> +		if (!strcmp(arg, "--")) {
> +			i++;
> +			break;
> +		}
> +		if (!strcmp(arg, "--stdin")) {
> +			use_stdin = 1;
> +			if ( !separator ) {
> +				separator = "\n";
> +				sep_len = 1;
> +			}
> +			break;
> +		}
> +		if (!strcmp(arg, "--c")) {

Perhaps "--c-style" with "-c" as a shorthand, (and "--shell-style" with "-s" to complement)?

Show 8 quoted lines
> +			style = C_QUOTE;
> +			continue;
> +		}
> +		if (!strcmp(arg, "-z")) {
> +			separator = "";
> +			sep_len = 1;
> +			continue;
> +		}

Is it plausible that somebody might want to feed you NUL terminated sequence as input (iow you might want to give them choice of separator on the input side)?

> +		if (!strncmp(arg, "--sep=", 6)) {

Perhaps "--separator" (or "--output-separator") with whatever shorthand is handy?

Show 12 quoted lines
> +			const char *end;
> +			char *tmp;
> +			arg += 6;
> +			if ('"' == *arg)
> +				tmp = strdup(arg);
> +			else {
> +				size_t l = strlen(arg);
> +				tmp = malloc(l + 3);
> +				sprintf(tmp, "\"%s\"", arg);
> +			}
> +			separator = unquote_c_style(tmp, &end);
> +			sep_len = strlen(separator);

If the parameter is a malformed c-quoted string, you would dump core here.

Show 8 quoted lines
> +			/* this will leak if multiple --sep= given */
> +			continue;
> +		}
> +		die(builtin_quote_usage);
> +	}
> +	if (!separator) {
> +		sep_len = 1;
> +		separator = "\x20";

Any reason you needed to spell it in hex? Is this trying to be portable to EBCDIC (or trying to prevent the code to be ported there)? I dunno.

Show 15 quoted lines
> +	}
> +	if (use_stdin) {
> +		size_t size = BUFSIZ;
> +		char *buf = xmalloc(size);
> +		int ch, pos = 0;
> +		while (EOF != (ch = fgetc(stdin))) {
> +			if (pos == size)
> +				buf = xrealloc(buf, size <<= 1);
> +			buf[pos++] = ch;
> +			if ('\n' == ch) {
> +				buf[--pos] = '\0';
> +				pos = 0;
> +				print_quoted(buf);
> +			}
> +		}
Looks similar to strbuf.c::read_line() loop...
Alex Riesen· Jul 24, 2006, 23:12 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/2] add git-quote: shell and C quoting tool

Junio C Hamano, Mon, Jul 24, 2006 07:49:53 +0200:
Show 6 quoted lines
> > In case anyone asks why isn't it a standalone tool nor is it put into
> > git-stripspace: I don't know. Maybe it should be.
> 
> This organization is fine by me.
> 
>  * unquote?

Not done yet. I actually never expected it to be used for unquoting, being naturally unquoted by bash. C-quoting was done just because it was so simple to do. I have no idea where could that be used.

>  * doc?
Done. Sorry for missing that.
Show 5 quoted lines
> > +enum {SHELL_QUOTE, C_QUOTE};
> > +static int style = SHELL_QUOTE,
> > +	   use_stdin = 0;
> 
> Shouldn't style be of type which is that unnamed enum?
It should. Done.
Show 7 quoted lines
> > +static const char *separator = NULL; /* default is space */
> > +static unsigned sep_len = 0;
> 
> It is not clear if this is separator of input side or output
> side (after reading the code it becomes somewhat obvious that
> you are talking about output separator), and if the default is
> space wouldn't it make more sense to set that here?
Right. It is out_separator now.
Show 18 quoted lines
> > +static const char builtin_quote_usage[] =
> > +"git-quote [--c] [--sep=<c-quoted> | -z] ( [--stdin] | [--] ... )";
> > +
> > +static void print_quoted(const char *text)
> > +{
> > +	switch (style)
> > +	{
> > +	case SHELL_QUOTE:
> > +		sq_quote_print(stdout, text);
> > +		break;
> > +	case C_QUOTE:
> > +		quote_c_style(text, NULL, stdout, 0);
> > +		break;
> > +	}
> 
> Not a big deal but aren't these going to write out things quoted
> when they do not need to?  To help scripts, it might be worth
> adding "check if this needs quoting" interface perhaps?
Not done yet. "--no-overquote"?
> > +		if (!strcmp(arg, "--c")) {
> 
> Perhaps "--c-style" with "-c" as a shorthand, (and
> "--shell-style" with "-s" to complement)?
Done. --sh-style.
Show 12 quoted lines
> > +			style = C_QUOTE;
> > +			continue;
> > +		}
> > +		if (!strcmp(arg, "-z")) {
> > +			separator = "";
> > +			sep_len = 1;
> > +			continue;
> > +		}
> 
> Is it plausible that somebody might want to feed you NUL
> terminated sequence as input (iow you might want to give them
> choice of separator on the input side)?

Done. -z sets both separators to NUL, --in-separator=<c-style> defines by its first character the input separator. I.e.:

$ find | git quote -z --in-separator='\n' 'a'\0'b'\0''

which is not all that useful...
> > +		if (!strncmp(arg, "--sep=", 6)) {
> 
> Perhaps "--separator" (or "--output-separator") with whatever
> shorthand is handy?
--out-separator. No idea of a shortcut, though
Show 5 quoted lines
> > +			separator = unquote_c_style(tmp, &end);
> > +			sep_len = strlen(separator);
> 
> If the parameter is a malformed c-quoted string, you would dump
> core here.
Oops. Fixed.
Show 7 quoted lines
> > +	if (!separator) {
> > +		sep_len = 1;
> > +		separator = "\x20";
> 
> Any reason you needed to spell it in hex?  Is this trying to
> be portable to EBCDIC (or trying to prevent the code to be
> ported there)?  I dunno.

Visibility. I have dificulty seeing spaces and tabs. I changed it anyway, maybe that's just me.

> > +		while (EOF != (ch = fgetc(stdin))) {
> 
> Looks similar to strbuf.c::read_line() loop...
> 
Indeed. Replaced.

I attach the updated patch here, because it is obviously is not quite finished yet and I probably wont have enough time over the week. So maybe someone takes over. Or it'll be taken as is, that happens too.

Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---
Show changes to 5 files +198 −1

Documentation/git-quote.txt, Makefile, builtin-quote.c, builtin.h, git.c

diff --git a/Documentation/git-quote.txt b/Documentation/git-quote.txt
new file mode 100644
index 0000000..98b2859
--- /dev/null
+++ b/Documentation/git-quote.txt
@@ -0,0 +1,70 @@
+git-quote(1)
+============
+
+NAME
+----
+git-quote - Quote given text according to Shell or C rules
+
+
+SYNOPSIS
+--------
+'git-quote' [-c] [-s] [-s] [--out-separator=<c-quoted>] 
+	[--in-separator=<c-quoted>] [-z] [--] ...
+'git-quote' ... --stdin < <stream>
+
+DESCRIPTION
+-----------
+Quote the lines according to the given rules, which can be Shell backslash
+quoting (every line is enclosed in single ticks, backslash and single tick
+quoted specially) or a C quoting (use double ticks and backslash-prefixed
+symbols).
+
+The separator options are handled in the order they are given, so one
+can save some typing by giving "-z" first, and overriding input or
+output separator as needed.
+
+OPTIONS
+-------
+-c|--c-style::
+	Select C-style quoting
+
+-s|--sh-style::
+	Select Shell-style quoting. This is default.
+
+--out-separator=<c-quoted>::
+	Specify the separator between the output elements. If the separator
+	have to contain special characters, they must be quoted according
+	to C quoting rules (double ticks are not essential).
+	The ASCII space is default output separator.
+
+--in-separator=<c-quoted>::
+	Specify the separator between the input elements. Only the
+	first character of <c-quoted> is used.
+	Used only if --stdin is also given. The default is LF.
+
+-z::
+	Separate the elements on output and expect elements separated
+	on input with NUL character.
+	Used only if --stdin is also given.
+
+--stdin::
+	Specify that the elements have to be read from stdin.
+	This option ends command line parsing.
+	Also, if there were no output separator set by previous
+	--out-separator or -z, this option will set it to LF.
+
+<stream>::
+	Byte stream to act on.
+
+Author
+------
+Written by Alex Riesen <raa.lkml@gmail.com>
+
+Documentation
+--------------
+Documentation by Alex Riesen.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
diff --git a/Makefile b/Makefile
index 3e085df..4df2951 100644
--- a/Makefile
+++ b/Makefile
@@ -246,7 +246,8 @@ BUILTIN_OBJS = \
 	builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
 	builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
 	builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
-	builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o
+	builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o \
+	builtin-quote.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 LIBS = $(GITLIBS) -lz
diff --git a/builtin-quote.c b/builtin-quote.c
new file mode 100644
index 0000000..d9d4b00
--- /dev/null
+++ b/builtin-quote.c
@@ -0,0 +1,123 @@
+/*
+ * "git quote" builtin command
+ *
+ * DOES NOT QUOTE \0 (truncates lines at it)
+ */
+#include "cache.h"
+#include "builtin.h"
+#include "strbuf.h"
+#include "quote.h"
+
+static enum {SHELL_QUOTE, C_QUOTE} style = SHELL_QUOTE;
+static int use_stdin = 0;
+static const char *out_separator = NULL; /* default is space */
+static unsigned out_separator_len = 0;
+
+static const char builtin_quote_usage[] =
+"git-quote [-c | -s] [--out-separator=<c-quoted> | -z] ( [--stdin] | [--] ... )";
+
+static void print_quoted(const char *text)
+{
+	switch (style)
+	{
+	case SHELL_QUOTE:
+		sq_quote_print(stdout, text);
+		break;
+	case C_QUOTE:
+		quote_c_style(text, NULL, stdout, 0);
+		break;
+	}
+	fwrite(out_separator, 1, out_separator_len, stdout);
+}
+
+static char *unquote_c_arg(const char *arg)
+{
+	const char *end;
+	char *tmp;
+	char *result;
+	if ('"' == *arg)
+		tmp = strdup(arg);
+	else {
+		size_t l = strlen(arg);
+		tmp = malloc(l + 3);
+		sprintf(tmp, "\"%s\"", arg);
+	}
+	result = unquote_c_style(tmp, &end);
+	free(tmp);
+	return result;
+}
+
+int cmd_quote(int argc, const char **argv, char **envp)
+{
+	int in_separator = '\n';
+	int i;
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+
+		if (arg[0] != '-')
+			break;
+		if (!strcmp(arg, "--")) {
+			i++;
+			break;
+		}
+		if (!strcmp(arg, "--stdin")) {
+			use_stdin = 1;
+			if ( !out_separator ) {
+				out_separator = "\n";
+				out_separator_len = 1;
+			}
+			break;
+		}
+		if (!strcmp(arg, "--c-style") || !strcmp(arg, "-c")) {
+			style = C_QUOTE;
+			continue;
+		}
+		if (!strcmp(arg, "--sh-style") || !strcmp(arg, "-s")) {
+			style = SHELL_QUOTE;
+			continue;
+		}
+		if (!strcmp(arg, "-z")) {
+			in_separator = 0;
+			out_separator = "";
+			out_separator_len = 1;
+			continue;
+		}
+		if (!strncmp(arg, "--out-separator=", 16)) {
+			arg += 16;
+			out_separator = unquote_c_arg(arg);
+			if (!out_separator)
+				die("malformed separator '%s'", arg);
+			out_separator_len = strlen(out_separator);
+			/* this will leak if multiple --sep= given */
+			continue;
+		}
+		if (!strncmp(arg, "--in-separator=", 15)) {
+			char *sep;
+			arg += 15;
+			sep = unquote_c_arg(arg);
+			if (!sep || !*sep)
+				die("malformed separator '%s'", arg);
+			in_separator = *sep;
+			free(sep);
+			continue;
+		}
+		die(builtin_quote_usage);
+	}
+	if (!out_separator) {
+		out_separator_len = 1;
+		out_separator = " ";
+	}
+	if (use_stdin) {
+		struct strbuf line;
+		strbuf_init(&line);
+
+		while (!line.eof) {
+			read_line(&line, stdin, in_separator);
+			if (line.len)
+				print_quoted(line.buf);
+		}
+	} else
+		for (; argv[i]; ++i)
+			print_quoted(argv[i]);
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index 5339d86..9bd522e 100644
--- a/builtin.h
+++ b/builtin.h
@@ -64,4 +64,6 @@ extern int mailinfo(FILE *in, FILE *out,
 
 extern int cmd_stripspace(int argc, const char **argv, char **envp);
 extern void stripspace(FILE *in, FILE *out);
+
+extern int cmd_quote(int argc, const char **argv, char **envp);
 #endif
diff --git a/git.c b/git.c
index ee5a0e8..f94d25a 100644
--- a/git.c
+++ b/git.c
@@ -202,6 +202,7 @@ static void handle_internal_command(int 
 		{ "update-ref", cmd_update_ref },
 		{ "fmt-merge-msg", cmd_fmt_merge_msg },
 		{ "prune", cmd_prune },
+		{ "quote", cmd_quote },
 	};
 	int i;
 

← back to recent threads