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