Annotation of mandoc/manpath.c, Revision 1.30.2.1
1.30.2.1! schwarze 1: /* $Id: manpath.c,v 1.30 2016/05/28 13:44:13 schwarze Exp $ */
1.1 kristaps 2: /*
1.30.2.1! schwarze 3: * Copyright (c) 2011, 2014, 2015, 2017 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>
1.28 schwarze 24: #if HAVE_ERR
1.27 schwarze 25: #include <err.h>
1.28 schwarze 26: #endif
1.1 kristaps 27: #include <limits.h>
28: #include <stdio.h>
29: #include <stdlib.h>
30: #include <string.h>
31:
1.13 schwarze 32: #include "mandoc_aux.h"
1.23 schwarze 33: #include "manconf.h"
1.1 kristaps 34:
1.26 schwarze 35: #if !HAVE_MANPATH
1.23 schwarze 36: static void manconf_file(struct manconf *, const char *);
1.26 schwarze 37: #endif
1.18 schwarze 38: static void manpath_add(struct manpaths *, const char *, int);
39: static void manpath_parseline(struct manpaths *, char *, int);
1.1 kristaps 40:
1.23 schwarze 41:
1.1 kristaps 42: void
1.23 schwarze 43: manconf_parse(struct manconf *conf, const char *file,
1.5 schwarze 44: char *defp, char *auxp)
1.1 kristaps 45: {
1.17 schwarze 46: #if HAVE_MANPATH
1.11 schwarze 47: char cmd[(PATH_MAX * 3) + 20];
1.6 kristaps 48: FILE *stream;
49: char *buf;
50: size_t sz, bsz;
51:
52: strlcpy(cmd, "manpath", sizeof(cmd));
53: if (file) {
54: strlcat(cmd, " -C ", sizeof(cmd));
55: strlcat(cmd, file, sizeof(cmd));
56: }
57: if (auxp) {
58: strlcat(cmd, " -m ", sizeof(cmd));
59: strlcat(cmd, auxp, sizeof(cmd));
60: }
61: if (defp) {
62: strlcat(cmd, " -M ", sizeof(cmd));
63: strlcat(cmd, defp, sizeof(cmd));
64: }
65:
66: /* Open manpath(1). Ignore errors. */
67:
68: stream = popen(cmd, "r");
69: if (NULL == stream)
70: return;
71:
72: buf = NULL;
73: bsz = 0;
74:
75: /* Read in as much output as we can. */
76:
77: do {
78: buf = mandoc_realloc(buf, bsz + 1024);
1.9 kristaps 79: sz = fread(buf + bsz, 1, 1024, stream);
1.6 kristaps 80: bsz += sz;
81: } while (sz > 0);
82:
83: if ( ! ferror(stream) && feof(stream) &&
84: bsz && '\n' == buf[bsz - 1]) {
85: buf[bsz - 1] = '\0';
1.24 schwarze 86: manpath_parseline(&conf->manpath, buf, 1);
1.6 kristaps 87: }
1.1 kristaps 88:
1.6 kristaps 89: free(buf);
90: pclose(stream);
91: #else
1.8 kristaps 92: char *insert;
1.4 schwarze 93:
1.8 kristaps 94: /* Always prepend -m. */
1.23 schwarze 95: manpath_parseline(&conf->manpath, auxp, 1);
1.10 schwarze 96:
1.8 kristaps 97: /* If -M is given, it overrides everything else. */
98: if (NULL != defp) {
1.23 schwarze 99: manpath_parseline(&conf->manpath, defp, 1);
1.8 kristaps 100: return;
101: }
1.1 kristaps 102:
1.8 kristaps 103: /* MANPATH and man.conf(5) cooperate. */
104: defp = getenv("MANPATH");
105: if (NULL == file)
106: file = MAN_CONF_FILE;
107:
108: /* No MANPATH; use man.conf(5) only. */
109: if (NULL == defp || '\0' == defp[0]) {
1.23 schwarze 110: manconf_file(conf, file);
1.8 kristaps 111: return;
112: }
113:
114: /* Prepend man.conf(5) to MANPATH. */
115: if (':' == defp[0]) {
1.23 schwarze 116: manconf_file(conf, file);
117: manpath_parseline(&conf->manpath, defp, 0);
1.8 kristaps 118: return;
119: }
120:
121: /* Append man.conf(5) to MANPATH. */
1.9 kristaps 122: if (':' == defp[strlen(defp) - 1]) {
1.23 schwarze 123: manpath_parseline(&conf->manpath, defp, 0);
124: manconf_file(conf, file);
1.8 kristaps 125: return;
126: }
127:
128: /* Insert man.conf(5) into MANPATH. */
129: insert = strstr(defp, "::");
130: if (NULL != insert) {
131: *insert++ = '\0';
1.23 schwarze 132: manpath_parseline(&conf->manpath, defp, 0);
133: manconf_file(conf, file);
134: manpath_parseline(&conf->manpath, insert + 1, 0);
1.8 kristaps 135: return;
136: }
137:
138: /* MANPATH overrides man.conf(5) completely. */
1.23 schwarze 139: manpath_parseline(&conf->manpath, defp, 0);
1.6 kristaps 140: #endif
1.1 kristaps 141: }
142:
143: /*
144: * Parse a FULL pathname from a colon-separated list of arrays.
145: */
1.6 kristaps 146: static void
1.18 schwarze 147: manpath_parseline(struct manpaths *dirs, char *path, int complain)
1.1 kristaps 148: {
149: char *dir;
150:
151: if (NULL == path)
152: return;
153:
154: for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
1.18 schwarze 155: manpath_add(dirs, dir, complain);
1.1 kristaps 156: }
157:
158: /*
159: * Add a directory to the array, ignoring bad directories.
160: * Grow the array one-by-one for simplicity's sake.
161: */
162: static void
1.18 schwarze 163: manpath_add(struct manpaths *dirs, const char *dir, int complain)
1.1 kristaps 164: {
165: char buf[PATH_MAX];
1.18 schwarze 166: struct stat sb;
1.1 kristaps 167: char *cp;
1.9 kristaps 168: size_t i;
1.1 kristaps 169:
1.18 schwarze 170: if (NULL == (cp = realpath(dir, buf))) {
1.27 schwarze 171: if (complain)
172: warn("manpath: %s", dir);
1.1 kristaps 173: return;
1.18 schwarze 174: }
1.1 kristaps 175:
176: for (i = 0; i < dirs->sz; i++)
177: if (0 == strcmp(dirs->paths[i], dir))
178: return;
179:
1.18 schwarze 180: if (stat(cp, &sb) == -1) {
1.27 schwarze 181: if (complain)
182: warn("manpath: %s", dir);
1.18 schwarze 183: return;
184: }
185:
1.15 schwarze 186: dirs->paths = mandoc_reallocarray(dirs->paths,
187: dirs->sz + 1, sizeof(char *));
1.1 kristaps 188:
189: dirs->paths[dirs->sz++] = mandoc_strdup(cp);
1.2 kristaps 190: }
191:
192: void
1.23 schwarze 193: manconf_free(struct manconf *conf)
1.2 kristaps 194: {
1.9 kristaps 195: size_t i;
1.2 kristaps 196:
1.23 schwarze 197: for (i = 0; i < conf->manpath.sz; i++)
198: free(conf->manpath.paths[i]);
1.2 kristaps 199:
1.23 schwarze 200: free(conf->manpath.paths);
201: free(conf->output.includes);
202: free(conf->output.man);
203: free(conf->output.paper);
204: free(conf->output.style);
1.2 kristaps 205: }
206:
1.26 schwarze 207: #if !HAVE_MANPATH
1.23 schwarze 208: static void
209: manconf_file(struct manconf *conf, const char *file)
1.2 kristaps 210: {
1.23 schwarze 211: const char *const toks[] = { "manpath", "output", "_whatdb" };
1.25 schwarze 212: char manpath_default[] = MANPATH_DEFAULT;
1.22 schwarze 213:
1.2 kristaps 214: FILE *stream;
1.29 schwarze 215: char *line, *cp, *ep;
216: size_t linesz, tok, toklen;
217: ssize_t linelen;
1.1 kristaps 218:
1.22 schwarze 219: if ((stream = fopen(file, "r")) == NULL)
1.25 schwarze 220: goto out;
1.1 kristaps 221:
1.29 schwarze 222: line = NULL;
223: linesz = 0;
224:
225: while ((linelen = getline(&line, &linesz, stream)) != -1) {
226: cp = line;
1.30 schwarze 227: ep = cp + linelen - 1;
228: while (ep > cp && isspace((unsigned char)*ep))
229: *ep-- = '\0';
1.22 schwarze 230: while (isspace((unsigned char)*cp))
231: cp++;
1.30 schwarze 232: if (cp == ep || *cp == '#')
1.1 kristaps 233: continue;
1.22 schwarze 234:
235: for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
1.29 schwarze 236: toklen = strlen(toks[tok]);
237: if (cp + toklen < ep &&
238: isspace((unsigned char)cp[toklen]) &&
239: strncmp(cp, toks[tok], toklen) == 0) {
240: cp += toklen;
1.22 schwarze 241: while (isspace((unsigned char)*cp))
242: cp++;
243: break;
244: }
245: }
246:
247: switch (tok) {
1.23 schwarze 248: case 2: /* _whatdb */
1.22 schwarze 249: while (ep > cp && ep[-1] != '/')
250: ep--;
251: if (ep == cp)
252: continue;
253: *ep = '\0';
254: /* FALLTHROUGH */
255: case 0: /* manpath */
1.23 schwarze 256: manpath_add(&conf->manpath, cp, 0);
1.25 schwarze 257: *manpath_default = '\0';
1.23 schwarze 258: break;
259: case 1: /* output */
1.30.2.1! schwarze 260: manconf_output(&conf->output, cp, 1);
1.22 schwarze 261: break;
262: default:
263: break;
264: }
1.1 kristaps 265: }
1.29 schwarze 266: free(line);
1.25 schwarze 267: fclose(stream);
1.1 kristaps 268:
1.25 schwarze 269: out:
270: if (*manpath_default != '\0')
271: manpath_parseline(&conf->manpath, manpath_default, 0);
1.23 schwarze 272: }
1.26 schwarze 273: #endif
1.23 schwarze 274:
1.30.2.1! schwarze 275: int
! 276: manconf_output(struct manoutput *conf, const char *cp, int fromfile)
1.23 schwarze 277: {
278: const char *const toks[] = {
279: "includes", "man", "paper", "style",
280: "indent", "width", "fragment", "mdoc"
281: };
282:
1.30.2.1! schwarze 283: const char *errstr;
! 284: char *oldval;
! 285: size_t len, tok;
1.23 schwarze 286:
287: for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
288: len = strlen(toks[tok]);
289: if ( ! strncmp(cp, toks[tok], len) &&
290: strchr(" = ", cp[len]) != NULL) {
291: cp += len;
292: if (*cp == '=')
293: cp++;
294: while (isspace((unsigned char)*cp))
295: cp++;
296: break;
297: }
298: }
299:
1.30.2.1! schwarze 300: if (tok < 6 && *cp == '\0') {
! 301: warnx("-O %s=?: Missing argument value", toks[tok]);
! 302: return -1;
! 303: }
! 304: if ((tok == 6 || tok == 7) && *cp != '\0') {
! 305: warnx("-O %s: Does not take a value: %s", toks[tok], cp);
! 306: return -1;
! 307: }
1.23 schwarze 308:
309: switch (tok) {
310: case 0:
1.30.2.1! schwarze 311: if (conf->includes != NULL) {
! 312: oldval = mandoc_strdup(conf->includes);
! 313: break;
! 314: }
! 315: conf->includes = mandoc_strdup(cp);
! 316: return 0;
1.23 schwarze 317: case 1:
1.30.2.1! schwarze 318: if (conf->man != NULL) {
! 319: oldval = mandoc_strdup(conf->man);
! 320: break;
! 321: }
! 322: conf->man = mandoc_strdup(cp);
! 323: return 0;
1.23 schwarze 324: case 2:
1.30.2.1! schwarze 325: if (conf->paper != NULL) {
! 326: oldval = mandoc_strdup(conf->paper);
! 327: break;
! 328: }
! 329: conf->paper = mandoc_strdup(cp);
! 330: return 0;
1.23 schwarze 331: case 3:
1.30.2.1! schwarze 332: if (conf->style != NULL) {
! 333: oldval = mandoc_strdup(conf->style);
! 334: break;
! 335: }
! 336: conf->style = mandoc_strdup(cp);
! 337: return 0;
1.23 schwarze 338: case 4:
1.30.2.1! schwarze 339: if (conf->indent) {
! 340: mandoc_asprintf(&oldval, "%zu", conf->indent);
! 341: break;
! 342: }
! 343: conf->indent = strtonum(cp, 0, 1000, &errstr);
! 344: if (errstr == NULL)
! 345: return 0;
! 346: warnx("-O indent=%s is %s", cp, errstr);
! 347: return -1;
1.23 schwarze 348: case 5:
1.30.2.1! schwarze 349: if (conf->width) {
! 350: mandoc_asprintf(&oldval, "%zu", conf->width);
! 351: break;
! 352: }
! 353: conf->width = strtonum(cp, 58, 1000, &errstr);
! 354: if (errstr == NULL)
! 355: return 0;
! 356: warnx("-O width=%s is %s", cp, errstr);
! 357: return -1;
1.23 schwarze 358: case 6:
359: conf->fragment = 1;
1.30.2.1! schwarze 360: return 0;
1.23 schwarze 361: case 7:
362: conf->mdoc = 1;
1.30.2.1! schwarze 363: return 0;
1.23 schwarze 364: default:
1.30.2.1! schwarze 365: if (fromfile)
! 366: warnx("-O %s: Bad argument", cp);
! 367: return -1;
! 368: }
! 369: if (fromfile == 0)
! 370: warnx("-O %s=%s: Option already set to %s",
! 371: toks[tok], cp, oldval);
! 372: free(oldval);
! 373: return -1;
1.1 kristaps 374: }
CVSweb