2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
11 static int print_spec_name(git_str
*out
, const cli_opt_spec
*spec
)
13 if (spec
->type
== CLI_OPT_TYPE_VALUE
&& spec
->alias
&&
14 !(spec
->usage
& CLI_OPT_USAGE_VALUE_OPTIONAL
) &&
15 !(spec
->usage
& CLI_OPT_USAGE_SHOW_LONG
))
16 return git_str_printf(out
, "-%c <%s>", spec
->alias
, spec
->value_name
);
17 if (spec
->type
== CLI_OPT_TYPE_VALUE
&& spec
->alias
&&
18 !(spec
->usage
& CLI_OPT_USAGE_SHOW_LONG
))
19 return git_str_printf(out
, "-%c [<%s>]", spec
->alias
, spec
->value_name
);
20 if (spec
->type
== CLI_OPT_TYPE_VALUE
&&
21 !(spec
->usage
& CLI_OPT_USAGE_VALUE_OPTIONAL
))
22 return git_str_printf(out
, "--%s[=<%s>]", spec
->name
, spec
->value_name
);
23 if (spec
->type
== CLI_OPT_TYPE_VALUE
)
24 return git_str_printf(out
, "--%s=<%s>", spec
->name
, spec
->value_name
);
25 if (spec
->type
== CLI_OPT_TYPE_ARG
)
26 return git_str_printf(out
, "<%s>", spec
->value_name
);
27 if (spec
->type
== CLI_OPT_TYPE_ARGS
)
28 return git_str_printf(out
, "<%s>...", spec
->value_name
);
29 if (spec
->type
== CLI_OPT_TYPE_LITERAL
)
30 return git_str_printf(out
, "--");
31 if (spec
->alias
&& !(spec
->usage
& CLI_OPT_USAGE_SHOW_LONG
))
32 return git_str_printf(out
, "-%c", spec
->alias
);
34 return git_str_printf(out
, "--%s", spec
->name
);
40 * This is similar to adopt's function, but modified to understand
41 * that we have a command ("git") and a "subcommand" ("checkout").
42 * It also understands a terminal's line length and wrap appropriately,
43 * using a `git_str` for storage.
45 int cli_opt_usage_fprint(
48 const char *subcommand
,
49 const cli_opt_spec specs
[])
51 git_str usage
= GIT_BUF_INIT
, opt
= GIT_BUF_INIT
;
52 const cli_opt_spec
*spec
;
53 size_t i
, prefixlen
, linelen
;
54 bool choice
= false, next_choice
= false, optional
= false;
57 /* TODO: query actual console width. */
58 int console_width
= 80;
60 if ((error
= git_str_printf(&usage
, "usage: %s", command
)) < 0)
64 (error
= git_str_printf(&usage
, " %s", subcommand
)) < 0)
67 linelen
= git_str_len(&usage
);
68 prefixlen
= linelen
+ 1;
70 for (spec
= specs
; spec
->type
; ++spec
) {
72 optional
= !(spec
->usage
& CLI_OPT_USAGE_REQUIRED
);
74 next_choice
= !!((spec
+ 1)->usage
& CLI_OPT_USAGE_CHOICE
);
76 if (spec
->usage
& CLI_OPT_USAGE_HIDDEN
)
80 git_str_putc(&opt
, '|');
84 if (optional
&& !choice
)
85 git_str_putc(&opt
, '[');
86 if (!optional
&& !choice
&& next_choice
)
87 git_str_putc(&opt
, '(');
89 if ((error
= print_spec_name(&opt
, spec
)) < 0)
92 if (!optional
&& choice
&& !next_choice
)
93 git_str_putc(&opt
, ')');
94 else if (optional
&& !next_choice
)
95 git_str_putc(&opt
, ']');
97 if ((choice
= next_choice
))
100 if (git_str_oom(&opt
)) {
105 if (linelen
> prefixlen
&&
107 linelen
+ git_str_len(&opt
) + 1 > (size_t)console_width
) {
108 git_str_putc(&usage
, '\n');
110 for (i
= 0; i
< prefixlen
; i
++)
111 git_str_putc(&usage
, ' ');
115 git_str_putc(&usage
, ' ');
116 linelen
+= git_str_len(&opt
) + 1;
119 git_str_puts(&usage
, git_str_cstr(&opt
));
121 if (git_str_oom(&usage
)) {
127 error
= fprintf(file
, "%s\n", git_str_cstr(&usage
));
130 error
= (error
< 0) ? -1 : 0;
132 git_str_dispose(&usage
);
133 git_str_dispose(&opt
);
137 int cli_opt_usage_error(
138 const char *subcommand
,
139 const cli_opt_spec specs
[],
140 const cli_opt
*invalid_opt
)
142 cli_opt_status_fprint(stderr
, PROGRAM_NAME
, invalid_opt
);
143 cli_opt_usage_fprint(stderr
, PROGRAM_NAME
, subcommand
, specs
);
144 return CLI_EXIT_USAGE
;
147 int cli_opt_help_fprint(
149 const cli_opt_spec specs
[])
151 git_str help
= GIT_BUF_INIT
;
152 const cli_opt_spec
*spec
;
155 /* Display required arguments first */
156 for (spec
= specs
; spec
->type
; ++spec
) {
157 if (! (spec
->usage
& CLI_OPT_USAGE_REQUIRED
) ||
158 (spec
->usage
& CLI_OPT_USAGE_HIDDEN
))
161 git_str_printf(&help
, " ");
163 if ((error
= print_spec_name(&help
, spec
)) < 0)
166 git_str_printf(&help
, ": %s\n", spec
->help
);
169 /* Display the remaining arguments */
170 for (spec
= specs
; spec
->type
; ++spec
) {
171 if ((spec
->usage
& CLI_OPT_USAGE_REQUIRED
) ||
172 (spec
->usage
& CLI_OPT_USAGE_HIDDEN
))
175 git_str_printf(&help
, " ");
177 if ((error
= print_spec_name(&help
, spec
)) < 0)
180 git_str_printf(&help
, ": %s\n", spec
->help
);
184 if (git_str_oom(&help
) ||
185 p_write(fileno(file
), help
.ptr
, help
.size
) < 0)
189 error
= (error
< 0) ? -1 : 0;
191 git_str_dispose(&help
);