Annotation of mandoc/manpath.c, Revision 1.25
1.25 ! schwarze 1: /* $Id: manpath.c,v 1.24 2015/04/28 16:13:45 schwarze Exp $ */
1.1 kristaps 2: /*
1.20 schwarze 3: * Copyright (c) 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
1.1 kristaps 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: *
1.22 schwarze 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1.1 kristaps 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1.22 schwarze 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1.1 kristaps 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: #include "config.h"
1.16 schwarze 19:
20: #include <sys/types.h>
1.18 schwarze 21: #include <sys/stat.h>
1.1 kristaps 22:
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.23 schwarze 30: #include "manconf.h"
1.1 kristaps 31:
1.23 schwarze 32: static void manconf_file(struct manconf *, const char *);
1.18 schwarze 33: static void manpath_add(struct manpaths *, const char *, int);
34: static void manpath_parseline(struct manpaths *, char *, int);
1.1 kristaps 35:
1.23 schwarze 36:
1.1 kristaps 37: void
1.23 schwarze 38: manconf_parse(struct manconf *conf, const char *file,
1.5 schwarze 39: char *defp, char *auxp)
1.1 kristaps 40: {
1.17 schwarze 41: #if HAVE_MANPATH
1.11 schwarze 42: char cmd[(PATH_MAX * 3) + 20];
1.6 kristaps 43: FILE *stream;
44: char *buf;
45: size_t sz, bsz;
46:
47: strlcpy(cmd, "manpath", sizeof(cmd));
48: if (file) {
49: strlcat(cmd, " -C ", sizeof(cmd));
50: strlcat(cmd, file, sizeof(cmd));
51: }
52: if (auxp) {
53: strlcat(cmd, " -m ", sizeof(cmd));
54: strlcat(cmd, auxp, sizeof(cmd));
55: }
56: if (defp) {
57: strlcat(cmd, " -M ", sizeof(cmd));
58: strlcat(cmd, defp, sizeof(cmd));
59: }
60:
61: /* Open manpath(1). Ignore errors. */
62:
63: stream = popen(cmd, "r");
64: if (NULL == stream)
65: return;
66:
67: buf = NULL;
68: bsz = 0;
69:
70: /* Read in as much output as we can. */
71:
72: do {
73: buf = mandoc_realloc(buf, bsz + 1024);
1.9 kristaps 74: sz = fread(buf + bsz, 1, 1024, stream);
1.6 kristaps 75: bsz += sz;
76: } while (sz > 0);
77:
78: if ( ! ferror(stream) && feof(stream) &&
79: bsz && '\n' == buf[bsz - 1]) {
80: buf[bsz - 1] = '\0';
1.24 schwarze 81: manpath_parseline(&conf->manpath, buf, 1);
1.6 kristaps 82: }
1.1 kristaps 83:
1.6 kristaps 84: free(buf);
85: pclose(stream);
86: #else
1.8 kristaps 87: char *insert;
1.4 schwarze 88:
1.8 kristaps 89: /* Always prepend -m. */
1.23 schwarze 90: manpath_parseline(&conf->manpath, auxp, 1);
1.10 schwarze 91:
1.8 kristaps 92: /* If -M is given, it overrides everything else. */
93: if (NULL != defp) {
1.23 schwarze 94: manpath_parseline(&conf->manpath, defp, 1);
1.8 kristaps 95: return;
96: }
1.1 kristaps 97:
1.8 kristaps 98: /* MANPATH and man.conf(5) cooperate. */
99: defp = getenv("MANPATH");
100: if (NULL == file)
101: file = MAN_CONF_FILE;
102:
103: /* No MANPATH; use man.conf(5) only. */
104: if (NULL == defp || '\0' == defp[0]) {
1.23 schwarze 105: manconf_file(conf, file);
1.8 kristaps 106: return;
107: }
108:
109: /* Prepend man.conf(5) to MANPATH. */
110: if (':' == defp[0]) {
1.23 schwarze 111: manconf_file(conf, file);
112: manpath_parseline(&conf->manpath, defp, 0);
1.8 kristaps 113: return;
114: }
115:
116: /* Append man.conf(5) to MANPATH. */
1.9 kristaps 117: if (':' == defp[strlen(defp) - 1]) {
1.23 schwarze 118: manpath_parseline(&conf->manpath, defp, 0);
119: manconf_file(conf, file);
1.8 kristaps 120: return;
121: }
122:
123: /* Insert man.conf(5) into MANPATH. */
124: insert = strstr(defp, "::");
125: if (NULL != insert) {
126: *insert++ = '\0';
1.23 schwarze 127: manpath_parseline(&conf->manpath, defp, 0);
128: manconf_file(conf, file);
129: manpath_parseline(&conf->manpath, insert + 1, 0);
1.8 kristaps 130: return;
131: }
132:
133: /* MANPATH overrides man.conf(5) completely. */
1.23 schwarze 134: manpath_parseline(&conf->manpath, defp, 0);
1.6 kristaps 135: #endif
1.1 kristaps 136: }
137:
138: /*
139: * Parse a FULL pathname from a colon-separated list of arrays.
140: */
1.6 kristaps 141: static void
1.18 schwarze 142: manpath_parseline(struct manpaths *dirs, char *path, int complain)
1.1 kristaps 143: {
144: char *dir;
145:
146: if (NULL == path)
147: return;
148:
149: for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
1.18 schwarze 150: manpath_add(dirs, dir, complain);
1.1 kristaps 151: }
152:
153: /*
154: * Add a directory to the array, ignoring bad directories.
155: * Grow the array one-by-one for simplicity's sake.
156: */
157: static void
1.18 schwarze 158: manpath_add(struct manpaths *dirs, const char *dir, int complain)
1.1 kristaps 159: {
160: char buf[PATH_MAX];
1.18 schwarze 161: struct stat sb;
1.1 kristaps 162: char *cp;
1.9 kristaps 163: size_t i;
1.1 kristaps 164:
1.18 schwarze 165: if (NULL == (cp = realpath(dir, buf))) {
166: if (complain) {
167: fputs("manpath: ", stderr);
168: perror(dir);
169: }
1.1 kristaps 170: return;
1.18 schwarze 171: }
1.1 kristaps 172:
173: for (i = 0; i < dirs->sz; i++)
174: if (0 == strcmp(dirs->paths[i], dir))
175: return;
176:
1.18 schwarze 177: if (stat(cp, &sb) == -1) {
178: if (complain) {
179: fputs("manpath: ", stderr);
180: perror(dir);
181: }
182: return;
183: }
184:
1.15 schwarze 185: dirs->paths = mandoc_reallocarray(dirs->paths,
186: dirs->sz + 1, sizeof(char *));
1.1 kristaps 187:
188: dirs->paths[dirs->sz++] = mandoc_strdup(cp);
1.2 kristaps 189: }
190:
191: void
1.23 schwarze 192: manconf_free(struct manconf *conf)
1.2 kristaps 193: {
1.9 kristaps 194: size_t i;
1.2 kristaps 195:
1.23 schwarze 196: for (i = 0; i < conf->manpath.sz; i++)
197: free(conf->manpath.paths[i]);
1.2 kristaps 198:
1.23 schwarze 199: free(conf->manpath.paths);
200: free(conf->output.includes);
201: free(conf->output.man);
202: free(conf->output.paper);
203: free(conf->output.style);
1.2 kristaps 204: }
205:
1.23 schwarze 206: static void
207: manconf_file(struct manconf *conf, const char *file)
1.2 kristaps 208: {
1.23 schwarze 209: const char *const toks[] = { "manpath", "output", "_whatdb" };
1.25 ! schwarze 210: char manpath_default[] = MANPATH_DEFAULT;
1.22 schwarze 211:
1.2 kristaps 212: FILE *stream;
1.22 schwarze 213: char *cp, *ep;
214: size_t len, tok;
1.1 kristaps 215:
1.22 schwarze 216: if ((stream = fopen(file, "r")) == NULL)
1.25 ! schwarze 217: goto out;
1.1 kristaps 218:
1.22 schwarze 219: while ((cp = fgetln(stream, &len)) != NULL) {
220: ep = cp + len;
221: if (ep[-1] != '\n')
1.1 kristaps 222: break;
1.22 schwarze 223: *--ep = '\0';
224: while (isspace((unsigned char)*cp))
225: cp++;
226: if (*cp == '#')
1.1 kristaps 227: continue;
1.22 schwarze 228:
229: for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
230: len = strlen(toks[tok]);
231: if (cp + len < ep &&
232: isspace((unsigned char)cp[len]) &&
233: !strncmp(cp, toks[tok], len)) {
234: cp += len;
235: while (isspace((unsigned char)*cp))
236: cp++;
237: break;
238: }
239: }
240:
241: switch (tok) {
1.23 schwarze 242: case 2: /* _whatdb */
1.22 schwarze 243: while (ep > cp && ep[-1] != '/')
244: ep--;
245: if (ep == cp)
246: continue;
247: *ep = '\0';
248: /* FALLTHROUGH */
249: case 0: /* manpath */
1.23 schwarze 250: manpath_add(&conf->manpath, cp, 0);
1.25 ! schwarze 251: *manpath_default = '\0';
1.23 schwarze 252: break;
253: case 1: /* output */
254: manconf_output(&conf->output, cp);
1.22 schwarze 255: break;
256: default:
257: break;
258: }
1.1 kristaps 259: }
1.25 ! schwarze 260: fclose(stream);
1.1 kristaps 261:
1.25 ! schwarze 262: out:
! 263: if (*manpath_default != '\0')
! 264: manpath_parseline(&conf->manpath, manpath_default, 0);
1.23 schwarze 265: }
266:
267: void
268: manconf_output(struct manoutput *conf, const char *cp)
269: {
270: const char *const toks[] = {
271: "includes", "man", "paper", "style",
272: "indent", "width", "fragment", "mdoc"
273: };
274:
275: size_t len, tok;
276:
277: for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
278: len = strlen(toks[tok]);
279: if ( ! strncmp(cp, toks[tok], len) &&
280: strchr(" = ", cp[len]) != NULL) {
281: cp += len;
282: if (*cp == '=')
283: cp++;
284: while (isspace((unsigned char)*cp))
285: cp++;
286: break;
287: }
288: }
289:
290: if (tok < 6 && *cp == '\0')
291: return;
292:
293: switch (tok) {
294: case 0:
295: if (conf->includes == NULL)
296: conf->includes = mandoc_strdup(cp);
297: break;
298: case 1:
299: if (conf->man == NULL)
300: conf->man = mandoc_strdup(cp);
301: break;
302: case 2:
303: if (conf->paper == NULL)
304: conf->paper = mandoc_strdup(cp);
305: break;
306: case 3:
307: if (conf->style == NULL)
308: conf->style = mandoc_strdup(cp);
309: break;
310: case 4:
311: if (conf->indent == 0)
312: conf->indent = strtonum(cp, 0, 1000, NULL);
313: break;
314: case 5:
315: if (conf->width == 0)
316: conf->width = strtonum(cp, 58, 1000, NULL);
317: break;
318: case 6:
319: conf->fragment = 1;
320: break;
321: case 7:
322: conf->mdoc = 1;
323: break;
324: default:
325: break;
326: }
1.1 kristaps 327: }
CVSweb