These functions help substitute %foo% in an alias command to real values, then run the alias and return the first line from stdout. The normal use case is: /* extract all %xxx% from cmd to params */ extract_alias_params(cmd, params); param = lookup_alias_param(params, "%foo%"); if (param) param->value = "value for %foo%"; param = lookup_alias_param(params, "%bar%"); if (param) param->value = "value for %bar%"; /* substitute %foo% and %bar% */ expand_alias_params(cmd, params); free_alias_params(params); if (!get_alias_oneline(alias, cmd, output)) /* do something with output->buf here */ Signed-off-by: Nguyán ThÃi Ngác Duy <pclouds@xxxxxxxxx> --- alias.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cache.h | 11 +++++ 2 files changed, 150 insertions(+), 0 deletions(-) diff --git a/alias.c b/alias.c index eb9f08b..6626bb0 100644 --- a/alias.c +++ b/alias.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "run-command.h" static const char *alias_key; static char *alias_val; @@ -85,3 +86,141 @@ int split_cmdline(char *cmdline, const char ***argv) const char *split_cmdline_strerror(int split_cmdline_errno) { return split_cmdline_errors[-split_cmdline_errno-1]; } + +int extract_alias_params(const char *cmd, struct alias_param **params) +{ + const char *s = cmd; + int nr_param = 0; + + *params = NULL; + while (s && (s = strchr(s, '%')) != NULL) { + int len = strcspn(s+1, "% ")+2; + if (len < 2 || s[len-1] != '%') + return error("malformed parameter at %s", s); + nr_param++; + *params = xrealloc(*params, sizeof(struct alias_param)*nr_param); + (*params)[nr_param-1].param = xstrndup(s, len); + (*params)[nr_param-1].pos = s - cmd; + (*params)[nr_param-1].value = NULL; + s += len; + } + + nr_param++; + *params = xrealloc(*params, sizeof(struct alias_param)*nr_param); + (*params)[nr_param-1].param = NULL; + (*params)[nr_param-1].value = NULL; + return 0; +} + +struct alias_param *lookup_alias_param(struct alias_param *params, const char *param) +{ + int i; + for (i = 0; params[i].param; i++) + if (!strcmp(params[i].param, param)) + return params+i; + return NULL; +} + +int expand_alias_params(struct strbuf *cmd, const struct alias_param *params) +{ + int i, offset = 0; + + /* TODO: quote for '!' commands */ + for (i = 0; params[i].param; i++) { + if (!params[i].value) + return error("param %s not substituted", params[i].param); + strbuf_splice(cmd, + params[i].pos + offset, strlen(params[i].param), + params[i].value, strlen(params[i].value)); + offset += strlen(params[i].value) - strlen(params[i].param); + } + + return 0; +} + +void free_alias_params(struct alias_param *params) +{ + int i; + for (i = 0; params[i].param; i++) { + free(params[i].param); + free(params[i].value); + } + free(params); +} + +static void *wait_and_finish(void *arg) +{ + struct child_process *cp = arg; + char buf[1024]; + while (xread(cp->out, buf, 1024) > 0) + ; + close(cp->out); + finish_command(cp); + free(cp->argv); + free(cp); + return (void *) (intptr_t) 0; +} + +static int start_support_alias(const char *alias, char *cmd, struct child_process **cpp) +{ + struct child_process *cp; + const char **argv; + int count; + + cp = xmalloc(sizeof(struct child_process)); + memset(cp, 0, sizeof(struct child_process)); + cp->in = 0; + cp->out = -1; + + if (cmd[0] == '!') { + argv = xmalloc(sizeof(*argv)*4); + argv[0] = "/bin/sh"; + argv[1] = "-c"; + argv[2] = cmd+1; + argv[3] = NULL; + } + else { + count = split_cmdline(cmd, &argv); + if (count < 0) { + free(cp); + return error("Bad alias %s: %s", cmd, split_cmdline_strerror(count)); + } + cp->git_cmd = 1; + } + + cp->argv = argv; + if (start_command(cp)) { + error("Failed to run %s", cmd); + free(cp); + free(argv); + return -1; + } + *cpp = cp; + return 0; +} + +int get_alias_oneline(const char *alias, char *cmd, struct strbuf *ref) +{ + struct child_process *cp; + FILE *fp; + int ret; + + ret = start_support_alias(alias, cmd, &cp); + if (ret) + return ret; + + fp = fdopen(cp->out, "r"); + ret = strbuf_getline(ref, fp, '\n'); + if (!ret) { + /* let it finish, if there's error, users should know */ +#ifdef NO_PTHREADS + wait_and_finish(cp); +#else + pthread_t thread; + pthread_create(&thread, NULL, wait_and_finish, cp); +#endif + return 0; + } + wait_and_finish(cp); + return -1; +} diff --git a/cache.h b/cache.h index e83bc2d..20a37ff 100644 --- a/cache.h +++ b/cache.h @@ -1113,10 +1113,21 @@ extern int ws_blank_line(const char *line, int len, unsigned ws_rule); int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset); void overlay_tree_on_cache(const char *tree_name, const char *prefix); +struct alias_param { + char *param; + int pos; + char *value; +}; + char *alias_lookup(const char *alias); int split_cmdline(char *cmdline, const char ***argv); /* Takes a negative value returned by split_cmdline */ const char *split_cmdline_strerror(int cmdline_errno); +int extract_alias_params(const char *cmd, struct alias_param **params); +struct alias_param *lookup_alias_param(struct alias_param *params, const char *param); +int expand_alias_params(struct strbuf *cmd, const struct alias_param *params); +void free_alias_params(struct alias_param *params); +int get_alias_oneline(const char *alias, char *cmd, struct strbuf *result); /* git.c */ struct startup_info { -- 1.7.3.3.476.g10a82 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html