Annotation of mandoc/manpath.c, Revision 1.23
1.23 ! schwarze 1: /* $Id: manpath.c,v 1.22 2015/03/26 22:42:32 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.19 schwarze 81: manpath_parseline(dirs, buf, 1);
1.6 kristaps 82: }
1.1 kristaps 83:
1.6 kristaps 84: free(buf);
85: pclose(stream);
86: #else
1.20 schwarze 87: char manpath_default[] = MANPATH_DEFAULT;
1.8 kristaps 88: char *insert;
1.4 schwarze 89:
1.8 kristaps 90: /* Always prepend -m. */
1.23 ! schwarze 91: manpath_parseline(&conf->manpath, auxp, 1);
1.10 schwarze 92:
1.8 kristaps 93: /* If -M is given, it overrides everything else. */
94: if (NULL != defp) {
1.23 ! schwarze 95: manpath_parseline(&conf->manpath, defp, 1);
1.8 kristaps 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]) {
1.23 ! schwarze 106: manconf_file(conf, file);
! 107: if (conf->manpath.sz == 0)
! 108: manpath_parseline(&conf->manpath, manpath_default, 0);
1.8 kristaps 109: return;
110: }
111:
112: /* Prepend man.conf(5) to MANPATH. */
113: if (':' == defp[0]) {
1.23 ! schwarze 114: manconf_file(conf, file);
! 115: manpath_parseline(&conf->manpath, defp, 0);
1.8 kristaps 116: return;
117: }
118:
119: /* Append man.conf(5) to MANPATH. */
1.9 kristaps 120: if (':' == defp[strlen(defp) - 1]) {
1.23 ! schwarze 121: manpath_parseline(&conf->manpath, defp, 0);
! 122: manconf_file(conf, file);
1.8 kristaps 123: return;
124: }
125:
126: /* Insert man.conf(5) into MANPATH. */
127: insert = strstr(defp, "::");
128: if (NULL != insert) {
129: *insert++ = '\0';
1.23 ! schwarze 130: manpath_parseline(&conf->manpath, defp, 0);
! 131: manconf_file(conf, file);
! 132: manpath_parseline(&conf->manpath, insert + 1, 0);
1.8 kristaps 133: return;
134: }
135:
136: /* MANPATH overrides man.conf(5) completely. */
1.23 ! schwarze 137: manpath_parseline(&conf->manpath, defp, 0);
1.6 kristaps 138: #endif
1.1 kristaps 139: }
140:
141: /*
142: * Parse a FULL pathname from a colon-separated list of arrays.
143: */
1.6 kristaps 144: static void
1.18 schwarze 145: manpath_parseline(struct manpaths *dirs, char *path, int complain)
1.1 kristaps 146: {
147: char *dir;
148:
149: if (NULL == path)
150: return;
151:
152: for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
1.18 schwarze 153: manpath_add(dirs, dir, complain);
1.1 kristaps 154: }
155:
156: /*
157: * Add a directory to the array, ignoring bad directories.
158: * Grow the array one-by-one for simplicity's sake.
159: */
160: static void
1.18 schwarze 161: manpath_add(struct manpaths *dirs, const char *dir, int complain)
1.1 kristaps 162: {
163: char buf[PATH_MAX];
1.18 schwarze 164: struct stat sb;
1.1 kristaps 165: char *cp;
1.9 kristaps 166: size_t i;
1.1 kristaps 167:
1.18 schwarze 168: if (NULL == (cp = realpath(dir, buf))) {
169: if (complain) {
170: fputs("manpath: ", stderr);
171: perror(dir);
172: }
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) {
181: if (complain) {
182: fputs("manpath: ", stderr);
183: perror(dir);
184: }
185: return;
186: }
187:
1.15 schwarze 188: dirs->paths = mandoc_reallocarray(dirs->paths,
189: dirs->sz + 1, sizeof(char *));
1.1 kristaps 190:
191: dirs->paths[dirs->sz++] = mandoc_strdup(cp);
1.2 kristaps 192: }
193:
194: void
1.23 ! schwarze 195: manconf_free(struct manconf *conf)
1.2 kristaps 196: {
1.9 kristaps 197: size_t i;
1.2 kristaps 198:
1.23 ! schwarze 199: for (i = 0; i < conf->manpath.sz; i++)
! 200: free(conf->manpath.paths[i]);
1.2 kristaps 201:
1.23 ! schwarze 202: free(conf->manpath.paths);
! 203: free(conf->output.includes);
! 204: free(conf->output.man);
! 205: free(conf->output.paper);
! 206: free(conf->output.style);
1.2 kristaps 207: }
208:
1.23 ! schwarze 209: static void
! 210: manconf_file(struct manconf *conf, const char *file)
1.2 kristaps 211: {
1.23 ! schwarze 212: const char *const toks[] = { "manpath", "output", "_whatdb" };
1.22 schwarze 213:
1.2 kristaps 214: FILE *stream;
1.22 schwarze 215: char *cp, *ep;
216: size_t len, tok;
1.1 kristaps 217:
1.22 schwarze 218: if ((stream = fopen(file, "r")) == NULL)
1.1 kristaps 219: return;
220:
1.22 schwarze 221: while ((cp = fgetln(stream, &len)) != NULL) {
222: ep = cp + len;
223: if (ep[-1] != '\n')
1.1 kristaps 224: break;
1.22 schwarze 225: *--ep = '\0';
226: while (isspace((unsigned char)*cp))
227: cp++;
228: if (*cp == '#')
1.1 kristaps 229: continue;
1.22 schwarze 230:
231: for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
232: len = strlen(toks[tok]);
233: if (cp + len < ep &&
234: isspace((unsigned char)cp[len]) &&
235: !strncmp(cp, toks[tok], len)) {
236: cp += len;
237: while (isspace((unsigned char)*cp))
238: cp++;
239: break;
240: }
241: }
242:
243: switch (tok) {
1.23 ! schwarze 244: case 2: /* _whatdb */
1.22 schwarze 245: while (ep > cp && ep[-1] != '/')
246: ep--;
247: if (ep == cp)
248: continue;
249: *ep = '\0';
250: /* FALLTHROUGH */
251: case 0: /* manpath */
1.23 ! schwarze 252: manpath_add(&conf->manpath, cp, 0);
! 253: break;
! 254: case 1: /* output */
! 255: manconf_output(&conf->output, cp);
1.22 schwarze 256: break;
257: default:
258: break;
259: }
1.1 kristaps 260: }
261:
262: fclose(stream);
1.23 ! schwarze 263: }
! 264:
! 265: void
! 266: manconf_output(struct manoutput *conf, const char *cp)
! 267: {
! 268: const char *const toks[] = {
! 269: "includes", "man", "paper", "style",
! 270: "indent", "width", "fragment", "mdoc"
! 271: };
! 272:
! 273: size_t len, tok;
! 274:
! 275: for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
! 276: len = strlen(toks[tok]);
! 277: if ( ! strncmp(cp, toks[tok], len) &&
! 278: strchr(" = ", cp[len]) != NULL) {
! 279: cp += len;
! 280: if (*cp == '=')
! 281: cp++;
! 282: while (isspace((unsigned char)*cp))
! 283: cp++;
! 284: break;
! 285: }
! 286: }
! 287:
! 288: if (tok < 6 && *cp == '\0')
! 289: return;
! 290:
! 291: switch (tok) {
! 292: case 0:
! 293: if (conf->includes == NULL)
! 294: conf->includes = mandoc_strdup(cp);
! 295: break;
! 296: case 1:
! 297: if (conf->man == NULL)
! 298: conf->man = mandoc_strdup(cp);
! 299: break;
! 300: case 2:
! 301: if (conf->paper == NULL)
! 302: conf->paper = mandoc_strdup(cp);
! 303: break;
! 304: case 3:
! 305: if (conf->style == NULL)
! 306: conf->style = mandoc_strdup(cp);
! 307: break;
! 308: case 4:
! 309: if (conf->indent == 0)
! 310: conf->indent = strtonum(cp, 0, 1000, NULL);
! 311: break;
! 312: case 5:
! 313: if (conf->width == 0)
! 314: conf->width = strtonum(cp, 58, 1000, NULL);
! 315: break;
! 316: case 6:
! 317: conf->fragment = 1;
! 318: break;
! 319: case 7:
! 320: conf->mdoc = 1;
! 321: break;
! 322: default:
! 323: break;
! 324: }
1.1 kristaps 325: }
CVSweb