Coverage Report

Created: 2023-11-19 07:08

/src/git/builtin/help.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Builtin help command
3
 */
4
#include "builtin.h"
5
#include "config.h"
6
#include "exec-cmd.h"
7
#include "gettext.h"
8
#include "pager.h"
9
#include "parse-options.h"
10
#include "path.h"
11
#include "run-command.h"
12
#include "config-list.h"
13
#include "help.h"
14
#include "alias.h"
15
#include "setup.h"
16
17
#ifndef DEFAULT_HELP_FORMAT
18
0
#define DEFAULT_HELP_FORMAT "man"
19
#endif
20
21
static struct man_viewer_list {
22
  struct man_viewer_list *next;
23
  char name[FLEX_ARRAY];
24
} *man_viewer_list;
25
26
static struct man_viewer_info_list {
27
  struct man_viewer_info_list *next;
28
  const char *info;
29
  char name[FLEX_ARRAY];
30
} *man_viewer_info_list;
31
32
enum help_format {
33
  HELP_FORMAT_NONE,
34
  HELP_FORMAT_MAN,
35
  HELP_FORMAT_INFO,
36
  HELP_FORMAT_WEB
37
};
38
39
enum show_config_type {
40
  SHOW_CONFIG_HUMAN,
41
  SHOW_CONFIG_VARS,
42
  SHOW_CONFIG_SECTIONS,
43
};
44
45
static enum help_action {
46
  HELP_ACTION_ALL = 1,
47
  HELP_ACTION_GUIDES,
48
  HELP_ACTION_CONFIG,
49
  HELP_ACTION_USER_INTERFACES,
50
  HELP_ACTION_DEVELOPER_INTERFACES,
51
  HELP_ACTION_CONFIG_FOR_COMPLETION,
52
  HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION,
53
} cmd_mode;
54
55
static const char *html_path;
56
static int verbose = 1;
57
static enum help_format help_format = HELP_FORMAT_NONE;
58
static int exclude_guides;
59
static int show_external_commands = -1;
60
static int show_aliases = -1;
61
static struct option builtin_help_options[] = {
62
  OPT_CMDMODE('a', "all", &cmd_mode, N_("print all available commands"),
63
        HELP_ACTION_ALL),
64
  OPT_BOOL(0, "external-commands", &show_external_commands,
65
     N_("show external commands in --all")),
66
  OPT_BOOL(0, "aliases", &show_aliases, N_("show aliases in --all")),
67
  OPT_HIDDEN_BOOL(0, "exclude-guides", &exclude_guides, N_("exclude guides")),
68
  OPT_SET_INT('m', "man", &help_format, N_("show man page"), HELP_FORMAT_MAN),
69
  OPT_SET_INT('w', "web", &help_format, N_("show manual in web browser"),
70
      HELP_FORMAT_WEB),
71
  OPT_SET_INT('i', "info", &help_format, N_("show info page"),
72
      HELP_FORMAT_INFO),
73
  OPT__VERBOSE(&verbose, N_("print command description")),
74
75
  OPT_CMDMODE('g', "guides", &cmd_mode, N_("print list of useful guides"),
76
        HELP_ACTION_GUIDES),
77
  OPT_CMDMODE(0, "user-interfaces", &cmd_mode,
78
        N_("print list of user-facing repository, command and file interfaces"),
79
        HELP_ACTION_USER_INTERFACES),
80
  OPT_CMDMODE(0, "developer-interfaces", &cmd_mode,
81
        N_("print list of file formats, protocols and other developer interfaces"),
82
        HELP_ACTION_DEVELOPER_INTERFACES),
83
  OPT_CMDMODE('c', "config", &cmd_mode, N_("print all configuration variable names"),
84
        HELP_ACTION_CONFIG),
85
  OPT_CMDMODE_F(0, "config-for-completion", &cmd_mode, "",
86
        HELP_ACTION_CONFIG_FOR_COMPLETION, PARSE_OPT_HIDDEN),
87
  OPT_CMDMODE_F(0, "config-sections-for-completion", &cmd_mode, "",
88
        HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION, PARSE_OPT_HIDDEN),
89
90
  OPT_END(),
91
};
92
93
static const char * const builtin_help_usage[] = {
94
  "git help [-a|--all] [--[no-]verbose] [--[no-]external-commands] [--[no-]aliases]",
95
  N_("git help [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]"),
96
  "git help [-g|--guides]",
97
  "git help [-c|--config]",
98
  "git help [--user-interfaces]",
99
  "git help [--developer-interfaces]",
100
  NULL
101
};
102
103
struct slot_expansion {
104
  const char *prefix;
105
  const char *placeholder;
106
  void (*fn)(struct string_list *list, const char *prefix);
107
  int found;
108
};
109
110
static void list_config_help(enum show_config_type type)
111
0
{
112
0
  struct slot_expansion slot_expansions[] = {
113
0
    { "advice", "*", list_config_advices },
114
0
    { "color.branch", "<slot>", list_config_color_branch_slots },
115
0
    { "color.decorate", "<slot>", list_config_color_decorate_slots },
116
0
    { "color.diff", "<slot>", list_config_color_diff_slots },
117
0
    { "color.grep", "<slot>", list_config_color_grep_slots },
118
0
    { "color.interactive", "<slot>", list_config_color_interactive_slots },
119
0
    { "color.remote", "<slot>", list_config_color_sideband_slots },
120
0
    { "color.status", "<slot>", list_config_color_status_slots },
121
0
    { "fsck", "<msg-id>", list_config_fsck_msg_ids },
122
0
    { "receive.fsck", "<msg-id>", list_config_fsck_msg_ids },
123
0
    { NULL, NULL, NULL }
124
0
  };
125
0
  const char **p;
126
0
  struct slot_expansion *e;
127
0
  struct string_list keys = STRING_LIST_INIT_DUP;
128
0
  struct string_list keys_uniq = STRING_LIST_INIT_DUP;
129
0
  struct string_list_item *item;
130
0
  int i;
131
132
0
  for (p = config_name_list; *p; p++) {
133
0
    const char *var = *p;
134
0
    struct strbuf sb = STRBUF_INIT;
135
136
0
    for (e = slot_expansions; e->prefix; e++) {
137
138
0
      strbuf_reset(&sb);
139
0
      strbuf_addf(&sb, "%s.%s", e->prefix, e->placeholder);
140
0
      if (!strcasecmp(var, sb.buf)) {
141
0
        e->fn(&keys, e->prefix);
142
0
        e->found++;
143
0
        break;
144
0
      }
145
0
    }
146
0
    strbuf_release(&sb);
147
0
    if (!e->prefix)
148
0
      string_list_append(&keys, var);
149
0
  }
150
151
0
  for (e = slot_expansions; e->prefix; e++)
152
0
    if (!e->found)
153
0
      BUG("slot_expansion %s.%s is not used",
154
0
          e->prefix, e->placeholder);
155
156
0
  string_list_sort(&keys);
157
0
  for (i = 0; i < keys.nr; i++) {
158
0
    const char *var = keys.items[i].string;
159
0
    const char *wildcard, *tag, *cut;
160
0
    const char *dot = NULL;
161
0
    struct strbuf sb = STRBUF_INIT;
162
163
0
    switch (type) {
164
0
    case SHOW_CONFIG_HUMAN:
165
0
      puts(var);
166
0
      continue;
167
0
    case SHOW_CONFIG_SECTIONS:
168
0
      dot = strchr(var, '.');
169
0
      break;
170
0
    case SHOW_CONFIG_VARS:
171
0
      break;
172
0
    }
173
0
    wildcard = strchr(var, '*');
174
0
    tag = strchr(var, '<');
175
176
0
    if (!dot && !wildcard && !tag) {
177
0
      string_list_append(&keys_uniq, var);
178
0
      continue;
179
0
    }
180
181
0
    if (dot)
182
0
      cut = dot;
183
0
    else if (wildcard && !tag)
184
0
      cut = wildcard;
185
0
    else if (!wildcard && tag)
186
0
      cut = tag;
187
0
    else
188
0
      cut = wildcard < tag ? wildcard : tag;
189
190
0
    strbuf_add(&sb, var, cut - var);
191
0
    string_list_append(&keys_uniq, sb.buf);
192
0
    strbuf_release(&sb);
193
194
0
  }
195
0
  string_list_clear(&keys, 0);
196
0
  string_list_remove_duplicates(&keys_uniq, 0);
197
0
  for_each_string_list_item(item, &keys_uniq)
198
0
    puts(item->string);
199
0
  string_list_clear(&keys_uniq, 0);
200
0
}
201
202
static enum help_format parse_help_format(const char *format)
203
0
{
204
0
  if (!strcmp(format, "man"))
205
0
    return HELP_FORMAT_MAN;
206
0
  if (!strcmp(format, "info"))
207
0
    return HELP_FORMAT_INFO;
208
0
  if (!strcmp(format, "web") || !strcmp(format, "html"))
209
0
    return HELP_FORMAT_WEB;
210
  /*
211
   * Please update _git_config() in git-completion.bash when you
212
   * add new help formats.
213
   */
214
0
  die(_("unrecognized help format '%s'"), format);
215
0
}
216
217
static const char *get_man_viewer_info(const char *name)
218
0
{
219
0
  struct man_viewer_info_list *viewer;
220
221
0
  for (viewer = man_viewer_info_list; viewer; viewer = viewer->next)
222
0
  {
223
0
    if (!strcasecmp(name, viewer->name))
224
0
      return viewer->info;
225
0
  }
226
0
  return NULL;
227
0
}
228
229
static int check_emacsclient_version(void)
230
0
{
231
0
  struct strbuf buffer = STRBUF_INIT;
232
0
  struct child_process ec_process = CHILD_PROCESS_INIT;
233
0
  int version;
234
235
  /* emacsclient prints its version number on stderr */
236
0
  strvec_pushl(&ec_process.args, "emacsclient", "--version", NULL);
237
0
  ec_process.err = -1;
238
0
  ec_process.stdout_to_stderr = 1;
239
0
  if (start_command(&ec_process))
240
0
    return error(_("Failed to start emacsclient."));
241
242
0
  strbuf_read(&buffer, ec_process.err, 20);
243
0
  close(ec_process.err);
244
245
  /*
246
   * Don't bother checking return value, because "emacsclient --version"
247
   * seems to always exits with code 1.
248
   */
249
0
  finish_command(&ec_process);
250
251
0
  if (!starts_with(buffer.buf, "emacsclient")) {
252
0
    strbuf_release(&buffer);
253
0
    return error(_("Failed to parse emacsclient version."));
254
0
  }
255
256
0
  strbuf_remove(&buffer, 0, strlen("emacsclient"));
257
0
  version = atoi(buffer.buf);
258
259
0
  if (version < 22) {
260
0
    strbuf_release(&buffer);
261
0
    return error(_("emacsclient version '%d' too old (< 22)."),
262
0
      version);
263
0
  }
264
265
0
  strbuf_release(&buffer);
266
0
  return 0;
267
0
}
268
269
static void exec_woman_emacs(const char *path, const char *page)
270
0
{
271
0
  if (!check_emacsclient_version()) {
272
    /* This works only with emacsclient version >= 22. */
273
0
    struct strbuf man_page = STRBUF_INIT;
274
275
0
    if (!path)
276
0
      path = "emacsclient";
277
0
    strbuf_addf(&man_page, "(woman \"%s\")", page);
278
0
    execlp(path, "emacsclient", "-e", man_page.buf, (char *)NULL);
279
0
    warning_errno(_("failed to exec '%s'"), path);
280
0
    strbuf_release(&man_page);
281
0
  }
282
0
}
283
284
static void exec_man_konqueror(const char *path, const char *page)
285
0
{
286
0
  const char *display = getenv("DISPLAY");
287
0
  if (display && *display) {
288
0
    struct strbuf man_page = STRBUF_INIT;
289
0
    const char *filename = "kfmclient";
290
291
    /* It's simpler to launch konqueror using kfmclient. */
292
0
    if (path) {
293
0
      size_t len;
294
0
      if (strip_suffix(path, "/konqueror", &len))
295
0
        path = xstrfmt("%.*s/kfmclient", (int)len, path);
296
0
      filename = basename((char *)path);
297
0
    } else
298
0
      path = "kfmclient";
299
0
    strbuf_addf(&man_page, "man:%s(1)", page);
300
0
    execlp(path, filename, "newTab", man_page.buf, (char *)NULL);
301
0
    warning_errno(_("failed to exec '%s'"), path);
302
0
    strbuf_release(&man_page);
303
0
  }
304
0
}
305
306
static void exec_man_man(const char *path, const char *page)
307
0
{
308
0
  if (!path)
309
0
    path = "man";
310
0
  execlp(path, "man", page, (char *)NULL);
311
0
  warning_errno(_("failed to exec '%s'"), path);
312
0
}
313
314
static void exec_man_cmd(const char *cmd, const char *page)
315
0
{
316
0
  struct strbuf shell_cmd = STRBUF_INIT;
317
0
  strbuf_addf(&shell_cmd, "%s %s", cmd, page);
318
0
  execl(SHELL_PATH, SHELL_PATH, "-c", shell_cmd.buf, (char *)NULL);
319
0
  warning(_("failed to exec '%s'"), cmd);
320
0
  strbuf_release(&shell_cmd);
321
0
}
322
323
static void add_man_viewer(const char *name)
324
0
{
325
0
  struct man_viewer_list **p = &man_viewer_list;
326
327
0
  while (*p)
328
0
    p = &((*p)->next);
329
0
  FLEX_ALLOC_STR(*p, name, name);
330
0
}
331
332
static int supported_man_viewer(const char *name, size_t len)
333
0
{
334
0
  return (!strncasecmp("man", name, len) ||
335
0
    !strncasecmp("woman", name, len) ||
336
0
    !strncasecmp("konqueror", name, len));
337
0
}
338
339
static void do_add_man_viewer_info(const char *name,
340
           size_t len,
341
           const char *value)
