@matheusbsbs / matheus-bagliano / commits / 3d78d1f18f
Fork 0

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);