Annotation of mandoc/manpath.c, Revision 1.14
1.14 ! schwarze 1: /* $Id: manpath.c,v 1.13 2014/03/23 11:25:26 schwarze Exp $ */
1.1 kristaps 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 <assert.h>
23: #include <ctype.h>
24: #include <limits.h>
25: #include <stdio.h>
26: #include <stdlib.h>
27: #include <string.h>
28:
1.13 schwarze 29: #include "mandoc_aux.h"
1.1 kristaps 30: #include "manpath.h"
31:
32: #define MAN_CONF_FILE "/etc/man.conf"
33: #define MAN_CONF_KEY "_whatdb"
34:
35: static void manpath_add(struct manpaths *, const char *);
1.6 kristaps 36: static void manpath_parseline(struct manpaths *, char *);
1.1 kristaps 37:
38: void
1.5 schwarze 39: manpath_parse(struct manpaths *dirs, const char *file,
40: char *defp, char *auxp)
1.1 kristaps 41: {
1.6 kristaps 42: #ifdef USE_MANPATH
1.11 schwarze 43: char cmd[(PATH_MAX * 3) + 20];
1.6 kristaps 44: FILE *stream;
45: char *buf;
46: size_t sz, bsz;
47:
48: strlcpy(cmd, "manpath", sizeof(cmd));
49: if (file) {
50: strlcat(cmd, " -C ", sizeof(cmd));
51: strlcat(cmd, file, sizeof(cmd));
52: }
53: if (auxp) {
54: strlcat(cmd, " -m ", sizeof(cmd));
55: strlcat(cmd, auxp, sizeof(cmd));
56: }
57: if (defp) {
58: strlcat(cmd, " -M ", sizeof(cmd));
59: strlcat(cmd, defp, sizeof(cmd));
60: }
61:
62: /* Open manpath(1). Ignore errors. */
63:
64: stream = popen(cmd, "r");
65: if (NULL == stream)
66: return;
67:
68: buf = NULL;
69: bsz = 0;
70:
71: /* Read in as much output as we can. */
72:
73: do {
74: buf = mandoc_realloc(buf, bsz + 1024);
1.9 kristaps 75: sz = fread(buf + bsz, 1, 1024, stream);
1.6 kristaps 76: bsz += sz;
77: } while (sz > 0);
78:
79: if ( ! ferror(stream) && feof(stream) &&
80: bsz && '\n' == buf[bsz - 1]) {
81: buf[bsz - 1] = '\0';
82: manpath_parseline(dirs, buf);
83: }
1.1 kristaps 84:
1.6 kristaps 85: free(buf);
86: pclose(stream);
87: #else
1.8 kristaps 88: char *insert;
1.4 schwarze 89:
1.8 kristaps 90: /* Always prepend -m. */
1.10 schwarze 91: manpath_parseline(dirs, auxp);
92:
1.8 kristaps 93: /* If -M is given, it overrides everything else. */
94: if (NULL != defp) {
95: manpath_parseline(dirs, defp);
96: return;
97: }
1.1 kristaps 98:
1.8 kristaps 99: /* MANPATH and man.conf(5) cooperate. */
100: defp = getenv("MANPATH");
101: if (NULL == file)
102: file = MAN_CONF_FILE;
103:
104: /* No MANPATH; use man.conf(5) only. */
105: if (NULL == defp || '\0' == defp[0]) {
106: manpath_manconf(dirs, file);
107: return;
108: }
109:
110: /* Prepend man.conf(5) to MANPATH. */
111: if (':' == defp[0]) {
112: manpath_manconf(dirs, file);
1.1 kristaps 113: manpath_parseline(dirs, defp);
1.8 kristaps 114: return;
115: }
116:
117: /* Append man.conf(5) to MANPATH. */
1.9 kristaps 118: if (':' == defp[strlen(defp) - 1]) {
1.8 kristaps 119: manpath_parseline(dirs, defp);
120: manpath_manconf(dirs, file);
121: return;
122: }
123:
124: /* Insert man.conf(5) into MANPATH. */
125: insert = strstr(defp, "::");
126: if (NULL != insert) {
127: *insert++ = '\0';
128: manpath_parseline(dirs, defp);
129: manpath_manconf(dirs, file);
130: manpath_parseline(dirs, insert + 1);
131: return;
132: }
133:
134: /* MANPATH overrides man.conf(5) completely. */
135: manpath_parseline(dirs, defp);
1.6 kristaps 136: #endif
1.1 kristaps 137: }
138:
139: /*
140: * Parse a FULL pathname from a colon-separated list of arrays.
141: */
1.6 kristaps 142: static void
1.4 schwarze 143: manpath_parseline(struct manpaths *dirs, char *path)
1.1 kristaps 144: {
145: char *dir;
146:
147: if (NULL == path)
148: return;
149:
150: for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
151: manpath_add(dirs, dir);
152: }
153:
154: /*
155: * Add a directory to the array, ignoring bad directories.
156: * Grow the array one-by-one for simplicity's sake.
157: */
158: static void
1.4 schwarze 159: manpath_add(struct manpaths *dirs, const char *dir)
1.1 kristaps 160: {
161: char buf[PATH_MAX];
162: char *cp;
1.9 kristaps 163: size_t i;
1.1 kristaps 164:
165: if (NULL == (cp = realpath(dir, buf)))
166: return;
167:
168: for (i = 0; i < dirs->sz; i++)
169: if (0 == strcmp(dirs->paths[i], dir))
170: return;
171:
1.14 ! schwarze 172: dirs->paths = mandoc_realloc(dirs->paths,
! 173: (dirs->sz + 1) * sizeof(char *));
1.1 kristaps 174:
175: dirs->paths[dirs->sz++] = mandoc_strdup(cp);
1.2 kristaps 176: }
177:
178: void
179: manpath_free(struct manpaths *p)
180: {
1.9 kristaps 181: size_t i;
1.2 kristaps 182:
183: for (i = 0; i < p->sz; i++)
184: free(p->paths[i]);
185:
186: free(p->paths);
187: }
188:
189: void
1.5 schwarze 190: manpath_manconf(struct manpaths *dirs, const char *file)
1.2 kristaps 191: {
192: FILE *stream;
1.1 kristaps 193: char *p, *q;
1.4 schwarze 194: size_t len, keysz;
1.1 kristaps 195:
196: keysz = strlen(MAN_CONF_KEY);
197: assert(keysz > 0);
198:
1.3 kristaps 199: if (NULL == (stream = fopen(file, "r")))
1.1 kristaps 200: return;
201:
202: while (NULL != (p = fgetln(stream, &len))) {
203: if (0 == len || '\n' != p[--len])
204: break;
205: p[len] = '\0';
206: while (isspace((unsigned char)*p))
207: p++;
208: if (strncmp(MAN_CONF_KEY, p, keysz))
209: continue;
210: p += keysz;
1.12 schwarze 211: while (isspace((unsigned char)*p))
1.1 kristaps 212: p++;
213: if ('\0' == *p)
214: continue;
215: if (NULL == (q = strrchr(p, '/')))
216: continue;
217: *q = '\0';
218: manpath_add(dirs, p);
219: }
220:
221: fclose(stream);
222: }
CVSweb