{"thread":{"id":"24086","subject":"[PATCH next] parseopt: wrap rev-parse --parseopt usage for eval consumption","startedAt":"2010-06-12T12:57:39Z","lastAt":"2010-06-12T12:57:39Z","messageCount":1,"participants":["Thomas Rast"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"143567","messageId":"49d2c5f5626b22c02d7528e76f9fbb36b7b96155.1276347347.git.trast@student.ethz.ch","threadId":"24086","inReplyTo":null,"subject":"[PATCH next] parseopt: wrap rev-parse --parseopt usage for eval consumption","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-06-12T12:57:39Z","receivedAt":"2010-06-12T12:57:39Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"9c7304e (print the usage string on stdout instead of stderr,\n2010-05-17) broke rev-parse --parseopt: when run with -h, the usage\nnotice on stdout ended up in the shell eval.\n\nWrap the usage in a cat <<\\EOF ... EOF block when printing to stdout.\nI do not expect any usage lines to ever start with EOF so this\nshouldn't be an undue burden.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nUnfortunately the impact is about half that of 9c7304e.  Maybe there's\na simpler solution that I'm missing.\n\n\n builtin/rev-parse.c           |    3 ++-\n parse-options.c               |   38 ++++++++++++++++++++++++--------------\n parse-options.h               |    3 ++-\n t/t1502-rev-parse-parseopt.sh |    4 +++-\n 4 files changed, 31 insertions(+), 17 deletions(-)\n\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 8fbf9d0..b676e29 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -408,7 +408,8 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \tmemset(opts + onb, 0, sizeof(opts[onb]));\n \targc = parse_options(argc, argv, prefix, opts, usage,\n \t\t\tkeep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0 |\n-\t\t\tstop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0);\n+\t\t\tstop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0 |\n+\t\t\tPARSE_OPT_SHELL_EVAL);\n \n \tstrbuf_addf(&parsed, \" --\");\n \tsq_quote_argv(&parsed, argv, 0);\ndiff --git a/parse-options.c b/parse-options.c\nindex c8aaf95..0fa79bc 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -4,7 +4,8 @@\n #include \"commit.h\"\n #include \"color.h\"\n \n-static int parse_options_usage(const char * const *usagestr,\n+static int parse_options_usage(struct parse_opt_ctx_t *ctx,\n+\t\t\t       const char * const *usagestr,\n \t\t\t       const struct option *opts, int err);\n \n #define OPT_SHORT 1\n@@ -351,7 +352,8 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,\n \t\tdie(\"STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together\");\n }\n \n-static int usage_with_options_internal(const char * const *,\n+static int usage_with_options_internal(struct parse_opt_ctx_t *,\n+\t\t\t\t       const char * const *,\n \t\t\t\t       const struct option *, int, int);\n \n int parse_options_step(struct parse_opt_ctx_t *ctx,\n@@ -380,10 +382,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,\n \t\tif (arg[1] != '-') {\n \t\t\tctx->opt = arg + 1;\n \t\t\tif (internal_help && *ctx->opt == 'h')\n-\t\t\t\treturn parse_options_usage(usagestr, options, 0);\n+\t\t\t\treturn parse_options_usage(ctx, usagestr, options, 0);\n \t\t\tswitch (parse_short_opt(ctx, options)) {\n \t\t\tcase -1:\n-\t\t\t\treturn parse_options_usage(usagestr, options, 1);\n+\t\t\t\treturn parse_options_usage(ctx, usagestr, options, 1);\n \t\t\tcase -2:\n \t\t\t\tgoto unknown;\n \t\t\t}\n@@ -391,10 +393,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,\n \t\t\t\tcheck_typos(arg + 1, options);\n \t\t\twhile (ctx->opt) {\n \t\t\t\tif (internal_help && *ctx->opt == 'h')\n-\t\t\t\t\treturn parse_options_usage(usagestr, options, 0);\n+\t\t\t\t\treturn parse_options_usage(ctx, usagestr, options, 0);\n \t\t\t\tswitch (parse_short_opt(ctx, options)) {\n \t\t\t\tcase -1:\n-\t\t\t\t\treturn parse_options_usage(usagestr, options, 1);\n+\t\t\t\t\treturn parse_options_usage(ctx, usagestr, options, 1);\n \t\t\t\tcase -2:\n \t\t\t\t\t/* fake a short option thing to hide the fact that we may have\n \t\t\t\t\t * started to parse aggregated stuff\n@@ -418,12 +420,12 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,\n \t\t}\n \n \t\tif (internal_help && !strcmp(arg + 2, \"help-all\"))\n-\t\t\treturn usage_with_options_internal(usagestr, options, 1, 0);\n+\t\t\treturn usage_with_options_internal(ctx, usagestr, options, 1, 0);\n \t\tif (internal_help && !strcmp(arg + 2, \"help\"))\n-\t\t\treturn parse_options_usage(usagestr, options, 0);\n+\t\t\treturn parse_options_usage(ctx, usagestr, options, 0);\n \t\tswitch (parse_long_opt(ctx, arg + 2, options)) {\n \t\tcase -1:\n-\t\t\treturn parse_options_usage(usagestr, options, 1);\n+\t\t\treturn parse_options_usage(ctx, usagestr, options, 1);\n \t\tcase -2:\n \t\t\tgoto unknown;\n \t\t}\n@@ -485,14 +487,18 @@ static int usage_argh(const struct option *opts, FILE *outfile)\n #define USAGE_OPTS_WIDTH 24\n #define USAGE_GAP         2\n \n-static int usage_with_options_internal(const char * const *usagestr,\n-\t\t\t\tconst struct option *opts, int full, int err)\n+static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,\n+\t\t\t\t       const char * const *usagestr,\n+\t\t\t\t       const struct option *opts, int full, int err)\n {\n \tFILE *outfile = err ? stderr : stdout;\n \n \tif (!usagestr)\n \t\treturn PARSE_OPT_HELP;\n \n+\tif (!err && ctx && ctx->flags & PARSE_OPT_SHELL_EVAL)\n+\t\tfprintf(outfile, \"cat <<\\\\EOF\\n\");\n+\n \tfprintf(outfile, \"usage: %s\\n\", *usagestr++);\n \twhile (*usagestr && **usagestr)\n \t\tfprintf(outfile, \"   or: %s\\n\", *usagestr++);\n@@ -548,13 +554,16 @@ static int usage_with_options_internal(const char * const *usagestr,\n \t}\n \tfputc('\\n', outfile);\n \n+\tif (!err && ctx && ctx->flags & PARSE_OPT_SHELL_EVAL)\n+\t\tfputs(\"EOF\\n\", outfile);\n+\n \treturn PARSE_OPT_HELP;\n }\n \n void usage_with_options(const char * const *usagestr,\n \t\t\tconst struct option *opts)\n {\n-\tusage_with_options_internal(usagestr, opts, 0, 1);\n+\tusage_with_options_internal(NULL, usagestr, opts, 0, 1);\n \texit(129);\n }\n \n@@ -566,10 +575,11 @@ void usage_msg_opt(const char *msg,\n \tusage_with_options(usagestr, options);\n }\n \n-static int parse_options_usage(const char * const *usagestr,\n+static int parse_options_usage(struct parse_opt_ctx_t *ctx,\n+\t\t\t       const char * const *usagestr,\n \t\t\t       const struct option *opts, int err)\n {\n-\treturn usage_with_options_internal(usagestr, opts, 0, err);\n+\treturn usage_with_options_internal(ctx, usagestr, opts, 0, err);\n }\n \n \ndiff --git a/parse-options.h b/parse-options.h\nindex 678b58d..7435cdb 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -36,7 +36,8 @@ enum parse_opt_option_flags {\n \tPARSE_OPT_LASTARG_DEFAULT = 16,\n \tPARSE_OPT_NODASH = 32,\n \tPARSE_OPT_LITERAL_ARGHELP = 64,\n-\tPARSE_OPT_NEGHELP = 128\n+\tPARSE_OPT_NEGHELP = 128,\n+\tPARSE_OPT_SHELL_EVAL = 256\n };\n \n struct option;\ndiff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh\nindex 660487d..4346795 100755\n--- a/t/t1502-rev-parse-parseopt.sh\n+++ b/t/t1502-rev-parse-parseopt.sh\n@@ -3,7 +3,8 @@\n test_description='test git rev-parse --parseopt'\n . ./test-lib.sh\n \n-cat > expect <<EOF\n+cat > expect <<\\END_EXPECT\n+cat <<\\EOF\n usage: some-command [options] <args>...\n \n     some-command does foo and bar!\n@@ -19,6 +20,7 @@ Extras\n     --extra1              line above used to cause a segfault but no longer does\n \n EOF\n+END_EXPECT\n \n cat > optionspec << EOF\n some-command [options] <args>...\n-- \n1.7.1.556.gfe6ec\n"}]}