manconf.c revision 1.6.28.1 1 1.6.28.1 tls /* $NetBSD: manconf.c,v 1.6.28.1 2014/08/20 00:05:00 tls Exp $ */
2 1.1 thorpej
3 1.1 thorpej /*
4 1.1 thorpej * Copyright (c) 1989, 1993, 1995
5 1.1 thorpej * The Regents of the University of California. All rights reserved.
6 1.1 thorpej *
7 1.1 thorpej * Redistribution and use in source and binary forms, with or without
8 1.1 thorpej * modification, are permitted provided that the following conditions
9 1.1 thorpej * are met:
10 1.1 thorpej * 1. Redistributions of source code must retain the above copyright
11 1.1 thorpej * notice, this list of conditions and the following disclaimer.
12 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 thorpej * notice, this list of conditions and the following disclaimer in the
14 1.1 thorpej * documentation and/or other materials provided with the distribution.
15 1.3 agc * 3. Neither the name of the University nor the names of its contributors
16 1.1 thorpej * may be used to endorse or promote products derived from this software
17 1.1 thorpej * without specific prior written permission.
18 1.1 thorpej *
19 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 1.1 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.1 thorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 1.1 thorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.1 thorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 1.1 thorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 1.1 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.1 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.1 thorpej * SUCH DAMAGE.
30 1.1 thorpej */
31 1.1 thorpej
32 1.5 chuck /*
33 1.5 chuck * manconf.c: provides interface for reading man.conf files
34 1.5 chuck *
35 1.5 chuck * note that this code is shared across all programs that read man.conf.
36 1.5 chuck * (currently: apropos, catman, makewhatis, man, and whatis...)
37 1.5 chuck */
38 1.5 chuck
39 1.4 lukem #if HAVE_NBTOOL_CONFIG_H
40 1.4 lukem #include "nbtool_config.h"
41 1.2 thorpej #endif
42 1.2 thorpej
43 1.1 thorpej #include <sys/cdefs.h>
44 1.1 thorpej #ifndef lint
45 1.1 thorpej #if 0
46 1.1 thorpej static char sccsid[] = "@(#)config.c 8.8 (Berkeley) 1/31/95";
47 1.1 thorpej #else
48 1.6.28.1 tls __RCSID("$NetBSD: manconf.c,v 1.6.28.1 2014/08/20 00:05:00 tls Exp $");
49 1.1 thorpej #endif
50 1.1 thorpej #endif /* not lint */
51 1.1 thorpej
52 1.1 thorpej #include <sys/types.h>
53 1.1 thorpej #include <sys/queue.h>
54 1.1 thorpej
55 1.1 thorpej #include <ctype.h>
56 1.1 thorpej #include <err.h>
57 1.1 thorpej #include <errno.h>
58 1.1 thorpej #include <stdio.h>
59 1.1 thorpej #include <stdlib.h>
60 1.1 thorpej #include <string.h>
61 1.1 thorpej
62 1.1 thorpej #include "manconf.h"
63 1.1 thorpej #include "pathnames.h"
64 1.1 thorpej
65 1.5 chuck TAILQ_HEAD(_head, _tag);
66 1.5 chuck static struct _head head; /* 'head' -- top level data structure */
67 1.5 chuck
68 1.5 chuck /*
69 1.5 chuck * xstrdup: like strdup, but also returns length of string in lenp
70 1.5 chuck */
71 1.5 chuck static char *
72 1.5 chuck xstrdup(const char *str, size_t *lenp)
73 1.5 chuck {
74 1.5 chuck size_t len;
75 1.5 chuck char *copy;
76 1.5 chuck
77 1.5 chuck len = strlen(str) + 1;
78 1.5 chuck copy = malloc(len);
79 1.5 chuck if (!copy)
80 1.6 christos return NULL;
81 1.6 christos (void)memcpy(copy, str, len);
82 1.5 chuck if (lenp)
83 1.5 chuck *lenp = len - 1; /* subtract out the null */
84 1.6 christos return copy;
85 1.5 chuck }
86 1.1 thorpej
87 1.1 thorpej /*
88 1.1 thorpej * config --
89 1.1 thorpej *
90 1.1 thorpej * Read the configuration file and build a doubly linked
91 1.5 chuck * list off of "head" that looks like:
92 1.1 thorpej *
93 1.5 chuck * tag1 <-> entry <-> entry <-> entry
94 1.1 thorpej * |
95 1.5 chuck * tag2 <-> entry <-> entry <-> entry
96 1.5 chuck *
97 1.5 chuck * note: will err/errx out on error (fopen or malloc failure)
98 1.1 thorpej */
99 1.1 thorpej void
100 1.5 chuck config(const char *fname)
101 1.1 thorpej {
102 1.1 thorpej TAG *tp;
103 1.1 thorpej FILE *cfp;
104 1.1 thorpej size_t len;
105 1.1 thorpej int lcnt;
106 1.1 thorpej char *p, *t, type;
107 1.1 thorpej
108 1.1 thorpej if (fname == NULL)
109 1.1 thorpej fname = _PATH_MANCONF;
110 1.1 thorpej if ((cfp = fopen(fname, "r")) == NULL)
111 1.6 christos err(EXIT_FAILURE, "%s", fname);
112 1.1 thorpej TAILQ_INIT(&head);
113 1.1 thorpej for (lcnt = 1; (p = fgetln(cfp, &len)) != NULL; ++lcnt) {
114 1.1 thorpej if (len == 1) /* Skip empty lines. */
115 1.1 thorpej continue;
116 1.1 thorpej if (p[len - 1] != '\n') { /* Skip corrupted lines. */
117 1.1 thorpej warnx("%s: line %d corrupted", fname, lcnt);
118 1.1 thorpej continue;
119 1.1 thorpej }
120 1.1 thorpej p[len - 1] = '\0'; /* Terminate the line. */
121 1.1 thorpej
122 1.1 thorpej /* Skip leading space. */
123 1.6 christos for (/*EMPTY*/; *p != '\0' && isspace((unsigned char)*p); ++p)
124 1.6 christos continue;
125 1.1 thorpej /* Skip empty/comment lines. */
126 1.1 thorpej if (*p == '\0' || *p == '#')
127 1.1 thorpej continue;
128 1.1 thorpej /* Find first token. */
129 1.6 christos for (t = p; *t && !isspace((unsigned char)*t); ++t)
130 1.6 christos continue;
131 1.1 thorpej if (*t == '\0') /* Need more than one token.*/
132 1.1 thorpej continue;
133 1.1 thorpej *t = '\0';
134 1.1 thorpej
135 1.5 chuck tp = gettag(p, 1);
136 1.5 chuck if (!tp)
137 1.6 christos errx(EXIT_FAILURE, "gettag: malloc failed");
138 1.1 thorpej
139 1.1 thorpej /*
140 1.1 thorpej * Attach new records. Check to see if it is a
141 1.1 thorpej * section record or not.
142 1.1 thorpej */
143 1.1 thorpej
144 1.1 thorpej if (*p == '_') { /* not a section record */
145 1.1 thorpej /*
146 1.6 christos * Special cases: _build and _crunch take the
147 1.1 thorpej * rest of the line as a single entry.
148 1.1 thorpej */
149 1.1 thorpej if (!strcmp(p, "_build") || !strcmp(p, "_crunch")) {
150 1.6.28.1 tls const char *u;
151 1.6.28.1 tls
152 1.1 thorpej /*
153 1.1 thorpej * The reason we're not just using
154 1.1 thorpej * strtok(3) for all of the parsing is
155 1.1 thorpej * so we don't get caught if a line
156 1.1 thorpej * has only a single token on it.
157 1.1 thorpej */
158 1.1 thorpej while (*++t && isspace((unsigned char)*t));
159 1.6.28.1 tls #ifndef HAVE_NBTOOL_CONFIG_H
160 1.6.28.1 tls /* pre-verify user-supplied command format */
161 1.6.28.1 tls u = t;
162 1.6.28.1 tls while (*u && !isspace((unsigned char)*u))
163 1.6.28.1 tls ++u;
164 1.6.28.1 tls while (*u && isspace((unsigned char)*u))
165 1.6.28.1 tls ++u;
166 1.6.28.1 tls if (fmtcheck(u, "%s") != u) {
167 1.6.28.1 tls warnx("%s:%d: invalid %s command ignored",
168 1.6.28.1 tls fname, lcnt, p);
169 1.6.28.1 tls continue;
170 1.6.28.1 tls }
171 1.6.28.1 tls #endif /* !HAVE_NBTOOL_CONFIG_H */
172 1.6 christos if (addentry(tp, t, 0) == -1)
173 1.6 christos errx(EXIT_FAILURE,
174 1.6 christos "addentry: malloc failed");
175 1.1 thorpej } else {
176 1.6 christos for (++t; (p = strtok(t, " \t\n")) != NULL;
177 1.6 christos t = NULL) {
178 1.6 christos if (addentry(tp, p, 0) == -1)
179 1.6 christos errx(EXIT_FAILURE,
180 1.5 chuck "addentry: malloc failed");
181 1.5 chuck }
182 1.1 thorpej }
183 1.6 christos
184 1.1 thorpej } else { /* section record */
185 1.1 thorpej
186 1.1 thorpej /*
187 1.1 thorpej * section entries can either be all absolute
188 1.1 thorpej * paths or all relative paths, but not both.
189 1.1 thorpej */
190 1.6.28.1 tls type = (char)((TAILQ_FIRST(&tp->entrylist) != NULL) ?
191 1.6.28.1 tls *(TAILQ_FIRST(&tp->entrylist)->s) : '\0');
192 1.1 thorpej
193 1.1 thorpej for (++t; (p = strtok(t, " \t\n")) != NULL; t = NULL) {
194 1.1 thorpej
195 1.1 thorpej /* ensure an assigned type */
196 1.1 thorpej if (type == 0)
197 1.1 thorpej type = *p;
198 1.6 christos
199 1.1 thorpej /* check for illegal mix */
200 1.1 thorpej if (*p != type) {
201 1.1 thorpej warnx("section %s: %s: invalid entry, does not match previous types",
202 1.1 thorpej tp->s, p);
203 1.1 thorpej warnx("man.conf cannot mix absolute and relative paths in an entry");
204 1.1 thorpej continue;
205 1.1 thorpej }
206 1.6 christos if (addentry(tp, p, 0) == -1)
207 1.6 christos errx(EXIT_FAILURE,
208 1.6 christos "addentry: malloc failed");
209 1.1 thorpej }
210 1.1 thorpej }
211 1.1 thorpej }
212 1.6 christos (void)fclose(cfp);
213 1.1 thorpej }
214 1.1 thorpej
215 1.1 thorpej /*
216 1.5 chuck * gettag --
217 1.5 chuck * if (!create) return tag for given name if it exists, or NULL otherwise
218 1.6 christos *
219 1.5 chuck * if (create) return tag for given name if it exists, try and create
220 1.5 chuck * a new tag if it does not exist. return NULL if unable to create new
221 1.5 chuck * tag.
222 1.1 thorpej */
223 1.1 thorpej TAG *
224 1.5 chuck gettag(const char *name, int create)
225 1.1 thorpej {
226 1.1 thorpej TAG *tp;
227 1.1 thorpej
228 1.1 thorpej TAILQ_FOREACH(tp, &head, q)
229 1.1 thorpej if (!strcmp(name, tp->s))
230 1.6 christos return tp;
231 1.5 chuck if (!create)
232 1.6 christos return NULL;
233 1.5 chuck
234 1.5 chuck /* try and add it in */
235 1.5 chuck tp = malloc(sizeof(*tp));
236 1.5 chuck if (tp)
237 1.5 chuck tp->s = xstrdup(name, &tp->len);
238 1.5 chuck if (!tp || !tp->s) {
239 1.5 chuck if (tp)
240 1.5 chuck free(tp);
241 1.6 christos return NULL;
242 1.5 chuck }
243 1.5 chuck TAILQ_INIT(&tp->entrylist);
244 1.5 chuck TAILQ_INSERT_TAIL(&head, tp, q);
245 1.6 christos return tp;
246 1.1 thorpej }
247 1.1 thorpej
248 1.1 thorpej /*
249 1.1 thorpej * addentry --
250 1.6 christos * add an entry to a list.
251 1.5 chuck * returns -1 if malloc failed, otherwise 0.
252 1.1 thorpej */
253 1.5 chuck int
254 1.6 christos addentry(TAG *tp, const char *newent, int ishead)
255 1.1 thorpej {
256 1.1 thorpej ENTRY *ep;
257 1.1 thorpej
258 1.5 chuck ep = malloc(sizeof(*ep));
259 1.5 chuck if (ep)
260 1.5 chuck ep->s = xstrdup(newent, &ep->len);
261 1.5 chuck if (!ep || !ep->s) {
262 1.5 chuck if (ep)
263 1.5 chuck free(ep);
264 1.6 christos return -1;
265 1.5 chuck }
266 1.6 christos if (ishead)
267 1.5 chuck TAILQ_INSERT_HEAD(&tp->entrylist, ep, q);
268 1.1 thorpej else
269 1.5 chuck TAILQ_INSERT_TAIL(&tp->entrylist, ep, q);
270 1.1 thorpej
271 1.6 christos return 0;
272 1.1 thorpej }
273