File: help.c

package info (click to toggle)
ndctl 82-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,460 kB
  • sloc: ansic: 42,027; sh: 3,974; makefile: 28
file content (147 lines) | stat: -rw-r--r-- 3,592 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2015-2020 Intel Corporation. All rights reserved.
// Copyright (C) 2008 Miklos Vajna. All rights reserved.
// Copyright (C) 2006 Linus Torvalds. All rights reserved.

/* originally copied from perf and git */

/*
 * builtin-help.c
 *
 * Builtin help command
 */
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <ndctl/builtin.h>
#include <util/strbuf.h>
#include <util/parse-options.h>

#define pr_err(x, ...) fprintf(stderr, x, ##__VA_ARGS__)
#define STRERR_BUFSIZE  128     /* For the buffer size of strerror_r */

static void exec_man_konqueror(const char *path, const char *page)
{
	const char *display = getenv("DISPLAY");

	if (display && *display) {
		struct strbuf man_page = STRBUF_INIT;
		const char *filename = "kfmclient";
		char sbuf[STRERR_BUFSIZE];

		/* It's simpler to launch konqueror using kfmclient. */
		if (path) {
			const char *file = strrchr(path, '/');
			if (file && !strcmp(file + 1, "konqueror")) {
				char *dest;
				char *new = strdup(path);
				if (!new) {
					pr_err("strdup(path) failed.\n");
					exit(1);
				}

				dest = strrchr(new, '/');

				/* strlen("konqueror") == strlen("kfmclient") */
				strcpy(dest + 1, "kfmclient");
				path = new;
			}
			if (file)
				filename = file;
		} else
			path = "kfmclient";
		strbuf_addf(&man_page, "man:%s(1)", page);
		execlp(path, filename, "newTab", man_page.buf, NULL);
		warning("failed to exec '%s': %s", path,
			strerror_r(errno, sbuf, sizeof(sbuf)));
	}
}

static void exec_man_man(const char *path, const char *page)
{
	char sbuf[STRERR_BUFSIZE];

	if (!path)
		path = "man";
	execlp(path, "man", page, NULL);
	warning("failed to exec '%s': %s", path,
		strerror_r(errno, sbuf, sizeof(sbuf)));
}

static char *cmd_to_page(const char *cmd, char **page, const char *util_name)
{
	int rc;

	if (!cmd)
		rc = asprintf(page, "%s", util_name);
	else if (!prefixcmp(cmd, util_name))
		rc = asprintf(page, "%s", cmd);
	else
		rc = asprintf(page, "%s-%s", util_name, cmd);

	if (rc < 0)
		return NULL;
	return *page;
}

static const char *system_path(const char *path)
{
        static const char *prefix = PREFIX;
        struct strbuf d = STRBUF_INIT;

        if (is_absolute_path(path))
                return path;

        strbuf_addf(&d, "%s/%s", prefix, path);
        path = strbuf_detach(&d, NULL);
        return path;
}

static void setup_man_path(void)
{
	struct strbuf new_path = STRBUF_INIT;
	const char *old_path = getenv("MANPATH");

	/* We should always put ':' after our path. If there is no
	 * old_path, the ':' at the end will let 'man' to try
	 * system-wide paths after ours to find the manual page. If
	 * there is old_path, we need ':' as delimiter. */
	strbuf_addstr(&new_path, system_path(NDCTL_MAN_PATH));
	strbuf_addch(&new_path, ':');
	if (old_path)
		strbuf_addstr(&new_path, old_path);

	setenv("MANPATH", new_path.buf, 1);

	strbuf_release(&new_path);
}

static void exec_viewer(const char *name, const char *page)
{
	if (!strcasecmp(name, "man"))
		exec_man_man(NULL, page);
	else if (!strcasecmp(name, "konqueror"))
		exec_man_konqueror(NULL, page);
	else
		warning("'%s': unknown man viewer.", name);
}

int help_show_man_page(const char *cmd, const char *util_name,
		const char *viewer)
{
	const char *fallback = getenv(viewer);
	char *page;

	page = cmd_to_page(cmd, &page, util_name);
	if (!page)
		return -1;
	setup_man_path();
	if (fallback)
		exec_viewer(fallback, page);
	exec_viewer("man", page);

	pr_err("no man viewer handled the request");
	free(page);
	return -1;
}