xref: /netbsd-src/usr.bin/man/manconf.c (revision 001c68bd94f75ce9270b69227c4199fbf34ee396)
1 /*	$NetBSD: manconf.c,v 1.2 2002/09/13 16:34:56 thorpej 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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #if HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 
40 #include <sys/cdefs.h>
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)config.c	8.8 (Berkeley) 1/31/95";
44 #else
45 #if defined(__RCSID)
46 __RCSID("$NetBSD: manconf.c,v 1.2 2002/09/13 16:34:56 thorpej Exp $");
47 #endif
48 #endif
49 #endif /* not lint */
50 
51 #include <sys/types.h>
52 #include <sys/queue.h>
53 
54 #include <ctype.h>
55 #include <err.h>
56 #include <errno.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 
61 #include "manconf.h"
62 #include "pathnames.h"
63 
64 struct _head head;
65 
66 /*
67  * config --
68  *
69  * Read the configuration file and build a doubly linked
70  * list that looks like:
71  *
72  *	tag1 <-> record <-> record <-> record
73  *	|
74  *	tag2 <-> record <-> record <-> record
75  */
76 void
77 config(fname)
78 	const char *fname;
79 {
80 	TAG *tp;
81 	FILE *cfp;
82 	size_t len;
83 	int lcnt;
84 	char *p, *t, type;
85 
86 	if (fname == NULL)
87 		fname = _PATH_MANCONF;
88 	if ((cfp = fopen(fname, "r")) == NULL)
89 		err(1, "%s", fname);
90 	TAILQ_INIT(&head);
91 	for (lcnt = 1; (p = fgetln(cfp, &len)) != NULL; ++lcnt) {
92 		if (len == 1)			/* Skip empty lines. */
93 			continue;
94 		if (p[len - 1] != '\n') {	/* Skip corrupted lines. */
95 			warnx("%s: line %d corrupted", fname, lcnt);
96 			continue;
97 		}
98 		p[len - 1] = '\0';		/* Terminate the line. */
99 
100 						/* Skip leading space. */
101 		for (; *p != '\0' && isspace((unsigned char)*p); ++p);
102 						/* Skip empty/comment lines. */
103 		if (*p == '\0' || *p == '#')
104 			continue;
105 						/* Find first token. */
106 		for (t = p; *t && !isspace((unsigned char)*t); ++t);
107 		if (*t == '\0')			/* Need more than one token.*/
108 			continue;
109 		*t = '\0';
110 
111 		tp = getlist(p, 1);
112 
113 		/*
114 		 * Attach new records. Check to see if it is a
115 		 * section record or not.
116 		 */
117 
118 		if (*p == '_') {		/* not a section record */
119 			/*
120 			 * Special cases: _build and _crunch take the
121 			 * rest of the line as a single entry.
122 			 */
123 			if (!strcmp(p, "_build") || !strcmp(p, "_crunch")) {
124 				/*
125 				 * The reason we're not just using
126 				 * strtok(3) for all of the parsing is
127 				 * so we don't get caught if a line
128 				 * has only a single token on it.
129 				 */
130 				while (*++t && isspace((unsigned char)*t));
131 				addentry(tp, t, 0);
132 			} else {
133 				for(++t; (p = strtok(t, " \t\n")) != NULL;
134 					t = NULL)
135 					addentry(tp, p, 0);
136 			}
137 
138 		} else {			/* section record */
139 
140 			/*
141 			 * section entries can either be all absolute
142 			 * paths or all relative paths, but not both.
143 			 */
144 			type = (TAILQ_FIRST(&tp->list) != NULL) ?
145 			  *(TAILQ_FIRST(&tp->list)->s) : 0;
146 
147 			for (++t; (p = strtok(t, " \t\n")) != NULL; t = NULL) {
148 
149 				/* ensure an assigned type */
150 				if (type == 0)
151 					type = *p;
152 
153 				/* check for illegal mix */
154 				if (*p != type) {
155 	warnx("section %s: %s: invalid entry, does not match previous types",
156 	      tp->s, p);
157 	warnx("man.conf cannot mix absolute and relative paths in an entry");
158 					continue;
159 				}
160 				addentry(tp, p, 0);
161 			}
162 		}
163 	}
164 
165 	fclose(cfp);
166 }
167 
168 /*
169  * getlist --
170  *	Return the linked list of entries for a tag if it exists.
171  *	If it doesn't exist and create is non zero, create new tag
172  *	and return that, otherwise return NULL.
173  */
174 TAG *
175 getlist(name, create)
176 	const char *name;
177 	int create;
178 {
179 	TAG *tp;
180 
181 	TAILQ_FOREACH(tp, &head, q)
182 		if (!strcmp(name, tp->s))
183 			return (tp);
184 	if (create) {
185 		if ((tp = malloc(sizeof(TAG))) == NULL ||
186 		    (tp->s = strdup(name)) == NULL)
187 			err(1, "malloc");
188 		TAILQ_INIT(&tp->list);
189 		TAILQ_INSERT_TAIL(&head, tp, q);
190 		return (tp);
191 	} else
192 		return (NULL);
193 }
194 
195 /*
196  * addentry --
197  *	add an entry to a list.
198  */
199 void
200 addentry(tp, newent, head)
201 	TAG *tp;
202 	const char *newent;
203 	int head;
204 {
205 	ENTRY *ep;
206 
207 	if ((ep = malloc(sizeof(*ep))) == NULL ||
208 	    (ep->s = strdup(newent)) == NULL)
209 		err(1, "malloc");
210 	if (head)
211 		TAILQ_INSERT_HEAD(&tp->list, ep, q);
212 	else
213 		TAILQ_INSERT_TAIL(&tp->list, ep, q);
214 }
215 
216 #ifdef MANDEBUG
217 void
218 debug(l)
219 	const char *l;
220 {
221 	TAG *tp;
222 	ENTRY *ep;
223 
224 	(void)printf("%s ===============\n", l);
225 	TAILQ_FOREACH(tp, &head, q) {
226 		printf("%s\n", tp->s);
227 		TAILQ_FOREACH(ep, &tp->list, q)
228 			printf("\t%s\n", ep->s);
229 	}
230 }
231 #endif
232