{"thread":{"id":"23825","subject":"[RFC][PATCH] Print the usage string on stdout instead of stderr.","startedAt":"2010-05-17T09:48:38Z","lastAt":"2010-05-25T08:40:46Z","messageCount":14,"participants":["Giuseppe Scrivano","Michael J Gruber","Miles Bader","Tay Ray Chuan"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"141801","messageId":"878w7ieu4p.fsf@thor.thematica.it","threadId":"23825","inReplyTo":null,"subject":"[RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Giuseppe Scrivano","fromEmail":"gscrivano@gnu.org","sentAt":"2010-05-17T09:48:38Z","receivedAt":"2010-05-17T09:48:38Z","isPatch":true,"sender":{"key":"gscrivano@gnu.org","avatar":"https://avatars.githubusercontent.com/u/67430?v=4"},"body":"Hello,\n\nI have noticed that the -h flag uses stderr to print the usage string,\nis there any reason for it?\n\nThe small patch I have attached changes -h to print on stdout.\n\nThanks,\nGiuseppe\n\n\n\n>From 4a5c4e4470dae11e22ff233b34a10b6a912fcd3e Mon Sep 17 00:00:00 2001\nFrom: Giuseppe Scrivano <gscrivano@gnu.org>\nDate: Mon, 17 May 2010 11:31:09 +0200\nSubject: [PATCH] Print the usage string on stdout instead of stderr.\n\nSigned-off-by: Giuseppe Scrivano <gscrivano@gnu.org>\n---\n parse-options.c |   36 +++++++++++++++++-------------------\n 1 files changed, 17 insertions(+), 19 deletions(-)\n\ndiff --git a/parse-options.c b/parse-options.c\nindex 8546d85..9adaf44 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -479,7 +479,7 @@ static int usage_argh(const struct option *opts)\n \t\t\ts = literal ? \"[%s]\" : \"[<%s>]\";\n \telse\n \t\ts = literal ? \" %s\" : \" <%s>\";\n-\treturn fprintf(stderr, s, opts->argh ? opts->argh : \"...\");\n+\treturn printf(s, opts->argh ? opts->argh : \"...\");\n }\n \n #define USAGE_OPTS_WIDTH 24\n@@ -491,47 +491,45 @@ static int usage_with_options_internal(const char * const *usagestr,\n \tif (!usagestr)\n \t\treturn PARSE_OPT_HELP;\n \n-\tfprintf(stderr, \"usage: %s\\n\", *usagestr++);\n+\tprintf(\"usage: %s\\n\", *usagestr++);\n \twhile (*usagestr && **usagestr)\n-\t\tfprintf(stderr, \"   or: %s\\n\", *usagestr++);\n+\t\tprintf(\"   or: %s\\n\", *usagestr++);\n \twhile (*usagestr) {\n-\t\tfprintf(stderr, \"%s%s\\n\",\n-\t\t\t\t**usagestr ? \"    \" : \"\",\n-\t\t\t\t*usagestr);\n+\t\tprintf(\"%s%s\\n\",**usagestr ? \"    \" : \"\", *usagestr);\n \t\tusagestr++;\n \t}\n \n \tif (opts->type != OPTION_GROUP)\n-\t\tfputc('\\n', stderr);\n+\t\tfputc('\\n', stdout);\n \n \tfor (; opts->type != OPTION_END; opts++) {\n \t\tsize_t pos;\n \t\tint pad;\n \n \t\tif (opts->type == OPTION_GROUP) {\n-\t\t\tfputc('\\n', stderr);\n+\t\t\tfputc('\\n', stdout);\n \t\t\tif (*opts->help)\n-\t\t\t\tfprintf(stderr, \"%s\\n\", opts->help);\n+\t\t\t\tprintf(\"%s\\n\", opts->help);\n \t\t\tcontinue;\n \t\t}\n \t\tif (!full && (opts->flags & PARSE_OPT_HIDDEN))\n \t\t\tcontinue;\n \n-\t\tpos = fprintf(stderr, \"    \");\n+\t\tpos = printf(\"    \");\n \t\tif (opts->short_name && !(opts->flags & PARSE_OPT_NEGHELP)) {\n \t\t\tif (opts->flags & PARSE_OPT_NODASH)\n-\t\t\t\tpos += fprintf(stderr, \"%c\", opts->short_name);\n+\t\t\t\tpos += printf(\"%c\", opts->short_name);\n \t\t\telse\n-\t\t\t\tpos += fprintf(stderr, \"-%c\", opts->short_name);\n+\t\t\t\tpos += printf(\"-%c\", opts->short_name);\n \t\t}\n \t\tif (opts->long_name && opts->short_name)\n-\t\t\tpos += fprintf(stderr, \", \");\n+\t\t\tpos += printf(\", \");\n \t\tif (opts->long_name)\n-\t\t\tpos += fprintf(stderr, \"--%s%s\",\n+\t\t\tpos += printf(\"--%s%s\",\n \t\t\t\t(opts->flags & PARSE_OPT_NEGHELP) ?  \"no-\" : \"\",\n \t\t\t\topts->long_name);\n \t\tif (opts->type == OPTION_NUMBER)\n-\t\t\tpos += fprintf(stderr, \"-NUM\");\n+\t\t\tpos += printf(\"-NUM\");\n \n \t\tif (!(opts->flags & PARSE_OPT_NOARG))\n \t\t\tpos += usage_argh(opts);\n@@ -539,12 +537,12 @@ static int usage_with_options_internal(const char * const *usagestr,\n \t\tif (pos <= USAGE_OPTS_WIDTH)\n \t\t\tpad = USAGE_OPTS_WIDTH - pos;\n \t\telse {\n-\t\t\tfputc('\\n', stderr);\n+\t\t\tfputc('\\n', stdout);\n \t\t\tpad = USAGE_OPTS_WIDTH;\n \t\t}\n-\t\tfprintf(stderr, \"%*s%s\\n\", pad + USAGE_GAP, \"\", opts->help);\n+\t\tprintf(\"%*s%s\\n\", pad + USAGE_GAP, \"\", opts->help);\n \t}\n-\tfputc('\\n', stderr);\n+\tfputc('\\n', stdout);\n \n \treturn PARSE_OPT_HELP;\n }\n@@ -560,7 +558,7 @@ void usage_msg_opt(const char *msg,\n \t\t   const char * const *usagestr,\n \t\t   const struct option *options)\n {\n-\tfprintf(stderr, \"%s\\n\\n\", msg);\n+\tprintf(\"%s\\n\\n\", msg);\n \tusage_with_options(usagestr, options);\n }\n \n-- \n1.7.1\n\n"},{"id":"141807","messageId":"4BF12C96.9030802@drmicha.warpmail.net","threadId":"23825","inReplyTo":"878w7ieu4p.fsf@thor.thematica.it","subject":"Re: [RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2010-05-17T11:46:30Z","receivedAt":"2010-05-17T11:46:30Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Giuseppe Scrivano venit, vidit, dixit 17.05.2010 11:48:\n> Hello,\n> \n> I have noticed that the -h flag uses stderr to print the usage string,\n> is there any reason for it?\n\nAs a general rule, regular output goes to stdout and error reports to\nstderr.\n\nNow, usage messages are displayed on specific request (-h) as well as\nwhen a command is used with wrong arguments. So the classification\ndepends on the use case! But I reckon that even with '-h', usage strings\nare not exactly \"regular output\", so stderr looks more natural to me.\n\nMore importantly, callers expect error messages on stderr, such as usage\nwith wrong arguments. I don't think scripts would call commands with\n'-h', and if they do they do so on purpose and can parse stderr, knowing\nthere is no stdout in this case.\n\nMichael\n\nP.S.: I guess this means NACK from me FWIIW.\n\n> \n> The small patch I have attached changes -h to print on stdout.\n> \n> Thanks,\n> Giuseppe\n> \n"},{"id":"141809","messageId":"buofx1qhgum.fsf@dhlpc061.dev.necel.com","threadId":"23825","inReplyTo":"4BF12C96.9030802@drmicha.warpmail.net","subject":"Re: [RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Miles Bader","fromEmail":"miles@gnu.org","sentAt":"2010-05-17T12:07:13Z","receivedAt":"2010-05-17T12:07:13Z","isPatch":true,"sender":{"key":"miles@gnu.org","avatar":"https://gravatar.com/avatar/01069b69593af7bff28e2f97afeb3644ae6fe2f5f56cb3a8cf34c5fb8c36efe5?d=mp&s=160"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n> Now, usage messages are displayed on specific request (-h) as well as\n> when a command is used with wrong arguments. So the classification\n> depends on the use case! But I reckon that even with '-h', usage strings\n> are not exactly \"regular output\", so stderr looks more natural to me.\n\nUsage info specifically requested by the user is not error output, it is\nthe output of the command.  It should be output to stdout, not stderr.\n\n[Note that for GNU progs, this behavior is explicitly required by the\nGNU coding standards, and I think it's a pretty reasonable rule.]\n\n-miles\n\n-- \no The existentialist, not having a pillow, goes everywhere with the book by\n  Sullivan, _I am going to spit on your graves_.\n"},{"id":"141812","messageId":"87vdamu2es.fsf@thor.thematica.it","threadId":"23825","inReplyTo":"4BF12C96.9030802@drmicha.warpmail.net","subject":"Re: [RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Giuseppe Scrivano","fromEmail":"gscrivano@gnu.org","sentAt":"2010-05-17T12:40:43Z","receivedAt":"2010-05-17T12:40:43Z","isPatch":true,"sender":{"key":"gscrivano@gnu.org","avatar":"https://avatars.githubusercontent.com/u/67430?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n> More importantly, callers expect error messages on stderr, such as usage\n> with wrong arguments. I don't think scripts would call commands with\n> '-h', and if they do they do so on purpose and can parse stderr, knowing\n> there is no stdout in this case.\n\nIt looks like a workaround to me.  Anyway, if -h is left unchanged then,\nI think, --help should be adjusted as well when it doesn't use an\nexternal pager.\n\nThese two commands behave differently:\n\ngit status --help 2>/dev/null | cat -\ngit status -h 2>/dev/null | cat -\n\nIMO, what should be changed is -h to be uniform with --help, as the it\nis the expected output, not an error.\n\nCheers,\nGiuseppe\n"},{"id":"141815","messageId":"4BF14500.30806@drmicha.warpmail.net","threadId":"23825","inReplyTo":"buofx1qhgum.fsf@dhlpc061.dev.necel.com","subject":"Re: [RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2010-05-17T13:30:40Z","receivedAt":"2010-05-17T13:30:40Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Miles Bader venit, vidit, dixit 17.05.2010 14:07:\n> Michael J Gruber <git@drmicha.warpmail.net> writes:\n>> Now, usage messages are displayed on specific request (-h) as well as\n>> when a command is used with wrong arguments. So the classification\n>> depends on the use case! But I reckon that even with '-h', usage strings\n>> are not exactly \"regular output\", so stderr looks more natural to me.\n> \n> Usage info specifically requested by the user is not error output, it is\n> the output of the command.  It should be output to stdout, not stderr.\n\nWell sure it is, just as I wrote. So do you suggest that the file handle\nshould depend on the use case? Care to implement?\n\n> [Note that for GNU progs, this behavior is explicitly required by the\n> GNU coding standards, and I think it's a pretty reasonable rule.]\n\nFortunately, Git is not GNU software.\n\nMichael\n"},{"id":"141816","messageId":"4BF14508.8040307@drmicha.warpmail.net","threadId":"23825","inReplyTo":"87vdamu2es.fsf@thor.thematica.it","subject":"Re: [RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2010-05-17T13:30:48Z","receivedAt":"2010-05-17T13:30:48Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Giuseppe Scrivano venit, vidit, dixit 17.05.2010 14:40:\n> Michael J Gruber <git@drmicha.warpmail.net> writes:\n> \n>> More importantly, callers expect error messages on stderr, such as usage\n>> with wrong arguments. I don't think scripts would call commands with\n>> '-h', and if they do they do so on purpose and can parse stderr, knowing\n>> there is no stdout in this case.\n> \n> It looks like a workaround to me.  Anyway, if -h is left unchanged then,\n> I think, --help should be adjusted as well when it doesn't use an\n> external pager.\n> \n> These two commands behave differently:\n> \n> git status --help 2>/dev/null | cat -\n> git status -h 2>/dev/null | cat -\n\nThey also do two very different things. The first one displays the man\npage, the second the usage string.\n\n> IMO, what should be changed is -h to be uniform with --help, as the it\n> is the expected output, not an error.\n\nThat is not what your patch does.\n\nI'm not opposed to having -h output on stdout. I'm opposed to having\nusage error messages on stdout. Currently, both are on stderr, which is\nno problem (we're not bound by GNU rules here).\n\nYour patch puts both on stdout, and that is a problem, not only for\nseveral test which could be adjusted, but also for scripters.\n\nA patch which *really* only changes '-h' to use stdout would certainly\nnot be objected. Actually, most calling sites are probably the \"error\ncase\" so that you only need to make sure that the \"-h\" path get's to use\na different output file descriptor.\n\nCheers,\nMichael\n"},{"id":"141818","messageId":"AANLkTikEOxUZz4aP8dw7sqLdDDp-Z5iDPMP2rsmZkPPy@mail.gmail.com","threadId":"23825","inReplyTo":"4BF14500.30806@drmicha.warpmail.net","subject":"Re: [RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Miles Bader","fromEmail":"miles@gnu.org","sentAt":"2010-05-17T13:54:38Z","receivedAt":"2010-05-17T13:54:38Z","isPatch":true,"sender":{"key":"miles@gnu.org","avatar":"https://gravatar.com/avatar/01069b69593af7bff28e2f97afeb3644ae6fe2f5f56cb3a8cf34c5fb8c36efe5?d=mp&s=160"},"body":"On Mon, May 17, 2010 at 10:30 PM, Michael J Gruber\n<git@drmicha.warpmail.net> wrote:\n>> [Note that for GNU progs, this behavior is explicitly required by the\n>> GNU coding standards, and I think it's a pretty reasonable rule.]\n>\n> Fortunately, Git is not GNU software.\n\nThe point is not that git must follow these standards, but that it''s\na reasonable guideline (as are many of the GNU standards), and it's\ngenerally useful if free software such as git is broadly consistent\nwith other free software.  For instance, git uses GNU-style long\ncommand-line option syntax, and this is a good thing.\n\n-Miles\n\n-- \nDo not taunt Happy Fun Ball.\n"},{"id":"141819","messageId":"87hbm6tydr.fsf@thor.thematica.it","threadId":"23825","inReplyTo":"4BF14500.30806@drmicha.warpmail.net","subject":"Re: [RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Giuseppe Scrivano","fromEmail":"gscrivano@gnu.org","sentAt":"2010-05-17T14:07:44Z","receivedAt":"2010-05-17T14:07:44Z","isPatch":true,"sender":{"key":"gscrivano@gnu.org","avatar":"https://avatars.githubusercontent.com/u/67430?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n> Well sure it is, just as I wrote. So do you suggest that the file handle\n> should depend on the use case? Care to implement?\n\nThanks for your comments.  I will fix my patch accordingly and resend it.\n\nCheers,\nGiuseppe\n"},{"id":"141820","messageId":"AANLkTinoTsoX-BzWj1pBFg8k6seDBMmwqC9Gm3sg1hz3@mail.gmail.com","threadId":"23825","inReplyTo":"87hbm6tydr.fsf@thor.thematica.it","subject":"Re: [RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Tay Ray Chuan","fromEmail":"rctay89@gmail.com","sentAt":"2010-05-17T14:11:22Z","receivedAt":"2010-05-17T14:11:22Z","isPatch":true,"sender":{"key":"rctay89@gmail.com","avatar":"https://avatars.githubusercontent.com/u/61553?v=4"},"body":"On Mon, May 17, 2010 at 10:07 PM, Giuseppe Scrivano <gscrivano@gnu.org> wrote:\n> Michael J Gruber <git@drmicha.warpmail.net> writes:\n>\n>> Well sure it is, just as I wrote. So do you suggest that the file handle\n>> should depend on the use case? Care to implement?\n>\n> Thanks for your comments.  I will fix my patch accordingly and resend it.\n\nWhile you're at it, please take a look at\n\n  http://github.com/git/git/blob/master/Documentation/SubmittingPatches\n\nfor your next re-send.\n\n-- \nCheers,\nRay Chuan\n"},{"id":"141826","messageId":"87d3wutt34.fsf@thor.thematica.it","threadId":"23825","inReplyTo":"4BF14508.8040307@drmicha.warpmail.net","subject":"Re: [RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Giuseppe Scrivano","fromEmail":"gscrivano@gnu.org","sentAt":"2010-05-17T16:02:07Z","receivedAt":"2010-05-17T16:02:07Z","isPatch":true,"sender":{"key":"gscrivano@gnu.org","avatar":"https://avatars.githubusercontent.com/u/67430?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n> Your patch puts both on stdout, and that is a problem, not only for\n> several test which could be adjusted, but also for scripters.\n>\n> A patch which *really* only changes '-h' to use stdout would certainly\n> not be objected. Actually, most calling sites are probably the \"error\n> case\" so that you only need to make sure that the \"-h\" path get's to use\n> a different output file descriptor.\n\nI have changed my patches following your suggestions.\n\nI have also fixed two tests.\n\nCheers,\nGiuseppe\n\n\n\n>From 00100c61db30725011edf62e7e0e7bc6ac685cb0 Mon Sep 17 00:00:00 2001\nFrom: Giuseppe Scrivano <gscrivano@gnu.org>\nDate: Mon, 17 May 2010 17:34:41 +0200\nSubject: [PATCH] print the usage string on stdout instead of stderr\n\nWhen -h is used, print usage messages on stdout.  If a command is invoked with\nwrong arguments then print the usage messages on stderr.\n\nSigned-off-by: Giuseppe Scrivano <gscrivano@gnu.org>\n---\n parse-options.c               |   64 +++++++++++++++++++++--------------------\n t/t0040-parse-options.sh      |    8 +++--\n t/t1502-rev-parse-parseopt.sh |    6 ++--\n 3 files changed, 41 insertions(+), 37 deletions(-)\n\ndiff --git a/parse-options.c b/parse-options.c\nindex 8546d85..c8aaf95 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -5,7 +5,7 @@\n #include \"color.h\"\n \n static int parse_options_usage(const char * const *usagestr,\n-\t\t\t       const struct option *opts);\n+\t\t\t       const struct option *opts, int err);\n \n #define OPT_SHORT 1\n #define OPT_UNSET 2\n@@ -352,7 +352,7 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,\n }\n \n static int usage_with_options_internal(const char * const *,\n-\t\t\t\t       const struct option *, int);\n+\t\t\t\t       const struct option *, int, int);\n \n int parse_options_step(struct parse_opt_ctx_t *ctx,\n \t\t       const struct option *options,\n@@ -380,10 +380,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);\n+\t\t\t\treturn parse_options_usage(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);\n+\t\t\t\treturn parse_options_usage(usagestr, options, 1);\n \t\t\tcase -2:\n \t\t\t\tgoto unknown;\n \t\t\t}\n@@ -391,10 +391,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);\n+\t\t\t\t\treturn parse_options_usage(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);\n+\t\t\t\t\treturn parse_options_usage(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 +418,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);\n+\t\t\treturn usage_with_options_internal(usagestr, options, 1, 0);\n \t\tif (internal_help && !strcmp(arg + 2, \"help\"))\n-\t\t\treturn parse_options_usage(usagestr, options);\n+\t\t\treturn parse_options_usage(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);\n+\t\t\treturn parse_options_usage(usagestr, options, 1);\n \t\tcase -2:\n \t\t\tgoto unknown;\n \t\t}\n@@ -468,7 +468,7 @@ int parse_options(int argc, const char **argv, const char *prefix,\n \treturn parse_options_end(&ctx);\n }\n \n-static int usage_argh(const struct option *opts)\n+static int usage_argh(const struct option *opts, FILE *outfile)\n {\n \tconst char *s;\n \tint literal = (opts->flags & PARSE_OPT_LITERAL_ARGHELP) || !opts->argh;\n@@ -479,72 +479,74 @@ static int usage_argh(const struct option *opts)\n \t\t\ts = literal ? \"[%s]\" : \"[<%s>]\";\n \telse\n \t\ts = literal ? \" %s\" : \" <%s>\";\n-\treturn fprintf(stderr, s, opts->argh ? opts->argh : \"...\");\n+\treturn fprintf(outfile, s, opts->argh ? opts->argh : \"...\");\n }\n \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)\n+\t\t\t\tconst 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-\tfprintf(stderr, \"usage: %s\\n\", *usagestr++);\n+\tfprintf(outfile, \"usage: %s\\n\", *usagestr++);\n \twhile (*usagestr && **usagestr)\n-\t\tfprintf(stderr, \"   or: %s\\n\", *usagestr++);\n+\t\tfprintf(outfile, \"   or: %s\\n\", *usagestr++);\n \twhile (*usagestr) {\n-\t\tfprintf(stderr, \"%s%s\\n\",\n+\t\tfprintf(outfile, \"%s%s\\n\",\n \t\t\t\t**usagestr ? \"    \" : \"\",\n \t\t\t\t*usagestr);\n \t\tusagestr++;\n \t}\n \n \tif (opts->type != OPTION_GROUP)\n-\t\tfputc('\\n', stderr);\n+\t\tfputc('\\n', outfile);\n \n \tfor (; opts->type != OPTION_END; opts++) {\n \t\tsize_t pos;\n \t\tint pad;\n \n \t\tif (opts->type == OPTION_GROUP) {\n-\t\t\tfputc('\\n', stderr);\n+\t\t\tfputc('\\n', outfile);\n \t\t\tif (*opts->help)\n-\t\t\t\tfprintf(stderr, \"%s\\n\", opts->help);\n+\t\t\t\tfprintf(outfile, \"%s\\n\", opts->help);\n \t\t\tcontinue;\n \t\t}\n \t\tif (!full && (opts->flags & PARSE_OPT_HIDDEN))\n \t\t\tcontinue;\n \n-\t\tpos = fprintf(stderr, \"    \");\n+\t\tpos = fprintf(outfile, \"    \");\n \t\tif (opts->short_name && !(opts->flags & PARSE_OPT_NEGHELP)) {\n \t\t\tif (opts->flags & PARSE_OPT_NODASH)\n-\t\t\t\tpos += fprintf(stderr, \"%c\", opts->short_name);\n+\t\t\t\tpos += fprintf(outfile, \"%c\", opts->short_name);\n \t\t\telse\n-\t\t\t\tpos += fprintf(stderr, \"-%c\", opts->short_name);\n+\t\t\t\tpos += fprintf(outfile, \"-%c\", opts->short_name);\n \t\t}\n \t\tif (opts->long_name && opts->short_name)\n-\t\t\tpos += fprintf(stderr, \", \");\n+\t\t\tpos += fprintf(outfile, \", \");\n \t\tif (opts->long_name)\n-\t\t\tpos += fprintf(stderr, \"--%s%s\",\n+\t\t\tpos += fprintf(outfile, \"--%s%s\",\n \t\t\t\t(opts->flags & PARSE_OPT_NEGHELP) ?  \"no-\" : \"\",\n \t\t\t\topts->long_name);\n \t\tif (opts->type == OPTION_NUMBER)\n-\t\t\tpos += fprintf(stderr, \"-NUM\");\n+\t\t\tpos += fprintf(outfile, \"-NUM\");\n \n \t\tif (!(opts->flags & PARSE_OPT_NOARG))\n-\t\t\tpos += usage_argh(opts);\n+\t\t\tpos += usage_argh(opts, outfile);\n \n \t\tif (pos <= USAGE_OPTS_WIDTH)\n \t\t\tpad = USAGE_OPTS_WIDTH - pos;\n \t\telse {\n-\t\t\tfputc('\\n', stderr);\n+\t\t\tfputc('\\n', outfile);\n \t\t\tpad = USAGE_OPTS_WIDTH;\n \t\t}\n-\t\tfprintf(stderr, \"%*s%s\\n\", pad + USAGE_GAP, \"\", opts->help);\n+\t\tfprintf(outfile, \"%*s%s\\n\", pad + USAGE_GAP, \"\", opts->help);\n \t}\n-\tfputc('\\n', stderr);\n+\tfputc('\\n', outfile);\n \n \treturn PARSE_OPT_HELP;\n }\n@@ -552,7 +554,7 @@ static int usage_with_options_internal(const char * const *usagestr,\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);\n+\tusage_with_options_internal(usagestr, opts, 0, 1);\n \texit(129);\n }\n \n@@ -565,9 +567,9 @@ void usage_msg_opt(const char *msg,\n }\n \n static int parse_options_usage(const char * const *usagestr,\n-\t\t\t       const struct option *opts)\n+\t\t\t       const struct option *opts, int err)\n {\n-\treturn usage_with_options_internal(usagestr, opts, 0);\n+\treturn usage_with_options_internal(usagestr, opts, 0, err);\n }\n \n \ndiff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh\nindex 3d450ed..2092450 100755\n--- a/t/t0040-parse-options.sh\n+++ b/t/t0040-parse-options.sh\n@@ -7,7 +7,7 @@ test_description='our own option parser'\n \n . ./test-lib.sh\n \n-cat > expect.err << EOF\n+cat > expect << EOF\n usage: test-parse-options <options>\n \n     -b, --boolean         get a boolean\n@@ -46,10 +46,12 @@ EOF\n \n test_expect_success 'test help' '\n \ttest_must_fail test-parse-options -h > output 2> output.err &&\n-\ttest ! -s output &&\n-\ttest_cmp expect.err output.err\n+\ttest ! -s output.err &&\n+\ttest_cmp expect output\n '\n \n+mv expect expect.err\n+\n cat > expect << EOF\n boolean: 2\n integer: 1729\ndiff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh\nindex e504058..660487d 100755\n--- a/t/t1502-rev-parse-parseopt.sh\n+++ b/t/t1502-rev-parse-parseopt.sh\n@@ -3,7 +3,7 @@\n test_description='test git rev-parse --parseopt'\n . ./test-lib.sh\n \n-cat > expect.err <<EOF\n+cat > expect <<EOF\n usage: some-command [options] <args>...\n \n     some-command does foo and bar!\n@@ -38,8 +38,8 @@ extra1    line above used to cause a segfault but no longer does\n EOF\n \n test_expect_success 'test --parseopt help output' '\n-\tgit rev-parse --parseopt -- -h 2> output.err < optionspec\n-\ttest_cmp expect.err output.err\n+\tgit rev-parse --parseopt -- -h > output < optionspec\n+\ttest_cmp expect output\n '\n \n cat > expect <<EOF\n-- \n1.7.1\n"},{"id":"141858","messageId":"4BF2614E.50003@drmicha.warpmail.net","threadId":"23825","inReplyTo":"87d3wutt34.fsf@thor.thematica.it","subject":"Re: [RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2010-05-18T09:43:42Z","receivedAt":"2010-05-18T09:43:42Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Giuseppe Scrivano venit, vidit, dixit 17.05.2010 18:02:\n> Michael J Gruber <git@drmicha.warpmail.net> writes:\n> \n>> Your patch puts both on stdout, and that is a problem, not only for\n>> several test which could be adjusted, but also for scripters.\n>>\n>> A patch which *really* only changes '-h' to use stdout would certainly\n>> not be objected. Actually, most calling sites are probably the \"error\n>> case\" so that you only need to make sure that the \"-h\" path get's to use\n>> a different output file descriptor.\n> \n> I have changed my patches following your suggestions.\n\nThanks!\n\n> I have also fixed two tests.\n> \n> Cheers,\n> Giuseppe\n> \n> \n> \n> From 00100c61db30725011edf62e7e0e7bc6ac685cb0 Mon Sep 17 00:00:00 2001\n> From: Giuseppe Scrivano <gscrivano@gnu.org>\n> Date: Mon, 17 May 2010 17:34:41 +0200\n> Subject: [PATCH] print the usage string on stdout instead of stderr\n> \n> When -h is used, print usage messages on stdout.  If a command is invoked with\n> wrong arguments then print the usage messages on stderr.\n> \n> Signed-off-by: Giuseppe Scrivano <gscrivano@gnu.org>\n> ---\n>  parse-options.c               |   64 +++++++++++++++++++++--------------------\n>  t/t0040-parse-options.sh      |    8 +++--\n>  t/t1502-rev-parse-parseopt.sh |    6 ++--\n>  3 files changed, 41 insertions(+), 37 deletions(-)\n> \n> diff --git a/parse-options.c b/parse-options.c\n> index 8546d85..c8aaf95 100644\n> --- a/parse-options.c\n> +++ b/parse-options.c\n> @@ -5,7 +5,7 @@\n>  #include \"color.h\"\n>  \n>  static int parse_options_usage(const char * const *usagestr,\n> -\t\t\t       const struct option *opts);\n> +\t\t\t       const struct option *opts, int err);\n>  \n>  #define OPT_SHORT 1\n>  #define OPT_UNSET 2\n> @@ -352,7 +352,7 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,\n>  }\n>  \n>  static int usage_with_options_internal(const char * const *,\n> -\t\t\t\t       const struct option *, int);\n> +\t\t\t\t       const struct option *, int, int);\n>  \n>  int parse_options_step(struct parse_opt_ctx_t *ctx,\n>  \t\t       const struct option *options,\n> @@ -380,10 +380,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);\n> +\t\t\t\treturn parse_options_usage(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);\n> +\t\t\t\treturn parse_options_usage(usagestr, options, 1);\n>  \t\t\tcase -2:\n>  \t\t\t\tgoto unknown;\n>  \t\t\t}\n> @@ -391,10 +391,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);\n> +\t\t\t\t\treturn parse_options_usage(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);\n> +\t\t\t\t\treturn parse_options_usage(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 +418,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);\n> +\t\t\treturn usage_with_options_internal(usagestr, options, 1, 0);\n>  \t\tif (internal_help && !strcmp(arg + 2, \"help\"))\n> -\t\t\treturn parse_options_usage(usagestr, options);\n> +\t\t\treturn parse_options_usage(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);\n> +\t\t\treturn parse_options_usage(usagestr, options, 1);\n>  \t\tcase -2:\n>  \t\t\tgoto unknown;\n>  \t\t}\n> @@ -468,7 +468,7 @@ int parse_options(int argc, const char **argv, const char *prefix,\n>  \treturn parse_options_end(&ctx);\n>  }\n>  \n> -static int usage_argh(const struct option *opts)\n> +static int usage_argh(const struct option *opts, FILE *outfile)\n>  {\n>  \tconst char *s;\n>  \tint literal = (opts->flags & PARSE_OPT_LITERAL_ARGHELP) || !opts->argh;\n> @@ -479,72 +479,74 @@ static int usage_argh(const struct option *opts)\n>  \t\t\ts = literal ? \"[%s]\" : \"[<%s>]\";\n>  \telse\n>  \t\ts = literal ? \" %s\" : \" <%s>\";\n> -\treturn fprintf(stderr, s, opts->argh ? opts->argh : \"...\");\n> +\treturn fprintf(outfile, s, opts->argh ? opts->argh : \"...\");\n>  }\n>  \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)\n> +\t\t\t\tconst 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> -\tfprintf(stderr, \"usage: %s\\n\", *usagestr++);\n> +\tfprintf(outfile, \"usage: %s\\n\", *usagestr++);\n>  \twhile (*usagestr && **usagestr)\n> -\t\tfprintf(stderr, \"   or: %s\\n\", *usagestr++);\n> +\t\tfprintf(outfile, \"   or: %s\\n\", *usagestr++);\n>  \twhile (*usagestr) {\n> -\t\tfprintf(stderr, \"%s%s\\n\",\n> +\t\tfprintf(outfile, \"%s%s\\n\",\n>  \t\t\t\t**usagestr ? \"    \" : \"\",\n>  \t\t\t\t*usagestr);\n>  \t\tusagestr++;\n>  \t}\n>  \n>  \tif (opts->type != OPTION_GROUP)\n> -\t\tfputc('\\n', stderr);\n> +\t\tfputc('\\n', outfile);\n>  \n>  \tfor (; opts->type != OPTION_END; opts++) {\n>  \t\tsize_t pos;\n>  \t\tint pad;\n>  \n>  \t\tif (opts->type == OPTION_GROUP) {\n> -\t\t\tfputc('\\n', stderr);\n> +\t\t\tfputc('\\n', outfile);\n>  \t\t\tif (*opts->help)\n> -\t\t\t\tfprintf(stderr, \"%s\\n\", opts->help);\n> +\t\t\t\tfprintf(outfile, \"%s\\n\", opts->help);\n>  \t\t\tcontinue;\n>  \t\t}\n>  \t\tif (!full && (opts->flags & PARSE_OPT_HIDDEN))\n>  \t\t\tcontinue;\n>  \n> -\t\tpos = fprintf(stderr, \"    \");\n> +\t\tpos = fprintf(outfile, \"    \");\n>  \t\tif (opts->short_name && !(opts->flags & PARSE_OPT_NEGHELP)) {\n>  \t\t\tif (opts->flags & PARSE_OPT_NODASH)\n> -\t\t\t\tpos += fprintf(stderr, \"%c\", opts->short_name);\n> +\t\t\t\tpos += fprintf(outfile, \"%c\", opts->short_name);\n>  \t\t\telse\n> -\t\t\t\tpos += fprintf(stderr, \"-%c\", opts->short_name);\n> +\t\t\t\tpos += fprintf(outfile, \"-%c\", opts->short_name);\n>  \t\t}\n>  \t\tif (opts->long_name && opts->short_name)\n> -\t\t\tpos += fprintf(stderr, \", \");\n> +\t\t\tpos += fprintf(outfile, \", \");\n>  \t\tif (opts->long_name)\n> -\t\t\tpos += fprintf(stderr, \"--%s%s\",\n> +\t\t\tpos += fprintf(outfile, \"--%s%s\",\n>  \t\t\t\t(opts->flags & PARSE_OPT_NEGHELP) ?  \"no-\" : \"\",\n>  \t\t\t\topts->long_name);\n>  \t\tif (opts->type == OPTION_NUMBER)\n> -\t\t\tpos += fprintf(stderr, \"-NUM\");\n> +\t\t\tpos += fprintf(outfile, \"-NUM\");\n>  \n>  \t\tif (!(opts->flags & PARSE_OPT_NOARG))\n> -\t\t\tpos += usage_argh(opts);\n> +\t\t\tpos += usage_argh(opts, outfile);\n>  \n>  \t\tif (pos <= USAGE_OPTS_WIDTH)\n>  \t\t\tpad = USAGE_OPTS_WIDTH - pos;\n>  \t\telse {\n> -\t\t\tfputc('\\n', stderr);\n> +\t\t\tfputc('\\n', outfile);\n>  \t\t\tpad = USAGE_OPTS_WIDTH;\n>  \t\t}\n> -\t\tfprintf(stderr, \"%*s%s\\n\", pad + USAGE_GAP, \"\", opts->help);\n> +\t\tfprintf(outfile, \"%*s%s\\n\", pad + USAGE_GAP, \"\", opts->help);\n>  \t}\n> -\tfputc('\\n', stderr);\n> +\tfputc('\\n', outfile);\n>  \n>  \treturn PARSE_OPT_HELP;\n>  }\n> @@ -552,7 +554,7 @@ static int usage_with_options_internal(const char * const *usagestr,\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);\n> +\tusage_with_options_internal(usagestr, opts, 0, 1);\n>  \texit(129);\n>  }\n>  \n> @@ -565,9 +567,9 @@ void usage_msg_opt(const char *msg,\n>  }\n>  \n>  static int parse_options_usage(const char * const *usagestr,\n> -\t\t\t       const struct option *opts)\n> +\t\t\t       const struct option *opts, int err)\n>  {\n> -\treturn usage_with_options_internal(usagestr, opts, 0);\n> +\treturn usage_with_options_internal(usagestr, opts, 0, err);\n>  }\n>  \n>  \n> diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh\n> index 3d450ed..2092450 100755\n> --- a/t/t0040-parse-options.sh\n> +++ b/t/t0040-parse-options.sh\n> @@ -7,7 +7,7 @@ test_description='our own option parser'\n>  \n>  . ./test-lib.sh\n>  \n> -cat > expect.err << EOF\n> +cat > expect << EOF\n>  usage: test-parse-options <options>\n>  \n>      -b, --boolean         get a boolean\n> @@ -46,10 +46,12 @@ EOF\n>  \n>  test_expect_success 'test help' '\n>  \ttest_must_fail test-parse-options -h > output 2> output.err &&\n> -\ttest ! -s output &&\n> -\ttest_cmp expect.err output.err\n> +\ttest ! -s output.err &&\n> +\ttest_cmp expect output\n>  '\n>  \n> +mv expect expect.err\n> +\n>  cat > expect << EOF\n>  boolean: 2\n>  integer: 1729\n> diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh\n> index e504058..660487d 100755\n> --- a/t/t1502-rev-parse-parseopt.sh\n> +++ b/t/t1502-rev-parse-parseopt.sh\n> @@ -3,7 +3,7 @@\n>  test_description='test git rev-parse --parseopt'\n>  . ./test-lib.sh\n>  \n> -cat > expect.err <<EOF\n> +cat > expect <<EOF\n>  usage: some-command [options] <args>...\n>  \n>      some-command does foo and bar!\n> @@ -38,8 +38,8 @@ extra1    line above used to cause a segfault but no longer does\n>  EOF\n>  \n>  test_expect_success 'test --parseopt help output' '\n> -\tgit rev-parse --parseopt -- -h 2> output.err < optionspec\n> -\ttest_cmp expect.err output.err\n> +\tgit rev-parse --parseopt -- -h > output < optionspec\n> +\ttest_cmp expect output\n>  '\n>  \n>  cat > expect <<EOF\n\nI haven't checked whether this covers all code paths but other than that\nit looks OK to me, and the tests pass.\n\nCheers,\nMichael\n"},{"id":"142219","messageId":"87pr0lja5n.fsf@gnu.org","threadId":"23825","inReplyTo":"4BF2614E.50003@drmicha.warpmail.net","subject":"Re: [RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Giuseppe Scrivano","fromEmail":"gscrivano@gnu.org","sentAt":"2010-05-24T20:51:32Z","receivedAt":"2010-05-24T20:51:32Z","isPatch":true,"sender":{"key":"gscrivano@gnu.org","avatar":"https://avatars.githubusercontent.com/u/67430?v=4"},"body":"Hello Michael,\n\n\nMichael J Gruber <git@drmicha.warpmail.net> writes:\n\n> I haven't checked whether this covers all code paths but other than that\n> it looks OK to me, and the tests pass.\n\nis the patch ready for inclusion?\n\n\nThanks,\nGiuseppe\n"},{"id":"142239","messageId":"4BFB724A.3020800@drmicha.warpmail.net","threadId":"23825","inReplyTo":"87pr0lja5n.fsf@gnu.org","subject":"Re: [RFC][PATCH] Print the usage string on stdout instead of stderr.","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2010-05-25T06:46:34Z","receivedAt":"2010-05-25T06:46:34Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Giuseppe Scrivano venit, vidit, dixit 24.05.2010 22:51:\n> Hello Michael,\n> \n> \n> Michael J Gruber <git@drmicha.warpmail.net> writes:\n> \n>> I haven't checked whether this covers all code paths but other than that\n>> it looks OK to me, and the tests pass.\n> \n> is the patch ready for inclusion?\n\nYou're the author, you should know ;)\n\nNote that I can't include your patch. That's up to Junio, and he's been\nlagging back for good reasons (as you could read on the list) and is in\nthe process of keeping up.\n\nI gave you my partial ack'ed-by (see above) and a homework problem to\nanswer: Have you checked whether this covers all code paths (all\nhelp/usage callers)? If yes then it's a good idea to resend v2 of your\npatch as a reply to this thread but with subject \"[PATCH v2]...\" as it\nis hard to find otherwise, and cc to Junio.\n\nCheers,\nMichael\n"},{"id":"142255","messageId":"874ohwwf01.fsf_-_@thor.thematica.it","threadId":"23825","inReplyTo":"4BFB724A.3020800@drmicha.warpmail.net","subject":"[PATCH v2] Print the usage string on stdout instead of stderr.","fromName":"Giuseppe Scrivano","fromEmail":"gscrivano@gnu.org","sentAt":"2010-05-25T08:40:46Z","receivedAt":"2010-05-25T08:40:46Z","isPatch":true,"sender":{"key":"gscrivano@gnu.org","avatar":"https://avatars.githubusercontent.com/u/67430?v=4"},"body":"Hello,\n\nMichael J Gruber <git@drmicha.warpmail.net> writes:\n\n> I gave you my partial ack'ed-by (see above) and a homework problem to\n> answer: Have you checked whether this covers all code paths (all\n> help/usage callers)? If yes then it's a good idea to resend v2 of your\n> patch as a reply to this thread but with subject \"[PATCH v2]...\" as it\n> is hard to find otherwise, and cc to Junio.\n\nYes, I have just double-checked it; I hope I am not missing something.\n\nThanks,\nGiuseppe\n\n\n\n>From 00100c61db30725011edf62e7e0e7bc6ac685cb0 Mon Sep 17 00:00:00 2001\nFrom: Giuseppe Scrivano <gscrivano@gnu.org>\nDate: Mon, 17 May 2010 17:34:41 +0200\nSubject: [PATCH] print the usage string on stdout instead of stderr\n\nWhen -h is used, print usage messages on stdout.  If a command is invoked with\nwrong arguments then print the usage messages on stderr.\n\nSigned-off-by: Giuseppe Scrivano <gscrivano@gnu.org>\n---\n parse-options.c               |   64 +++++++++++++++++++++--------------------\n t/t0040-parse-options.sh      |    8 +++--\n t/t1502-rev-parse-parseopt.sh |    6 ++--\n 3 files changed, 41 insertions(+), 37 deletions(-)\n\ndiff --git a/parse-options.c b/parse-options.c\nindex 8546d85..c8aaf95 100644\n--- a/parse-options.c\n+++ b/parse-options.c\n@@ -5,7 +5,7 @@\n #include \"color.h\"\n \n static int parse_options_usage(const char * const *usagestr,\n-\t\t\t       const struct option *opts);\n+\t\t\t       const struct option *opts, int err);\n \n #define OPT_SHORT 1\n #define OPT_UNSET 2\n@@ -352,7 +352,7 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,\n }\n \n static int usage_with_options_internal(const char * const *,\n-\t\t\t\t       const struct option *, int);\n+\t\t\t\t       const struct option *, int, int);\n \n int parse_options_step(struct parse_opt_ctx_t *ctx,\n \t\t       const struct option *options,\n@@ -380,10 +380,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);\n+\t\t\t\treturn parse_options_usage(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);\n+\t\t\t\treturn parse_options_usage(usagestr, options, 1);\n \t\t\tcase -2:\n \t\t\t\tgoto unknown;\n \t\t\t}\n@@ -391,10 +391,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);\n+\t\t\t\t\treturn parse_options_usage(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);\n+\t\t\t\t\treturn parse_options_usage(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 +418,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);\n+\t\t\treturn usage_with_options_internal(usagestr, options, 1, 0);\n \t\tif (internal_help && !strcmp(arg + 2, \"help\"))\n-\t\t\treturn parse_options_usage(usagestr, options);\n+\t\t\treturn parse_options_usage(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);\n+\t\t\treturn parse_options_usage(usagestr, options, 1);\n \t\tcase -2:\n \t\t\tgoto unknown;\n \t\t}\n@@ -468,7 +468,7 @@ int parse_options(int argc, const char **argv, const char *prefix,\n \treturn parse_options_end(&ctx);\n }\n \n-static int usage_argh(const struct option *opts)\n+static int usage_argh(const struct option *opts, FILE *outfile)\n {\n \tconst char *s;\n \tint literal = (opts->flags & PARSE_OPT_LITERAL_ARGHELP) || !opts->argh;\n@@ -479,72 +479,74 @@ static int usage_argh(const struct option *opts)\n \t\t\ts = literal ? \"[%s]\" : \"[<%s>]\";\n \telse\n \t\ts = literal ? \" %s\" : \" <%s>\";\n-\treturn fprintf(stderr, s, opts->argh ? opts->argh : \"...\");\n+\treturn fprintf(outfile, s, opts->argh ? opts->argh : \"...\");\n }\n \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)\n+\t\t\t\tconst 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-\tfprintf(stderr, \"usage: %s\\n\", *usagestr++);\n+\tfprintf(outfile, \"usage: %s\\n\", *usagestr++);\n \twhile (*usagestr && **usagestr)\n-\t\tfprintf(stderr, \"   or: %s\\n\", *usagestr++);\n+\t\tfprintf(outfile, \"   or: %s\\n\", *usagestr++);\n \twhile (*usagestr) {\n-\t\tfprintf(stderr, \"%s%s\\n\",\n+\t\tfprintf(outfile, \"%s%s\\n\",\n \t\t\t\t**usagestr ? \"    \" : \"\",\n \t\t\t\t*usagestr);\n \t\tusagestr++;\n \t}\n \n \tif (opts->type != OPTION_GROUP)\n-\t\tfputc('\\n', stderr);\n+\t\tfputc('\\n', outfile);\n \n \tfor (; opts->type != OPTION_END; opts++) {\n \t\tsize_t pos;\n \t\tint pad;\n \n \t\tif (opts->type == OPTION_GROUP) {\n-\t\t\tfputc('\\n', stderr);\n+\t\t\tfputc('\\n', outfile);\n \t\t\tif (*opts->help)\n-\t\t\t\tfprintf(stderr, \"%s\\n\", opts->help);\n+\t\t\t\tfprintf(outfile, \"%s\\n\", opts->help);\n \t\t\tcontinue;\n \t\t}\n \t\tif (!full && (opts->flags & PARSE_OPT_HIDDEN))\n \t\t\tcontinue;\n \n-\t\tpos = fprintf(stderr, \"    \");\n+\t\tpos = fprintf(outfile, \"    \");\n \t\tif (opts->short_name && !(opts->flags & PARSE_OPT_NEGHELP)) {\n \t\t\tif (opts->flags & PARSE_OPT_NODASH)\n-\t\t\t\tpos += fprintf(stderr, \"%c\", opts->short_name);\n+\t\t\t\tpos += fprintf(outfile, \"%c\", opts->short_name);\n \t\t\telse\n-\t\t\t\tpos += fprintf(stderr, \"-%c\", opts->short_name);\n+\t\t\t\tpos += fprintf(outfile, \"-%c\", opts->short_name);\n \t\t}\n \t\tif (opts->long_name && opts->short_name)\n-\t\t\tpos += fprintf(stderr, \", \");\n+\t\t\tpos += fprintf(outfile, \", \");\n \t\tif (opts->long_name)\n-\t\t\tpos += fprintf(stderr, \"--%s%s\",\n+\t\t\tpos += fprintf(outfile, \"--%s%s\",\n \t\t\t\t(opts->flags & PARSE_OPT_NEGHELP) ?  \"no-\" : \"\",\n \t\t\t\topts->long_name);\n \t\tif (opts->type == OPTION_NUMBER)\n-\t\t\tpos += fprintf(stderr, \"-NUM\");\n+\t\t\tpos += fprintf(outfile, \"-NUM\");\n \n \t\tif (!(opts->flags & PARSE_OPT_NOARG))\n-\t\t\tpos += usage_argh(opts);\n+\t\t\tpos += usage_argh(opts, outfile);\n \n \t\tif (pos <= USAGE_OPTS_WIDTH)\n \t\t\tpad = USAGE_OPTS_WIDTH - pos;\n \t\telse {\n-\t\t\tfputc('\\n', stderr);\n+\t\t\tfputc('\\n', outfile);\n \t\t\tpad = USAGE_OPTS_WIDTH;\n \t\t}\n-\t\tfprintf(stderr, \"%*s%s\\n\", pad + USAGE_GAP, \"\", opts->help);\n+\t\tfprintf(outfile, \"%*s%s\\n\", pad + USAGE_GAP, \"\", opts->help);\n \t}\n-\tfputc('\\n', stderr);\n+\tfputc('\\n', outfile);\n \n \treturn PARSE_OPT_HELP;\n }\n@@ -552,7 +554,7 @@ static int usage_with_options_internal(const char * const *usagestr,\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);\n+\tusage_with_options_internal(usagestr, opts, 0, 1);\n \texit(129);\n }\n \n@@ -565,9 +567,9 @@ void usage_msg_opt(const char *msg,\n }\n \n static int parse_options_usage(const char * const *usagestr,\n-\t\t\t       const struct option *opts)\n+\t\t\t       const struct option *opts, int err)\n {\n-\treturn usage_with_options_internal(usagestr, opts, 0);\n+\treturn usage_with_options_internal(usagestr, opts, 0, err);\n }\n \n \ndiff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh\nindex 3d450ed..2092450 100755\n--- a/t/t0040-parse-options.sh\n+++ b/t/t0040-parse-options.sh\n@@ -7,7 +7,7 @@ test_description='our own option parser'\n \n . ./test-lib.sh\n \n-cat > expect.err << EOF\n+cat > expect << EOF\n usage: test-parse-options <options>\n \n     -b, --boolean         get a boolean\n@@ -46,10 +46,12 @@ EOF\n \n test_expect_success 'test help' '\n \ttest_must_fail test-parse-options -h > output 2> output.err &&\n-\ttest ! -s output &&\n-\ttest_cmp expect.err output.err\n+\ttest ! -s output.err &&\n+\ttest_cmp expect output\n '\n \n+mv expect expect.err\n+\n cat > expect << EOF\n boolean: 2\n integer: 1729\ndiff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh\nindex e504058..660487d 100755\n--- a/t/t1502-rev-parse-parseopt.sh\n+++ b/t/t1502-rev-parse-parseopt.sh\n@@ -3,7 +3,7 @@\n test_description='test git rev-parse --parseopt'\n . ./test-lib.sh\n \n-cat > expect.err <<EOF\n+cat > expect <<EOF\n usage: some-command [options] <args>...\n \n     some-command does foo and bar!\n@@ -38,8 +38,8 @@ extra1    line above used to cause a segfault but no longer does\n EOF\n \n test_expect_success 'test --parseopt help output' '\n-\tgit rev-parse --parseopt -- -h 2> output.err < optionspec\n-\ttest_cmp expect.err output.err\n+\tgit rev-parse --parseopt -- -h > output < optionspec\n+\ttest_cmp expect output\n '\n \n cat > expect <<EOF\n-- \n1.7.1\n"}]}