git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Alex Riesen <fork0@t-online.de>
Date
Jul 24, 2006, 23:12 UTC
Message-ID
<20060724231259.GA14792@steel.home>
In-Reply-To
<7vwta3h7r2.fsf@assigned-by-dhcp.cox.net>
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>
---
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;
 
Previous: Junio C Hamano
Message 3 of 3 in “add git-quote: shell and C quoting tool”
  1. 1/2 add git-quote: shell and C quoting toolAlex Riesen, Jul 16, 2006
  2. Junio C HamanoJul 24, 2006
  3. Alex RiesenJul 24, 2006

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.