Builtin git-help.
This patch splits out git-help's functions to builtin-help.c and leaves only functions used by other builtins in help.c. First this removes git-help's functions from libgit which are not interesting for other builtins, second this makes 'git help help' work again. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Miklos Vajna committed
Aug 2, 2008 at 10:08 UTC
3d78d1f18f211fd3d3e95977dee85a17a2aeb16c
4 files changed
+470
-465
Makefile
+2
-1
@@ -519,6 +519,7 @@ BUILTIN_OBJS += builtin-for-each-ref.o
519
BUILTIN_OBJS += builtin-fsck.o
520
BUILTIN_OBJS += builtin-gc.o
521
BUILTIN_OBJS += builtin-grep.o
522
+BUILTIN_OBJS += builtin-help.o
523
BUILTIN_OBJS += builtin-init-db.o
524
BUILTIN_OBJS += builtin-log.o
525
BUILTIN_OBJS += builtin-ls-files.o
@@ -1085,7 +1086,7 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
1086
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
1087
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
1088
1088
-help.o: help.c common-cmds.h GIT-CFLAGS
1089
+builtin-help.o: builtin-help.c common-cmds.h GIT-CFLAGS
1090
$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
1091
'-DGIT_HTML_PATH="$(htmldir_SQ)"' \
1092
'-DGIT_MAN_PATH="$(mandir_SQ)"' \
builtin-help.c
new
+462
@@ -0,0 +1,462 @@
1
+/*
2
+ * builtin-help.c
3
+ *
4
+ * Builtin help command
5
+ */
6
+#include "cache.h"
7
+#include "builtin.h"
8
+#include "exec_cmd.h"
9
+#include "common-cmds.h"
10
+#include "parse-options.h"
11
+#include "run-command.h"
12
+#include "help.h"
13
+
14
+static struct man_viewer_list {
15
+ struct man_viewer_list *next;
16
+ char name[FLEX_ARRAY];
17
+} *man_viewer_list;
18
+
19
+static struct man_viewer_info_list {
20
+ struct man_viewer_info_list *next;
21
+ const char *info;
22
+ char name[FLEX_ARRAY];
23
+} *man_viewer_info_list;
24
+
25
+enum help_format {
26
+ HELP_FORMAT_MAN,
27
+ HELP_FORMAT_INFO,
28
+ HELP_FORMAT_WEB,
29
+};
30
+
31
+static int show_all = 0;
32
+static enum help_format help_format = HELP_FORMAT_MAN;
33
+static struct option builtin_help_options[] = {
34
+ OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
35
+ OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
36
+ OPT_SET_INT('w', "web", &help_format, "show manual in web browser",
37
+ HELP_FORMAT_WEB),
38
+ OPT_SET_INT('i', "info", &help_format, "show info page",
39
+ HELP_FORMAT_INFO),
40
+ OPT_END(),
41
+};
42
+
43
+static const char * const builtin_help_usage[] = {
44
+ "git help [--all] [--man|--web|--info] [command]",
45
+ NULL
46
+};
47
+
48
+static enum help_format parse_help_format(const char *format)
49
+{
50
+ if (!strcmp(format, "man"))
51
+ return HELP_FORMAT_MAN;
52
+ if (!strcmp(format, "info"))
53
+ return HELP_FORMAT_INFO;
54
+ if (!strcmp(format, "web") || !strcmp(format, "html"))
55
+ return HELP_FORMAT_WEB;
56
+ die("unrecognized help format '%s'", format);
57
+}
58
+
59
+static const char *get_man_viewer_info(const char *name)
60
+{
61
+ struct man_viewer_info_list *viewer;
62
+
63
+ for (viewer = man_viewer_info_list; viewer; viewer = viewer->next)
64
+ {
65
+ if (!strcasecmp(name, viewer->name))
66
+ return viewer->info;
67
+ }
68
+ return NULL;
69
+}
70
+
71
+static int check_emacsclient_version(void)
72
+{
73
+ struct strbuf buffer = STRBUF_INIT;
74
+ struct child_process ec_process;
75
+ const char *argv_ec[] = { "emacsclient", "--version", NULL };
76
+ int version;
77
+
78
+ /* emacsclient prints its version number on stderr */
79
+ memset(&ec_process, 0, sizeof(ec_process));
80
+ ec_process.argv = argv_ec;
81
+ ec_process.err = -1;
82
+ ec_process.stdout_to_stderr = 1;
83
+ if (start_command(&ec_process)) {
84
+ fprintf(stderr, "Failed to start emacsclient.\n");
85
+ return -1;
86
+ }
87
+ strbuf_read(&buffer, ec_process.err, 20);
88
+ close(ec_process.err);
89
+
90
+ /*
91
+ * Don't bother checking return value, because "emacsclient --version"
92
+ * seems to always exits with code 1.
93
+ */
94
+ finish_command(&ec_process);
95
+
96
+ if (prefixcmp(buffer.buf, "emacsclient")) {
97
+ fprintf(stderr, "Failed to parse emacsclient version.\n");
98
+ strbuf_release(&buffer);
99
+ return -1;
100
+ }
101
+
102
+ strbuf_remove(&buffer, 0, strlen("emacsclient"));
103
+ version = atoi(buffer.buf);
104
+
105
+ if (version < 22) {
106
+ fprintf(stderr,
107
+ "emacsclient version '%d' too old (< 22).\n",
108
+ version);
109
+ strbuf_release(&buffer);
110
+ return -1;
111
+ }
112
+
113
+ strbuf_release(&buffer);
114
+ return 0;
115
+}
116
+
117
+static void exec_woman_emacs(const char* path, const char *page)
118
+{
119
+ if (!check_emacsclient_version()) {
120
+ /* This works only with emacsclient version >= 22. */
121
+ struct strbuf man_page = STRBUF_INIT;
122
+
123
+ if (!path)
124
+ path = "emacsclient";
125
+ strbuf_addf(&man_page, "(woman \"%s\")", page);
126
+ execlp(path, "emacsclient", "-e", man_page.buf, NULL);
127
+ warning("failed to exec '%s': %s", path, strerror(errno));
128
+ }
129
+}
130
+
131
+static void exec_man_konqueror(const char* path, const char *page)
132
+{
133
+ const char *display = getenv("DISPLAY");
134
+ if (display && *display) {
135
+ struct strbuf man_page = STRBUF_INIT;
136
+ const char *filename = "kfmclient";
137
+
138
+ /* It's simpler to launch konqueror using kfmclient. */
139
+ if (path) {
140
+ const char *file = strrchr(path, '/');
141
+ if (file && !strcmp(file + 1, "konqueror")) {
142
+ char *new = xstrdup(path);
143
+ char *dest = strrchr(new, '/');
144
+
145
+ /* strlen("konqueror") == strlen("kfmclient") */
146
+ strcpy(dest + 1, "kfmclient");
147
+ path = new;
148
+ }
149
+ if (file)
150
+ filename = file;
151
+ } else
152
+ path = "kfmclient";
153
+ strbuf_addf(&man_page, "man:%s(1)", page);
154
+ execlp(path, filename, "newTab", man_page.buf, NULL);
155
+ warning("failed to exec '%s': %s", path, strerror(errno));
156
+ }
157
+}
158
+
159
+static void exec_man_man(const char* path, const char *page)
160
+{
161
+ if (!path)
162
+ path = "man";
163
+ execlp(path, "man", page, NULL);
164
+ warning("failed to exec '%s': %s", path, strerror(errno));
165
+}
166
+
167
+static void exec_man_cmd(const char *cmd, const char *page)
168
+{
169
+ struct strbuf shell_cmd = STRBUF_INIT;
170
+ strbuf_addf(&shell_cmd, "%s %s", cmd, page);
171
+ execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL);
172
+ warning("failed to exec '%s': %s", cmd, strerror(errno));
173
+}
174
+
175
+static void add_man_viewer(const char *name)
176
+{
177
+ struct man_viewer_list **p = &man_viewer_list;
178
+ size_t len = strlen(name);
179
+
180
+ while (*p)
181
+ p = &((*p)->next);
182
+ *p = xcalloc(1, (sizeof(**p) + len + 1));
183
+ strncpy((*p)->name, name, len);
184
+}
185
+
186
+static int supported_man_viewer(const char *name, size_t len)
187
+{
188
+ return (!strncasecmp("man", name, len) ||
189
+ !strncasecmp("woman", name, len) ||
190
+ !strncasecmp("konqueror", name, len));
191
+}
192
+
193
+static void do_add_man_viewer_info(const char *name,
194
+ size_t len,
195
+ const char *value)
196
+{
197
+ struct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1);
198
+
199
+ strncpy(new->name, name, len);
200
+ new->info = xstrdup(value);
201
+ new->next = man_viewer_info_list;
202
+ man_viewer_info_list = new;
203
+}
204
+
205
+static int add_man_viewer_path(const char *name,
206
+ size_t len,
207
+ const char *value)
208
+{
209
+ if (supported_man_viewer(name, len))
210
+ do_add_man_viewer_info(name, len, value);
211
+ else
212
+ warning("'%s': path for unsupported man viewer.\n"
213
+ "Please consider using 'man.<tool>.cmd' instead.",
214
+ name);
215
+
216
+ return 0;
217
+}
218
+
219
+static int add_man_viewer_cmd(const char *name,
220
+ size_t len,
221
+ const char *value)
222
+{
223
+ if (supported_man_viewer(name, len))
224
+ warning("'%s': cmd for supported man viewer.\n"
225
+ "Please consider using 'man.<tool>.path' instead.",
226
+ name);
227
+ else
228
+ do_add_man_viewer_info(name, len, value);
229
+
230
+ return 0;
231
+}
232
+
233
+static int add_man_viewer_info(const char *var, const char *value)
234
+{
235
+ const char *name = var + 4;
236
+ const char *subkey = strrchr(name, '.');
237
+
238
+ if (!subkey)
239
+ return error("Config with no key for man viewer: %s", name);
240
+
241
+ if (!strcmp(subkey, ".path")) {
242
+ if (!value)
243
+ return config_error_nonbool(var);
244
+ return add_man_viewer_path(name, subkey - name, value);
245
+ }
246
+ if (!strcmp(subkey, ".cmd")) {
247
+ if (!value)
248
+ return config_error_nonbool(var);
249
+ return add_man_viewer_cmd(name, subkey - name, value);
250
+ }
251
+
252
+ warning("'%s': unsupported man viewer sub key.", subkey);
253
+ return 0;
254
+}
255
+
256
+static int git_help_config(const char *var, const char *value, void *cb)
257
+{
258
+ if (!strcmp(var, "help.format")) {
259
+ if (!value)
260
+ return config_error_nonbool(var);
261
+ help_format = parse_help_format(value);
262
+ return 0;
263
+ }
264
+ if (!strcmp(var, "man.viewer")) {
265
+ if (!value)
266
+ return config_error_nonbool(var);
267
+ add_man_viewer(value);
268
+ return 0;
269
+ }
270
+ if (!prefixcmp(var, "man."))
271
+ return add_man_viewer_info(var, value);
272
+
273
+ return git_default_config(var, value, cb);
274
+}
275
+
276
+struct cmdnames main_cmds, other_cmds;
277
+
278
+void list_common_cmds_help(void)
279
+{
280
+ int i, longest = 0;
281
+
282
+ for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
283
+ if (longest < strlen(common_cmds[i].name))
284
+ longest = strlen(common_cmds[i].name);
285
+ }
286
+
287
+ puts("The most commonly used git commands are:");
288
+ for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
289
+ printf(" %s ", common_cmds[i].name);
290
+ mput_char(' ', longest - strlen(common_cmds[i].name));
291
+ puts(common_cmds[i].help);
292
+ }
293
+}
294
+
295
+static int is_git_command(const char *s)
296
+{
297
+ return is_in_cmdlist(&main_cmds, s) ||
298
+ is_in_cmdlist(&other_cmds, s);
299
+}
300
+
301
+static const char *prepend(const char *prefix, const char *cmd)
302
+{
303
+ size_t pre_len = strlen(prefix);
304
+ size_t cmd_len = strlen(cmd);
305
+ char *p = xmalloc(pre_len + cmd_len + 1);
306
+ memcpy(p, prefix, pre_len);
307
+ strcpy(p + pre_len, cmd);
308
+ return p;
309
+}
310
+
311
+static const char *cmd_to_page(const char *git_cmd)
312
+{
313
+ if (!git_cmd)
314
+ return "git";
315
+ else if (!prefixcmp(git_cmd, "git"))
316
+ return git_cmd;
317
+ else if (is_git_command(git_cmd))
318
+ return prepend("git-", git_cmd);
319
+ else
320
+ return prepend("git", git_cmd);
321
+}
322
+
323
+static void setup_man_path(void)
324
+{
325
+ struct strbuf new_path;
326
+ const char *old_path = getenv("MANPATH");
327
+
328
+ strbuf_init(&new_path, 0);
329
+
330
+ /* We should always put ':' after our path. If there is no
331
+ * old_path, the ':' at the end will let 'man' to try
332
+ * system-wide paths after ours to find the manual page. If
333
+ * there is old_path, we need ':' as delimiter. */
334
+ strbuf_addstr(&new_path, GIT_MAN_PATH);
335
+ strbuf_addch(&new_path, ':');
336
+ if (old_path)
337
+ strbuf_addstr(&new_path, old_path);
338
+
339
+ setenv("MANPATH", new_path.buf, 1);
340
+
341
+ strbuf_release(&new_path);
342
+}
343
+
344
+static void exec_viewer(const char *name, const char *page)
345
+{
346
+ const char *info = get_man_viewer_info(name);
347
+
348
+ if (!strcasecmp(name, "man"))
349
+ exec_man_man(info, page);
350
+ else if (!strcasecmp(name, "woman"))
351
+ exec_woman_emacs(info, page);
352
+ else if (!strcasecmp(name, "konqueror"))
353
+ exec_man_konqueror(info, page);
354
+ else if (info)
355
+ exec_man_cmd(info, page);
356
+ else
357
+ warning("'%s': unknown man viewer.", name);
358
+}
359
+
360
+static void show_man_page(const char *git_cmd)
361
+{
362
+ struct man_viewer_list *viewer;
363
+ const char *page = cmd_to_page(git_cmd);
364
+
365
+ setup_man_path();
366
+ for (viewer = man_viewer_list; viewer; viewer = viewer->next)
367
+ {
368
+ exec_viewer(viewer->name, page); /* will return when unable */
369
+ }
370
+ exec_viewer("man", page);
371
+ die("no man viewer handled the request");
372
+}
373
+
374
+static void show_info_page(const char *git_cmd)
375
+{
376
+ const char *page = cmd_to_page(git_cmd);
377
+ setenv("INFOPATH", GIT_INFO_PATH, 1);
378
+ execlp("info", "info", "gitman", page, NULL);
379
+}
380
+
381
+static void get_html_page_path(struct strbuf *page_path, const char *page)
382
+{
383
+ struct stat st;
384
+ const char *html_path = system_path(GIT_HTML_PATH);
385
+
386
+ /* Check that we have a git documentation directory. */
387
+ if (stat(mkpath("%s/git.html", html_path), &st)
388
+ || !S_ISREG(st.st_mode))
389
+ die("'%s': not a documentation directory.", html_path);
390
+
391
+ strbuf_init(page_path, 0);
392
+ strbuf_addf(page_path, "%s/%s.html", html_path, page);
393
+}
394
+
395
+/*
396
+ * If open_html is not defined in a platform-specific way (see for
397
+ * example compat/mingw.h), we use the script web--browse to display
398
+ * HTML.
399
+ */
400
+#ifndef open_html
401
+void open_html(const char *path)
402
+{
403
+ execl_git_cmd("web--browse", "-c", "help.browser", path, NULL);
404
+}
405
+#endif
406
+
407
+static void show_html_page(const char *git_cmd)
408
+{
409
+ const char *page = cmd_to_page(git_cmd);
410
+ struct strbuf page_path; /* it leaks but we exec bellow */
411
+
412
+ get_html_page_path(&page_path, page);
413
+
414
+ open_html(page_path.buf);
415
+}
416
+
417
+int cmd_help(int argc, const char **argv, const char *prefix)
418
+{
419
+ int nongit;
420
+ const char *alias;
421
+ unsigned int longest = load_command_list("git-", &main_cmds, &other_cmds);
422
+
423
+ setup_git_directory_gently(&nongit);
424
+ git_config(git_help_config, NULL);
425
+
426
+ argc = parse_options(argc, argv, builtin_help_options,
427
+ builtin_help_usage, 0);
428
+
429
+ if (show_all) {
430
+ printf("usage: %s\n\n", git_usage_string);
431
+ list_commands("git commands", longest, &main_cmds, &other_cmds);
432
+ printf("%s\n", git_more_info_string);
433
+ return 0;
434
+ }
435
+
436
+ if (!argv[0]) {
437
+ printf("usage: %s\n\n", git_usage_string);
438
+ list_common_cmds_help();
439
+ printf("\n%s\n", git_more_info_string);
440
+ return 0;
441
+ }
442
+
443
+ alias = alias_lookup(argv[0]);
444
+ if (alias && !is_git_command(argv[0])) {
445
+ printf("`git %s' is aliased to `%s'\n", argv[0], alias);
446
+ return 0;
447
+ }
448
+
449
+ switch (help_format) {
450
+ case HELP_FORMAT_MAN:
451
+ show_man_page(argv[0]);
452
+ break;
453
+ case HELP_FORMAT_INFO:
454
+ show_info_page(argv[0]);
455
+ break;
456
+ case HELP_FORMAT_WEB:
457
+ show_html_page(argv[0]);
458
+ break;
459
+ }
460
+
461
+ return 0;
462
+}
help.c
-464
@@ -1,278 +1,8 @@
1
-/*
2
- * builtin-help.c
3
- *
4
- * Builtin help-related commands (help, usage, version)
5
- */
1
#include "cache.h"
2
#include "builtin.h"
3
#include "exec_cmd.h"
9
-#include "common-cmds.h"
10
-#include "parse-options.h"
11
-#include "run-command.h"
4
#include "help.h"
5
14
-static struct man_viewer_list {
15
- struct man_viewer_list *next;
16
- char name[FLEX_ARRAY];
17
-} *man_viewer_list;
18
-
19
-static struct man_viewer_info_list {
20
- struct man_viewer_info_list *next;
21
- const char *info;
22
- char name[FLEX_ARRAY];
23
-} *man_viewer_info_list;
24
-
25
-enum help_format {
26
- HELP_FORMAT_MAN,
27
- HELP_FORMAT_INFO,
28
- HELP_FORMAT_WEB,
29
-};
30
-
31
-static int show_all = 0;
32
-static enum help_format help_format = HELP_FORMAT_MAN;
33
-static struct option builtin_help_options[] = {
34
- OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
35
- OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
36
- OPT_SET_INT('w', "web", &help_format, "show manual in web browser",
37
- HELP_FORMAT_WEB),
38
- OPT_SET_INT('i', "info", &help_format, "show info page",
39
- HELP_FORMAT_INFO),
40
- OPT_END(),
41
-};
42
-
43
-static const char * const builtin_help_usage[] = {
44
- "git help [--all] [--man|--web|--info] [command]",
45
- NULL
46
-};
47
-
48
-static enum help_format parse_help_format(const char *format)
49
-{
50
- if (!strcmp(format, "man"))
51
- return HELP_FORMAT_MAN;
52
- if (!strcmp(format, "info"))
53
- return HELP_FORMAT_INFO;
54
- if (!strcmp(format, "web") || !strcmp(format, "html"))
55
- return HELP_FORMAT_WEB;
56
- die("unrecognized help format '%s'", format);
57
-}
58
-
59
-static const char *get_man_viewer_info(const char *name)
60
-{
61
- struct man_viewer_info_list *viewer;
62
-
63
- for (viewer = man_viewer_info_list; viewer; viewer = viewer->next)
64
- {
65
- if (!strcasecmp(name, viewer->name))
66
- return viewer->info;
67
- }
68
- return NULL;
69
-}
70
-
71
-static int check_emacsclient_version(void)
72
-{
73
- struct strbuf buffer = STRBUF_INIT;
74
- struct child_process ec_process;
75
- const char *argv_ec[] = { "emacsclient", "--version", NULL };
76
- int version;
77
-
78
- /* emacsclient prints its version number on stderr */
79
- memset(&ec_process, 0, sizeof(ec_process));
80
- ec_process.argv = argv_ec;
81
- ec_process.err = -1;
82
- ec_process.stdout_to_stderr = 1;
83
- if (start_command(&ec_process)) {
84
- fprintf(stderr, "Failed to start emacsclient.\n");
85
- return -1;
86
- }
87
- strbuf_read(&buffer, ec_process.err, 20);
88
- close(ec_process.err);
89
-
90
- /*
91
- * Don't bother checking return value, because "emacsclient --version"
92
- * seems to always exits with code 1.
93
- */
94
- finish_command(&ec_process);
95
-
96
- if (prefixcmp(buffer.buf, "emacsclient")) {
97
- fprintf(stderr, "Failed to parse emacsclient version.\n");
98
- strbuf_release(&buffer);
99
- return -1;
100
- }
101
-
102
- strbuf_remove(&buffer, 0, strlen("emacsclient"));
103
- version = atoi(buffer.buf);
104
-
105
- if (version < 22) {
106
- fprintf(stderr,
107
- "emacsclient version '%d' too old (< 22).\n",
108
- version);
109
- strbuf_release(&buffer);
110
- return -1;
111
- }
112
-
113
- strbuf_release(&buffer);
114
- return 0;
115
-}
116
-
117
-static void exec_woman_emacs(const char* path, const char *page)
118
-{
119
- if (!check_emacsclient_version()) {
120
- /* This works only with emacsclient version >= 22. */
121
- struct strbuf man_page = STRBUF_INIT;
122
-
123
- if (!path)
124
- path = "emacsclient";
125
- strbuf_addf(&man_page, "(woman \"%s\")", page);
126
- execlp(path, "emacsclient", "-e", man_page.buf, NULL);
127
- warning("failed to exec '%s': %s", path, strerror(errno));
128
- }
129
-}
130
-
131
-static void exec_man_konqueror(const char* path, const char *page)
132
-{
133
- const char *display = getenv("DISPLAY");
134
- if (display && *display) {
135
- struct strbuf man_page = STRBUF_INIT;
136
- const char *filename = "kfmclient";
137
-
138
- /* It's simpler to launch konqueror using kfmclient. */
139
- if (path) {
140
- const char *file = strrchr(path, '/');
141
- if (file && !strcmp(file + 1, "konqueror")) {
142
- char *new = xstrdup(path);
143
- char *dest = strrchr(new, '/');
144
-
145
- /* strlen("konqueror") == strlen("kfmclient") */
146
- strcpy(dest + 1, "kfmclient");
147
- path = new;
148
- }
149
- if (file)
150
- filename = file;
151
- } else
152
- path = "kfmclient";
153
- strbuf_addf(&man_page, "man:%s(1)", page);
154
- execlp(path, filename, "newTab", man_page.buf, NULL);
155
- warning("failed to exec '%s': %s", path, strerror(errno));
156
- }
157
-}
158
-
159
-static void exec_man_man(const char* path, const char *page)
160
-{
161
- if (!path)
162
- path = "man";
163
- execlp(path, "man", page, NULL);
164
- warning("failed to exec '%s': %s", path, strerror(errno));
165
-}
166
-
167
-static void exec_man_cmd(const char *cmd, const char *page)
168
-{
169
- struct strbuf shell_cmd = STRBUF_INIT;
170
- strbuf_addf(&shell_cmd, "%s %s", cmd, page);
171
- execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL);
172
- warning("failed to exec '%s': %s", cmd, strerror(errno));
173
-}
174
-
175
-static void add_man_viewer(const char *name)
176
-{
177
- struct man_viewer_list **p = &man_viewer_list;
178
- size_t len = strlen(name);
179
-
180
- while (*p)
181
- p = &((*p)->next);
182
- *p = xcalloc(1, (sizeof(**p) + len + 1));
183
- strncpy((*p)->name, name, len);
184
-}
185
-
186
-static int supported_man_viewer(const char *name, size_t len)
187
-{
188
- return (!strncasecmp("man", name, len) ||
189
- !strncasecmp("woman", name, len) ||
190
- !strncasecmp("konqueror", name, len));
191
-}
192
-
193
-static void do_add_man_viewer_info(const char *name,
194
- size_t len,
195
- const char *value)
196
-{
197
- struct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1);
198
-
199
- strncpy(new->name, name, len);
200
- new->info = xstrdup(value);
201
- new->next = man_viewer_info_list;
202
- man_viewer_info_list = new;
203
-}
204
-
205
-static int add_man_viewer_path(const char *name,
206
- size_t len,
207
- const char *value)
208
-{
209
- if (supported_man_viewer(name, len))
210
- do_add_man_viewer_info(name, len, value);
211
- else
212
- warning("'%s': path for unsupported man viewer.\n"
213
- "Please consider using 'man.<tool>.cmd' instead.",
214
- name);
215
-
216
- return 0;
217
-}
218
-
219
-static int add_man_viewer_cmd(const char *name,
220
- size_t len,
221
- const char *value)
222
-{
223
- if (supported_man_viewer(name, len))
224
- warning("'%s': cmd for supported man viewer.\n"
225
- "Please consider using 'man.<tool>.path' instead.",
226
- name);
227
- else
228
- do_add_man_viewer_info(name, len, value);
229
-
230
- return 0;
231
-}
232
-
233
-static int add_man_viewer_info(const char *var, const char *value)
234
-{
235
- const char *name = var + 4;
236
- const char *subkey = strrchr(name, '.');
237
-
238
- if (!subkey)
239
- return error("Config with no key for man viewer: %s", name);
240
-
241
- if (!strcmp(subkey, ".path")) {
242
- if (!value)
243
- return config_error_nonbool(var);
244
- return add_man_viewer_path(name, subkey - name, value);
245
- }
246
- if (!strcmp(subkey, ".cmd")) {
247
- if (!value)
248
- return config_error_nonbool(var);
249
- return add_man_viewer_cmd(name, subkey - name, value);
250
- }
251
-
252
- warning("'%s': unsupported man viewer sub key.", subkey);
253
- return 0;
254
-}
255
-
256
-static int git_help_config(const char *var, const char *value, void *cb)
257
-{
258
- if (!strcmp(var, "help.format")) {
259
- if (!value)
260
- return config_error_nonbool(var);
261
- help_format = parse_help_format(value);
262
- return 0;
263
- }
264
- if (!strcmp(var, "man.viewer")) {
265
- if (!value)
266
- return config_error_nonbool(var);
267
- add_man_viewer(value);
268
- return 0;
269
- }
270
- if (!prefixcmp(var, "man."))
271
- return add_man_viewer_info(var, value);
272
-
273
- return git_default_config(var, value, cb);
274
-}
275
-
6
/* most GUI terminals set COLUMNS (although some don't export it) */
7
static int term_columns(void)
8
{
@@ -295,14 +25,6 @@ static int term_columns(void)
25
return 80;
26
}
27
298
-static inline void mput_char(char c, unsigned int num)
299
-{
300
- while(num--)
301
- putchar(c);
302
-}
303
-
304
-struct cmdnames main_cmds, other_cmds;
305
-
28
void add_cmdname(struct cmdnames *cmds, const char *name, int len)
29
{
30
struct cmdname *ent = xmalloc(sizeof(*ent) + len + 1);
@@ -526,23 +248,6 @@ void list_commands(const char *title, unsigned int longest,
248
}
249
}
250
529
-void list_common_cmds_help(void)
530
-{
531
- int i, longest = 0;
532
-
533
- for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
534
- if (longest < strlen(common_cmds[i].name))
535
- longest = strlen(common_cmds[i].name);
536
- }
537
-
538
- puts("The most commonly used git commands are:");
539
- for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
540
- printf(" %s ", common_cmds[i].name);
541
- mput_char(' ', longest - strlen(common_cmds[i].name));
542
- puts(common_cmds[i].help);
543
- }
544
-}
545
-
251
int is_in_cmdlist(struct cmdnames *c, const char *s)
252
{
253
int i;
@@ -552,128 +257,6 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)
257
return 0;
258
}
259
555
-static int is_git_command(const char *s)
556
-{
557
- return is_in_cmdlist(&main_cmds, s) ||
558
- is_in_cmdlist(&other_cmds, s);
559
-}
560
-
561
-static const char *prepend(const char *prefix, const char *cmd)
562
-{
563
- size_t pre_len = strlen(prefix);
564
- size_t cmd_len = strlen(cmd);
565
- char *p = xmalloc(pre_len + cmd_len + 1);
566
- memcpy(p, prefix, pre_len);
567
- strcpy(p + pre_len, cmd);
568
- return p;
569
-}
570
-
571
-static const char *cmd_to_page(const char *git_cmd)
572
-{
573
- if (!git_cmd)
574
- return "git";
575
- else if (!prefixcmp(git_cmd, "git"))
576
- return git_cmd;
577
- else if (is_git_command(git_cmd))
578
- return prepend("git-", git_cmd);
579
- else
580
- return prepend("git", git_cmd);
581
-}
582
-
583
-static void setup_man_path(void)
584
-{
585
- struct strbuf new_path;
586
- const char *old_path = getenv("MANPATH");
587
-
588
- strbuf_init(&new_path, 0);
589
-
590
- /* We should always put ':' after our path. If there is no
591
- * old_path, the ':' at the end will let 'man' to try
592
- * system-wide paths after ours to find the manual page. If
593
- * there is old_path, we need ':' as delimiter. */
594
- strbuf_addstr(&new_path, GIT_MAN_PATH);
595
- strbuf_addch(&new_path, ':');
596
- if (old_path)
597
- strbuf_addstr(&new_path, old_path);
598
-
599
- setenv("MANPATH", new_path.buf, 1);
600
-
601
- strbuf_release(&new_path);
602
-}
603
-
604
-static void exec_viewer(const char *name, const char *page)
605
-{
606
- const char *info = get_man_viewer_info(name);
607
-
608
- if (!strcasecmp(name, "man"))
609
- exec_man_man(info, page);
610
- else if (!strcasecmp(name, "woman"))
611
- exec_woman_emacs(info, page);
612
- else if (!strcasecmp(name, "konqueror"))
613
- exec_man_konqueror(info, page);
614
- else if (info)
615
- exec_man_cmd(info, page);
616
- else
617
- warning("'%s': unknown man viewer.", name);
618
-}
619
-
620
-static void show_man_page(const char *git_cmd)
621
-{
622
- struct man_viewer_list *viewer;
623
- const char *page = cmd_to_page(git_cmd);
624
-
625
- setup_man_path();
626
- for (viewer = man_viewer_list; viewer; viewer = viewer->next)
627
- {
628
- exec_viewer(viewer->name, page); /* will return when unable */
629
- }
630
- exec_viewer("man", page);
631
- die("no man viewer handled the request");
632
-}
633
-
634
-static void show_info_page(const char *git_cmd)
635
-{
636
- const char *page = cmd_to_page(git_cmd);
637
- setenv("INFOPATH", GIT_INFO_PATH, 1);
638
- execlp("info", "info", "gitman", page, NULL);
639
-}
640
-
641
-static void get_html_page_path(struct strbuf *page_path, const char *page)
642
-{
643
- struct stat st;
644
- const char *html_path = system_path(GIT_HTML_PATH);
645
-
646
- /* Check that we have a git documentation directory. */
647
- if (stat(mkpath("%s/git.html", html_path), &st)
648
- || !S_ISREG(st.st_mode))
649
- die("'%s': not a documentation directory.", html_path);
650
-
651
- strbuf_init(page_path, 0);
652
- strbuf_addf(page_path, "%s/%s.html", html_path, page);
653
-}
654
-
655
-/*
656
- * If open_html is not defined in a platform-specific way (see for
657
- * example compat/mingw.h), we use the script web--browse to display
658
- * HTML.
659
- */
660
-#ifndef open_html
661
-void open_html(const char *path)
662
-{
663
- execl_git_cmd("web--browse", "-c", "help.browser", path, NULL);
664
-}
665
-#endif
666
-
667
-static void show_html_page(const char *git_cmd)
668
-{
669
- const char *page = cmd_to_page(git_cmd);
670
- struct strbuf page_path; /* it leaks but we exec bellow */
671
-
672
- get_html_page_path(&page_path, page);
673
-
674
- open_html(page_path.buf);
675
-}
676
-
260
void help_unknown_cmd(const char *cmd)
261
{
262
fprintf(stderr, "git: '%s' is not a git-command. See 'git --help'.\n", cmd);
@@ -685,50 +268,3 @@ int cmd_version(int argc, const char **argv, const char *prefix)
268
printf("git version %s\n", git_version_string);
269
return 0;
270
}
688
-
689
-int cmd_help(int argc, const char **argv, const char *prefix)
690
-{
691
- int nongit;
692
- const char *alias;
693
- unsigned int longest = load_command_list("git-", &main_cmds, &other_cmds);
694
-
695
- setup_git_directory_gently(&nongit);
696
- git_config(git_help_config, NULL);
697
-
698
- argc = parse_options(argc, argv, builtin_help_options,
699
- builtin_help_usage, 0);
700
-
701
- if (show_all) {
702
- printf("usage: %s\n\n", git_usage_string);
703
- list_commands("git commands", longest, &main_cmds, &other_cmds);
704
- printf("%s\n", git_more_info_string);
705
- return 0;
706
- }
707
-
708
- if (!argv[0]) {
709
- printf("usage: %s\n\n", git_usage_string);
710
- list_common_cmds_help();
711
- printf("\n%s\n", git_more_info_string);
712
- return 0;
713
- }
714
-
715
- alias = alias_lookup(argv[0]);
716
- if (alias && !is_git_command(argv[0])) {
717
- printf("`git %s' is aliased to `%s'\n", argv[0], alias);
718
- return 0;
719
- }
720
-
721
- switch (help_format) {
722
- case HELP_FORMAT_MAN:
723
- show_man_page(argv[0]);
724
- break;
725
- case HELP_FORMAT_INFO:
726
- show_info_page(argv[0]);
727
- break;
728
- case HELP_FORMAT_WEB:
729
- show_html_page(argv[0]);
730
- break;
731
- }
732
-
733
- return 0;
734
-}
help.h
+6
@@ -10,6 +10,12 @@ struct cmdnames {
10
} **names;
11
};
12
13
+static inline void mput_char(char c, unsigned int num)
14
+{
15
+ while(num--)
16
+ putchar(c);
17
+}
18
+
19
unsigned int load_command_list(const char *prefix,
20
struct cmdnames *main_cmds,
21
struct cmdnames *other_cmds);