342
0
{
343
0
  struct man_viewer_info_list *new_man_viewer;
344
0
  FLEX_ALLOC_MEM(new_man_viewer, name, name, len);
345
0
  new_man_viewer->info = xstrdup(value);
346
0
  new_man_viewer->next = man_viewer_info_list;
347
0
  man_viewer_info_list = new_man_viewer;
348
0
}
349
350
static int add_man_viewer_path(const char *name,
351
             size_t len,
352
             const char *value)
353
0
{
354
0
  if (supported_man_viewer(name, len))
355
0
    do_add_man_viewer_info(name, len, value);
356
0
  else
357
0
    warning(_("'%s': path for unsupported man viewer.\n"
358
0
        "Please consider using 'man.<tool>.cmd' instead."),
359
0
      name);
360
361
0
  return 0;
362
0
}
363
364
static int add_man_viewer_cmd(const char *name,
365
            size_t len,
366
            const char *value)
367
0
{
368
0
  if (supported_man_viewer(name, len))
369
0
    warning(_("'%s': cmd for supported man viewer.\n"
370
0
        "Please consider using 'man.<tool>.path' instead."),
371
0
      name);
372
0
  else
373
0
    do_add_man_viewer_info(name, len, value);
374
375
0
  return 0;
376
0
}
377
378
static int add_man_viewer_info(const char *var, const char *value)
379
0
{
380
0
  const char *name, *subkey;
381
0
  size_t namelen;
382
383
0
  if (parse_config_key(var, "man", &name, &namelen, &subkey) < 0 || !name)
384
0
    return 0;
385
386
0
  if (!strcmp(subkey, "path")) {
387
0
    if (!value)
388
0
      return config_error_nonbool(var);
389
0
    return add_man_viewer_path(name, namelen, value);
390
0
  }
391
0
  if (!strcmp(subkey, "cmd")) {
392
0
    if (!value)
393
0
      return config_error_nonbool(var);
394
0
    return add_man_viewer_cmd(name, namelen, value);
395
0
  }
396
397
0
  return 0;
398
0
}
399
400
static int git_help_config(const char *var, const char *value,
401
         const struct config_context *ctx, void *cb)
