* [PATCH] Allow commit (and tag) messages to be edited when $EDITOR has arguments
@ 2007-12-16 1:12 Steven Grimm
2007-12-16 1:41 ` Johannes Schindelin
2007-12-16 1:41 ` [PATCH] " Thomas Harning
0 siblings, 2 replies; 5+ messages in thread
From: Steven Grimm @ 2007-12-16 1:12 UTC (permalink / raw)
To: git
Users who do EDITOR="/usr/bin/emacs -nw" or similar were left unable to
edit commit messages once commit became a builtin, because the editor
launch code assumed that $EDITOR was a single pathname.
Signed-off-by: Steven Grimm <koreth@midwinter.com>
---
Looked around but didn't see an existing "build a char* array
out of a delimited string" function in the git source; if one
exists, of course it should be used instead of my pair of loops
here.
builtin-tag.c | 27 ++++++++++++++++++++++++++-
1 files changed, 26 insertions(+), 1 deletions(-)
diff --git a/builtin-tag.c b/builtin-tag.c
index 274901a..dace758 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -47,10 +47,35 @@ void launch_editor(const char *path, struct strbuf *buffer, const char *const *e
editor = "vi";
if (strcmp(editor, ":")) {
- const char *args[] = { editor, path, NULL };
+ char *editor_copy, *c;
+ int args_size = 3, args_pos = 0;
+ char **args;
+
+ /* Parse the editor command, since it can contain arguments.
+ * First count the number of arguments so we can allocate an
+ * appropriately-sized arg array.
+ */
+ editor_copy = xstrdup(editor);
+ for (c = editor_copy; *c != '\0'; c++) {
+ if (*c == ' ') {
+ args_size++;
+ }
+ }
+
+ args = xmalloc(sizeof(char *) * args_size);
+ for (c = strtok(editor_copy, " "); c != NULL;
+ c = strtok(NULL, " ")) {
+ args[args_pos++] = c;
+ }
+
+ args[args_pos++] = path;
+ args[args_pos++] = NULL;
if (run_command_v_opt_cd_env(args, 0, NULL, env))
die("There was a problem with the editor %s.", editor);
+
+ free(args);
+ free(editor_copy);
}
if (!buffer)
--
1.5.4.rc0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] Allow commit (and tag) messages to be edited when $EDITOR has arguments
2007-12-16 1:12 [PATCH] Allow commit (and tag) messages to be edited when $EDITOR has arguments Steven Grimm
@ 2007-12-16 1:41 ` Johannes Schindelin
2007-12-16 7:34 ` [PATCH v2] " Steven Grimm
2007-12-16 1:41 ` [PATCH] " Thomas Harning
1 sibling, 1 reply; 5+ messages in thread
From: Johannes Schindelin @ 2007-12-16 1:41 UTC (permalink / raw)
To: Steven Grimm; +Cc: git
Hi,
On Sat, 15 Dec 2007, Steven Grimm wrote:
> Looked around but didn't see an existing "build a char* array
> out of a delimited string" function in the git source; if one
> exists, of course it should be used instead of my pair of loops
> here.
Did you look for split_cmdline() in git.c? IMHO it should move to
run-command.c and be made public.
Thanks,
Dscho
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Allow commit (and tag) messages to be edited when $EDITOR has arguments
2007-12-16 1:12 [PATCH] Allow commit (and tag) messages to be edited when $EDITOR has arguments Steven Grimm
2007-12-16 1:41 ` Johannes Schindelin
@ 2007-12-16 1:41 ` Thomas Harning
1 sibling, 0 replies; 5+ messages in thread
From: Thomas Harning @ 2007-12-16 1:41 UTC (permalink / raw)
To: Steven Grimm; +Cc: git
Steven Grimm wrote:
> Users who do EDITOR="/usr/bin/emacs -nw" or similar were left unable to
> edit commit messages once commit became a builtin, because the editor
> launch code assumed that $EDITOR was a single pathname.
>
I see one problem with this code... If you use quotes (single or
double) then this will break it. I suppose this isn't a major issue
usually, but if not fixed should be documented. One case that jumps out
of my head is an executable path with spaces (quite stupid-and-ugly, but
possible).
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2] Allow commit (and tag) messages to be edited when $EDITOR has arguments
2007-12-16 1:41 ` Johannes Schindelin
@ 2007-12-16 7:34 ` Steven Grimm
2007-12-16 15:36 ` Johannes Schindelin
0 siblings, 1 reply; 5+ messages in thread
From: Steven Grimm @ 2007-12-16 7:34 UTC (permalink / raw)
To: git
Users who do EDITOR="/usr/bin/emacs -nw" or similar were left unable to
edit commit messages once commit became a builtin, because the editor
launch code assumed that $EDITOR was a single pathname.
This patch makes split_cmdline() a public function as suggested by
Johannes Schindelin, and renames an internal function in git.c to avoid
a name collision.
Signed-off-by: Steven Grimm <koreth@midwinter.com>
---
builtin-tag.c | 14 +++++++++++-
git.c | 60 +++-------------------------------------------------
run-command.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
run-command.h | 2 +
4 files changed, 84 insertions(+), 57 deletions(-)
diff --git a/builtin-tag.c b/builtin-tag.c
index 274901a..0a38724 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -47,10 +47,22 @@ void launch_editor(const char *path, struct strbuf *buffer, const char *const *e
editor = "vi";
if (strcmp(editor, ":")) {
- const char *args[] = { editor, path, NULL };
+ char *editor_copy = xstrdup(editor);
+ char **args;
+ int args_pos;
+
+ args_pos = split_cmdline(editor_copy, &args, 2);
+ if (args_pos < 0)
+ die("Couldn't parse the editor command %s.", editor);
+
+ args[args_pos++] = path;
+ args[args_pos++] = NULL;
if (run_command_v_opt_cd_env(args, 0, NULL, env))
die("There was a problem with the editor %s.", editor);
+
+ free(args);
+ free(editor_copy);
}
if (!buffer)
diff --git a/git.c b/git.c
index 15fec89..3d095ee 100644
--- a/git.c
+++ b/git.c
@@ -2,6 +2,7 @@
#include "exec_cmd.h"
#include "cache.h"
#include "quote.h"
+#include "run-command.h"
const char git_usage_string[] =
"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]";
@@ -98,59 +99,6 @@ static int git_alias_config(const char *var, const char *value)
return 0;
}
-static int split_cmdline(char *cmdline, const char ***argv)
-{
- int src, dst, count = 0, size = 16;
- char quoted = 0;
-
- *argv = xmalloc(sizeof(char*) * size);
-
- /* split alias_string */
- (*argv)[count++] = cmdline;
- for (src = dst = 0; cmdline[src];) {
- char c = cmdline[src];
- if (!quoted && isspace(c)) {
- cmdline[dst++] = 0;
- while (cmdline[++src]
- && isspace(cmdline[src]))
- ; /* skip */
- if (count >= size) {
- size += 16;
- *argv = xrealloc(*argv, sizeof(char*) * size);
- }
- (*argv)[count++] = cmdline + dst;
- } else if(!quoted && (c == '\'' || c == '"')) {
- quoted = c;
- src++;
- } else if (c == quoted) {
- quoted = 0;
- src++;
- } else {
- if (c == '\\' && quoted != '\'') {
- src++;
- c = cmdline[src];
- if (!c) {
- free(*argv);
- *argv = NULL;
- return error("cmdline ends with \\");
- }
- }
- cmdline[dst++] = c;
- src++;
- }
- }
-
- cmdline[dst] = 0;
-
- if (quoted) {
- free(*argv);
- *argv = NULL;
- return error("unclosed quote");
- }
-
- return count;
-}
-
static int handle_alias(int *argcp, const char ***argv)
{
int nongit = 0, envchanged = 0, ret = 0, saved_errno = errno;
@@ -182,7 +130,7 @@ static int handle_alias(int *argcp, const char ***argv)
die("Failed to run '%s' when expanding alias '%s'\n",
alias_string + 1, alias_command);
}
- count = split_cmdline(alias_string, &new_argv);
+ count = split_cmdline(alias_string, &new_argv, 0);
option_count = handle_options(&new_argv, &count, &envchanged);
if (envchanged)
die("alias '%s' changes environment variables\n"
@@ -238,7 +186,7 @@ struct cmd_struct {
int option;
};
-static int run_command(struct cmd_struct *p, int argc, const char **argv)
+static int run_git_command(struct cmd_struct *p, int argc, const char **argv)
{
int status;
struct stat st;
@@ -380,7 +328,7 @@ static void handle_internal_command(int argc, const char **argv)
struct cmd_struct *p = commands+i;
if (strcmp(p->cmd, cmd))
continue;
- exit(run_command(p, argc, argv));
+ exit(run_git_command(p, argc, argv));
}
}
diff --git a/run-command.c b/run-command.c
index 476d00c..3ae55ec 100644
--- a/run-command.c
+++ b/run-command.c
@@ -237,3 +237,68 @@ int finish_async(struct async *async)
ret = error("waitpid (async) failed");
return ret;
}
+
+/*
+ * Parses a command line into an array of char* representing the tokens
+ * on the command line. Pass in a count to reserve some number of additional
+ * slots in the allocated array, e.g., so the caller can add a filename
+ * argument without having to reallocate the array.
+ *
+ * Returns the number of items in the array or -1 if an error occurred.
+ *
+ * Note that the command line will be altered (nulls will be inserted
+ * where the original had argument-delimiting whitespace.)
+ */
+int split_cmdline(char *cmdline, const char ***argv, int extra_slots)
+{
+ int src, dst, count = 0, size = extra_slots + 16;
+ char quoted = 0;
+
+ *argv = xmalloc(sizeof(char*) * size);
+
+ /* split alias_string */
+ (*argv)[count++] = cmdline;
+ for (src = dst = 0; cmdline[src];) {
+ char c = cmdline[src];
+ if (!quoted && isspace(c)) {
+ cmdline[dst++] = 0;
+ while (cmdline[++src]
+ && isspace(cmdline[src]))
+ ; /* skip */
+ if (count >= size) {
+ size += 16;
+ *argv = xrealloc(*argv, sizeof(char*) * size);
+ }
+ (*argv)[count++] = cmdline + dst;
+ } else if(!quoted && (c == '\'' || c == '"')) {
+ quoted = c;
+ src++;
+ } else if (c == quoted) {
+ quoted = 0;
+ src++;
+ } else {
+ if (c == '\\' && quoted != '\'') {
+ src++;
+ c = cmdline[src];
+ if (!c) {
+ free(*argv);
+ *argv = NULL;
+ return error("cmdline ends with \\");
+ }
+ }
+ cmdline[dst++] = c;
+ src++;
+ }
+ }
+
+ cmdline[dst] = 0;
+
+ if (quoted) {
+ free(*argv);
+ *argv = NULL;
+ return error("unclosed quote");
+ }
+
+ return count;
+}
+
diff --git a/run-command.h b/run-command.h
index 1fc781d..e2b5dea 100644
--- a/run-command.h
+++ b/run-command.h
@@ -66,4 +66,6 @@ struct async {
int start_async(struct async *async);
int finish_async(struct async *async);
+int split_cmdline(char *cmdline, const char ***argv, int extra_slots);
+
#endif
--
1.5.4.rc0.37.g176bc
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2] Allow commit (and tag) messages to be edited when $EDITOR has arguments
2007-12-16 7:34 ` [PATCH v2] " Steven Grimm
@ 2007-12-16 15:36 ` Johannes Schindelin
0 siblings, 0 replies; 5+ messages in thread
From: Johannes Schindelin @ 2007-12-16 15:36 UTC (permalink / raw)
To: Steven Grimm; +Cc: git
Hi,
On Sat, 15 Dec 2007, Steven Grimm wrote:
> @@ -238,7 +186,7 @@ struct cmd_struct {
> int option;
> };
>
> -static int run_command(struct cmd_struct *p, int argc, const char **argv)
> +static int run_git_command(struct cmd_struct *p, int argc, const char **argv)
> {
> int status;
> struct stat st;
Funny ;-) I have a similar change in my (now-inactive until 1.5.4) tree,
but I renamed it to execv_git_builtin (because it is not supposed to
return in case of success).
> diff --git a/run-command.c b/run-command.c
> index 476d00c..3ae55ec 100644
> --- a/run-command.c
> +++ b/run-command.c
> @@ -237,3 +237,68 @@ int finish_async(struct async *async)
> ret = error("waitpid (async) failed");
> return ret;
> }
> +
> +/*
> + * Parses a command line into an array of char* representing the tokens
> + * on the command line. Pass in a count to reserve some number of additional
> + * slots in the allocated array, e.g., so the caller can add a filename
> + * argument without having to reallocate the array.
In the editor call, you said "2" for this, but I suspect that you counted
the NULL extra. However, in git.c you said "0", thus not counting the
NULL. IMHO it makes sense _not_ to count the NULL (and NULL-terminate
the list _always_).
> +int split_cmdline(char *cmdline, const char ***argv, int extra_slots)
> +{
> + int src, dst, count = 0, size = extra_slots + 16;
> + char quoted = 0;
> +
> + *argv = xmalloc(sizeof(char*) * size);
> +
> + /* split alias_string */
s/alias_string/the command line/
> + (*argv)[count++] = cmdline;
> + for (src = dst = 0; cmdline[src];) {
> + char c = cmdline[src];
> + if (!quoted && isspace(c)) {
> + cmdline[dst++] = 0;
> + while (cmdline[++src]
> + && isspace(cmdline[src]))
> + ; /* skip */
> + if (count >= size) {
s/count/count + extra_slots/
> + size += 16;
> + *argv = xrealloc(*argv, sizeof(char*) * size);
This seems a nice candidate for ALLOC_GROW() in any case:
ALLOC_GROW(*argv, count + extra_slots + 1, size);
> + }
> + (*argv)[count++] = cmdline + dst;
> + } else if(!quoted && (c == '\'' || c == '"')) {
> + quoted = c;
> + src++;
> + } else if (c == quoted) {
> + quoted = 0;
> + src++;
> + } else {
> + if (c == '\\' && quoted != '\'') {
> + src++;
> + c = cmdline[src];
> + if (!c) {
> + free(*argv);
> + *argv = NULL;
> + return error("cmdline ends with \\");
> + }
> + }
> + cmdline[dst++] = c;
> + src++;
> + }
> + }
> +
> + cmdline[dst] = 0;
> +
> + if (quoted) {
> + free(*argv);
> + *argv = NULL;
> + return error("unclosed quote");
> + }
AFAICT the argv were not NULL terminated before. But now that the
function is public, it is safer to do so:
(*argv)[count] = NULL;
> +
> + return count;
> +}
> +
Thanks,
Dscho
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2007-12-16 15:37 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-12-16 1:12 [PATCH] Allow commit (and tag) messages to be edited when $EDITOR has arguments Steven Grimm
2007-12-16 1:41 ` Johannes Schindelin
2007-12-16 7:34 ` [PATCH v2] " Steven Grimm
2007-12-16 15:36 ` Johannes Schindelin
2007-12-16 1:41 ` [PATCH] " Thomas Harning
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).