xref: /minix3/external/bsd/mdocml/dist/manpage.c (revision bdb565187c0f1a04513dd488df843317b27f86c8)
1 /*	Id: manpage.c,v 1.6 2013/12/31 03:41:14 schwarze Exp  */
2 /*
3  * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 
22 #include <assert.h>
23 #include <getopt.h>
24 #include <limits.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #include "manpath.h"
32 #include "mansearch.h"
33 
34 static	void	 show(const char *, const char *);
35 
36 int
37 main(int argc, char *argv[])
38 {
39 	int		 ch, term;
40 	size_t		 i, sz, len;
41 	struct mansearch search;
42 	struct manpage	*res;
43 	char		*conf_file, *defpaths, *auxpaths, *cp;
44 	char		 buf[PATH_MAX];
45 	const char	*cmd;
46 	struct manpaths	 paths;
47 	char		*progname;
48 	extern char	*optarg;
49 	extern int	 optind;
50 
51 	term = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
52 
53 	progname = strrchr(argv[0], '/');
54 	if (progname == NULL)
55 		progname = argv[0];
56 	else
57 		++progname;
58 
59 	auxpaths = defpaths = conf_file = NULL;
60 	memset(&paths, 0, sizeof(struct manpaths));
61 	memset(&search, 0, sizeof(struct mansearch));
62 
63 	while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
64 		switch (ch) {
65 		case ('C'):
66 			conf_file = optarg;
67 			break;
68 		case ('M'):
69 			defpaths = optarg;
70 			break;
71 		case ('m'):
72 			auxpaths = optarg;
73 			break;
74 		case ('S'):
75 			search.arch = optarg;
76 			break;
77 		case ('s'):
78 			search.sec = optarg;
79 			break;
80 		default:
81 			goto usage;
82 		}
83 
84 	argc -= optind;
85 	argv += optind;
86 
87 	if (0 == argc)
88 		goto usage;
89 
90 	search.deftype = TYPE_Nm | TYPE_Nd;
91 
92 	manpath_parse(&paths, conf_file, defpaths, auxpaths);
93 	ch = mansearch(&search, &paths, argc, argv, NULL, &res, &sz);
94 	manpath_free(&paths);
95 
96 	if (0 == ch)
97 		goto usage;
98 
99 	if (0 == sz) {
100 		free(res);
101 		return(EXIT_FAILURE);
102 	} else if (1 == sz && term) {
103 		i = 1;
104 		goto show;
105 	} else if (NULL == res)
106 		return(EXIT_FAILURE);
107 
108 	for (i = 0; i < sz; i++) {
109 		printf("%6zu  %s: %s\n",
110 			i + 1, res[i].names, res[i].desc);
111 		free(res[i].names);
112 		free(res[i].desc);
113 		free(res[i].output);
114 	}
115 
116 	if (0 == term) {
117 		for (i = 0; i < sz; i++)
118 			free(res[i].file);
119 		free(res);
120 		return(EXIT_SUCCESS);
121 	}
122 
123 	i = 1;
124 	printf("Enter a choice [1]: ");
125 	fflush(stdout);
126 
127 	if (NULL != (cp = fgetln(stdin, &len)))
128 		if ('\n' == cp[--len] && len > 0) {
129 			cp[len] = '\0';
130 			if ((i = atoi(cp)) < 1 || i > sz)
131 				i = 0;
132 		}
133 
134 	if (0 == i) {
135 		for (i = 0; i < sz; i++)
136 			free(res[i].file);
137 		free(res);
138 		return(EXIT_SUCCESS);
139 	}
140 show:
141 	cmd = res[i - 1].form ? "mandoc" : "cat";
142 	strlcpy(buf, res[i - 1].file, PATH_MAX);
143 	for (i = 0; i < sz; i++)
144 		free(res[i].file);
145 	free(res);
146 
147 	show(cmd, buf);
148 	/* NOTREACHED */
149 usage:
150 	fprintf(stderr, "usage: %s [-C conf] "
151 			 	  "[-M paths] "
152 				  "[-m paths] "
153 				  "[-S arch] "
154 				  "[-s section] "
155 			          "expr ...\n",
156 				  progname);
157 	return(EXIT_FAILURE);
158 }
159 
160 static void
161 show(const char *cmd, const char *file)
162 {
163 	int		 fds[2];
164 	pid_t		 pid;
165 
166 	if (-1 == pipe(fds)) {
167 		perror(NULL);
168 		exit(EXIT_FAILURE);
169 	}
170 
171 	if (-1 == (pid = fork())) {
172 		perror(NULL);
173 		exit(EXIT_FAILURE);
174 	} else if (pid > 0) {
175 		dup2(fds[0], STDIN_FILENO);
176 		close(fds[1]);
177 		cmd = NULL != getenv("MANPAGER") ?
178 			getenv("MANPAGER") :
179 			(NULL != getenv("PAGER") ?
180 			 getenv("PAGER") : "more");
181 		execlp(cmd, cmd, (char *)NULL);
182 		perror(cmd);
183 		exit(EXIT_FAILURE);
184 	}
185 
186 	dup2(fds[1], STDOUT_FILENO);
187 	close(fds[0]);
188 	execlp(cmd, cmd, file, (char *)NULL);
189 	perror(cmd);
190 	exit(EXIT_FAILURE);
191 }
192