]> git.cameronkatri.com Git - mandoc.git/blob - manpath.c
If no man.cgi `whatis' results are found, offer a quick link to the apropos
[mandoc.git] / manpath.c
1 /* $Id: manpath.c,v 1.4 2011/11/26 22:38:11 schwarze Exp $ */
2 /*
3 * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
4 * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
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 <sys/types.h>
23 #include <assert.h>
24 #include <ctype.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "mandoc.h"
31 #include "manpath.h"
32
33 #define MAN_CONF_FILE "/etc/man.conf"
34 #define MAN_CONF_KEY "_whatdb"
35
36 static void manpath_add(struct manpaths *, const char *);
37
38 void
39 manpath_parse(struct manpaths *dirs, char *defp, char *auxp)
40 {
41
42 manpath_parseline(dirs, auxp);
43
44 if (NULL == defp)
45 defp = getenv("MANPATH");
46
47 if (NULL == defp)
48 manpath_parseconf(dirs);
49 else
50 manpath_parseline(dirs, defp);
51 }
52
53 /*
54 * Parse a FULL pathname from a colon-separated list of arrays.
55 */
56 void
57 manpath_parseline(struct manpaths *dirs, char *path)
58 {
59 char *dir;
60
61 if (NULL == path)
62 return;
63
64 for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
65 manpath_add(dirs, dir);
66 }
67
68 /*
69 * Add a directory to the array, ignoring bad directories.
70 * Grow the array one-by-one for simplicity's sake.
71 */
72 static void
73 manpath_add(struct manpaths *dirs, const char *dir)
74 {
75 char buf[PATH_MAX];
76 char *cp;
77 int i;
78
79 if (NULL == (cp = realpath(dir, buf)))
80 return;
81
82 for (i = 0; i < dirs->sz; i++)
83 if (0 == strcmp(dirs->paths[i], dir))
84 return;
85
86 dirs->paths = mandoc_realloc
87 (dirs->paths,
88 ((size_t)dirs->sz + 1) * sizeof(char *));
89
90 dirs->paths[dirs->sz++] = mandoc_strdup(cp);
91 }
92
93 void
94 manpath_parseconf(struct manpaths *dirs)
95 {
96 #ifdef USE_MANPATH
97 FILE *stream;
98 char *buf;
99 size_t sz, bsz;
100
101 /* Open manpath(1). Ignore errors. */
102
103 stream = popen("manpath", "r");
104 if (NULL == stream)
105 return;
106
107 buf = NULL;
108 bsz = 0;
109
110 /* Read in as much output as we can. */
111
112 do {
113 buf = mandoc_realloc(buf, bsz + 1024);
114 sz = fread(buf + (int)bsz, 1, 1024, stream);
115 bsz += sz;
116 } while (sz > 0);
117
118 if ( ! ferror(stream) && feof(stream) &&
119 bsz && '\n' == buf[bsz - 1]) {
120 buf[bsz - 1] = '\0';
121 manpath_parseline(dirs, buf);
122 }
123
124 free(buf);
125 pclose(stream);
126 #else
127 manpath_manconf(MAN_CONF_FILE, dirs);
128 #endif
129 }
130
131 void
132 manpath_free(struct manpaths *p)
133 {
134 int i;
135
136 for (i = 0; i < p->sz; i++)
137 free(p->paths[i]);
138
139 free(p->paths);
140 }
141
142 void
143 manpath_manconf(const char *file, struct manpaths *dirs)
144 {
145 FILE *stream;
146 char *p, *q;
147 size_t len, keysz;
148
149 keysz = strlen(MAN_CONF_KEY);
150 assert(keysz > 0);
151
152 if (NULL == (stream = fopen(file, "r")))
153 return;
154
155 while (NULL != (p = fgetln(stream, &len))) {
156 if (0 == len || '\n' != p[--len])
157 break;
158 p[len] = '\0';
159 while (isspace((unsigned char)*p))
160 p++;
161 if (strncmp(MAN_CONF_KEY, p, keysz))
162 continue;
163 p += keysz;
164 while (isspace(*p))
165 p++;
166 if ('\0' == *p)
167 continue;
168 if (NULL == (q = strrchr(p, '/')))
169 continue;
170 *q = '\0';
171 manpath_add(dirs, p);
172 }
173
174 fclose(stream);
175 }