402
0
{
403
0
  if (!strcmp(var, "help.format")) {
404
0
    if (!value)
405
0
      return config_error_nonbool(var);
406
0
    help_format = parse_help_format(value);
407
0
    return 0;
408
0
  }
409
0
  if (!strcmp(var, "help.htmlpath")) {
410
0
    if (!value)
411
0
      return config_error_nonbool(var);
412
0
    html_path = xstrdup(value);
413
0
    return 0;
414
0
  }
415
0
  if (!strcmp(var, "man.viewer")) {
416
0
    if (!value)
417
0
      return config_error_nonbool(var);
418
0
    add_man_viewer(value);
419
0
    return 0;
420
0
  }
421
0
  if (starts_with(var, "man."))
422
0
    return add_man_viewer_info(var, value);
423
424
0
  return git_default_config(var, value, ctx, cb);
425
0
}
426
427
static struct cmdnames main_cmds, other_cmds;
428
429
static int is_git_command(const char *s)
430
0
{
431
0
  if (is_builtin(s))
432
0
    return 1;
433
434
0
  load_command_list("git-", &main_cmds, &other_cmds);
435
0
  return is_in_cmdlist(&main_cmds, s) ||
436
0
    is_in_cmdlist(&other_cmds, s);
437
0
}
438
439
static const char *cmd_to_page(const char *git_cmd)
440
0
{
441
0
  if (!git_cmd)
442
0
    return "git";
443
0
  else if (starts_with(git_cmd, "git"))
444
0
    return git_cmd;
445
0
  else if (is_git_command(git_cmd))
446
0
    return xstrfmt("git-%s", git_cmd);
447
0
  else if (!strcmp("scalar", git_cmd))
448
0
    return xstrdup(git_cmd);
449
0
  else
450
0
    return xstrfmt("git%s", git_cmd);
451
0
}
452
453
static void setup_man_path(void)
454
0
{
455
0
  struct strbuf new_path = STRBUF_INIT;
456
0
  const char *old_path = getenv("MANPATH");
457
0
  char *git_man_path = system_path(GIT_MAN_PATH);
458
459
  /* We should always put ':' after our path. If there is no
460
   * old_path, the ':' at the end will let 'man' to try
461
   * system-wide paths after ours to find the manual page. If
462
   * there is old_path, we need ':' as delimiter. */
463
0
  strbuf_addstr(&new_path, git_man_path);
464
0
  strbuf_addch(&new_path, ':');
465
0
  if (old_path)
466
0
    strbuf_addstr(&new_path, old_path);
467
468
0
  free(git_man_path);
469
0
  setenv("MANPATH", new_path.buf, 1);
470
471
0
  strbuf_release(&new_path);
472
0
}
473
474
static void exec_viewer(const char *name, const char *page)
475
0
{
476
0
  const char *info = get_man_viewer_info(name);
477
478
0
  if (!strcasecmp(name, "man"))
479
0
    exec_man_man(info, page);
480
0
  else if (!strcasecmp(name, "woman"))
481
0
    exec_woman_emacs(info, page);
482
0
  else if (!strcasecmp(name, "konqueror"))
483
0
    exec_man_konqueror(info, page);
484
0
  else if (info)
485
0
    exec_man_cmd(info, page);
486
0
  else
487
0
    warning(_("'%s': unknown man viewer."), name);
488
0
}
489
490
static void show_man_page(const char *page)
491
0
{
492
0
  struct man_viewer_list *viewer;
493
0
  const char *fallback = getenv("GIT_MAN_VIEWER");
494
495
0
  setup_man_path();
496
0
  for (viewer = man_viewer_list; viewer; viewer = viewer->next)
497
0
  {
498
0
    exec_viewer(viewer->name, page); /* will return when unable */
499
0
  }
500
0
  if (fallback)
501
0
    exec_viewer(fallback, page);
502
0
  exec_viewer("man", page);
503
0
  die(_("no man viewer handled the request"));
504
0
}
505
506
static void show_info_page(const char *page)
507
0
{
508
0
  setenv("INFOPATH", system_path(GIT_INFO_PATH), 1);
509
0
  execlp("info", "info", "gitman", page, (char *)NULL);
510
0
  die(_("no info viewer handled the request"));
511
0
}
512
513
static void get_html_page_path(struct strbuf *page_path, const char *page)
514
0
{
515
0
  struct stat st;
516
0
  char *to_free = NULL;
517
518
0
  if (!html_path)
519
0
    html_path = to_free = system_path(GIT_HTML_PATH);
520
521
  /*
522
   * Check that the page we're looking for exists.
523
   */
524
0
  if (!strstr(html_path, "://")) {
525
0
    if (stat(mkpath("%s/%s.html", html_path, page), &st)
526
0
        || !S_ISREG(st.st_mode))
527
0
      die("'%s/%s.html': documentation file not found.",
528
0
        html_path, page);
529
0
  }
530
531
0
  strbuf_init(page_path, 0);
532
0
  strbuf_addf(page_path, "%s/%s.html", html_path, page);
533
0
  free(to_free);
534
0
}
535
536
static void open_html(const char *path)
537
0
{
538
0
  execl_git_cmd("web--browse", "-c", "help.browser", path, (char *)NULL);
539
0
}
540
541
static void show_html_page(const char *page)
542
0
{
543
0
  struct strbuf page_path; /* it leaks but we exec bellow */
544
545
0
  get_html_page_path(&page_path, page);
546
547
0
  open_html(page_path.buf);
548
0
}
549
550
static const char *check_git_cmd(const char* cmd)
551
0
{
552
0
  char *alias;
553
554
0
  if (is_git_command(cmd))
555
0
    return cmd;
556
557
0
  alias = alias_lookup(cmd);
558
0
  if (alias) {
559
0
    const char **argv;
560
0
    int count;
561
562
    /*
563
     * handle_builtin() in git.c rewrites "git cmd --help"
564
     * to "git help --exclude-guides cmd", so we can use
565
     * exclude_guides to distinguish "git cmd --help" from
566
     * "git help cmd". In the latter case, or if cmd is an
567
     * alias for a shell command, just print the alias
568
     * definition.
569
     */
570
0
    if (!exclude_guides || alias[0] == '!') {
571
0
      printf_ln(_("'%s' is aliased to '%s'"), cmd, alias);
572
0
      free(alias);
573
0
      exit(0);
574
0
    }
575
    /*
576
     * Otherwise, we pretend that the command was "git
577
     * word0 --help". We use split_cmdline() to get the
578
     * first word of the alias, to ensure that we use the
579
     * same rules as when the alias is actually
580
     * used. split_cmdline() modifies alias in-place.
581
     */
582
0
    fprintf_ln(stderr, _("'%s' is aliased to '%s'"), cmd, alias);
583
0
    count = split_cmdline(alias, &argv);
584
0
    if (count < 0)
585
0
      die(_("bad alias.%s string: %s"), cmd,
586
0
          split_cmdline_strerror(count));
587
0
    free(argv);
588
0
    UNLEAK(alias);
589
0
    return alias;
590
0
  }
591
592
0
  if (exclude_guides)
593
0
    return help_unknown_cmd(cmd);
594
595
0
  return cmd;
596
0
}
597
598
static void no_help_format(const char *opt_mode, enum help_format fmt)
599
0
{
600
0
  const char *opt_fmt;
601
602
0
  switch (fmt) {
603
0
  case HELP_FORMAT_NONE:
604
0
    return;
605
0
  case HELP_FORMAT_MAN:
606
0
    opt_fmt = "--man";
607
0
    break;
608
0
  case HELP_FORMAT_INFO:
609
0
    opt_fmt = "--info";
610
0
    break;
611
0
  case HELP_FORMAT_WEB:
612
0
    opt_fmt = "--web";
613
0
    break;
614
0
  default:
615
0
    BUG("unreachable");
616
0
  }
617
618
0
  usage_msg_optf(_("options '%s' and '%s' cannot be used together"),
619
0
           builtin_help_usage, builtin_help_options, opt_mode,
620
0
           opt_fmt);
621
0
}
622
623
static void opt_mode_usage(int argc, const char *opt_mode,
624
         enum help_format fmt)
625
0
{
626
0
  if (argc)
627
0
    usage_msg_optf(_("the '%s' option doesn't take any non-option arguments"),
628
0
             builtin_help_usage, builtin_help_options,
629
0
             opt_mode);
630
631
0
  no_help_format(opt_mode, fmt);
632
0
}
633
634
int cmd_help(int argc, const char **argv, const char *prefix)
635
0
{
636
0
  int nongit;
637
0
  enum help_format parsed_help_format;
638
0
  const char *page;
639
640
0
  argc = parse_options(argc, argv, prefix, builtin_help_options,
641
0
      builtin_help_usage, 0);
642
0
  parsed_help_format = help_format;
643
644
0
  if (cmd_mode != HELP_ACTION_ALL &&
645
0
      (show_external_commands >= 0 ||
646
0
       show_aliases >= 0))
647
0
    usage_msg_opt(_("the '--no-[external-commands|aliases]' options can only be used with '--all'"),
648
0
            builtin_help_usage, builtin_help_options);
649
650
0
  switch (cmd_mode) {
651
0
  case HELP_ACTION_ALL:
652
0
    opt_mode_usage(argc, "--all", help_format);
653
0
    if (verbose) {
654
0
      setup_pager();
655
0
      list_all_cmds_help(show_external_commands,
656
0
             show_aliases);
657
0
      return 0;
658
0
    }
659
0
    printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
660
0
    load_command_list("git-", &main_cmds, &other_cmds);
661
0
    list_commands(&main_cmds, &other_cmds);
662
0
    printf("%s\n", _(git_more_info_string));
663
0
    break;
664
0
  case HELP_ACTION_GUIDES:
665
0
    opt_mode_usage(argc, "--guides", help_format);
666
0
    list_guides_help();
667
0
    printf("%s\n", _(git_more_info_string));
668
0
    return 0;
669
0
  case HELP_ACTION_CONFIG_FOR_COMPLETION:
670
0
    opt_mode_usage(argc, "--config-for-completion", help_format);
671
0
    list_config_help(SHOW_CONFIG_VARS);
672
0
    return 0;
673
0
  case HELP_ACTION_USER_INTERFACES:
674
0
    opt_mode_usage(argc, "--user-interfaces", help_format);
675
0
    list_user_interfaces_help();
676
0
    return 0;
677
0
  case HELP_ACTION_DEVELOPER_INTERFACES:
678
0
    opt_mode_usage(argc, "--developer-interfaces", help_format);
679
0
    list_developer_interfaces_help();
680
0
    return 0;
681
0
  case HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION:
682
0
    opt_mode_usage(argc, "--config-sections-for-completion",
683
0
             help_format);
684
0
    list_config_help(SHOW_CONFIG_SECTIONS);
685
0
    return 0;
686
0
  case HELP_ACTION_CONFIG:
687
0
    opt_mode_usage(argc, "--config", help_format);
688
0
    setup_pager();
689
0
    list_config_help(SHOW_CONFIG_HUMAN);
690
0
    printf("\n%s\n", _("'git help config' for more information"));
691
0
    return 0;
692
0
  }
693
694
0
  if (!argv[0]) {
695
0
    printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
696
0
    list_common_cmds_help();
697
0
    printf("\n%s\n", _(git_more_info_string));
698
0
    return 0;
699
0
  }
700
701
0
  setup_git_directory_gently(&nongit);
702
0
  git_config(git_help_config, NULL);
703
704
0
  if (parsed_help_format != HELP_FORMAT_NONE)
705
0
    help_format = parsed_help_format;
706
0
  if (help_format == HELP_FORMAT_NONE)
707
0
    help_format = parse_help_format(DEFAULT_HELP_FORMAT);
708
709
0
  argv[0] = check_git_cmd(argv[0]);
710
711
0
  page = cmd_to_page(argv[0]);
712
0
  switch (help_format) {
713
0
  case HELP_FORMAT_NONE:
714
0
  case HELP_FORMAT_MAN:
715
0
    show_man_page(page);
716
0
    break;
717
0
  case HELP_FORMAT_INFO:
718
0
    show_info_page(page);
719
0
    break;
720
0
  case HELP_FORMAT_WEB:
721
0
    show_html_page(page);
722
0
    break;
723
0
  }
724
725
0
  return 0;
726
0
}