xref: /netbsd-src/usr.bin/man/manconf.c (revision 73704c4ce4ee2a60eb617e693ce7e9f03902613e)
1 /*	$NetBSD: manconf.c,v 1.3 2003/08/07 11:15:11 agc 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 #if HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)config.c	8.8 (Berkeley) 1/31/95";
40 #else
41 #if defined(__RCSID)
42 __RCSID("$NetBSD: manconf.c,v 1.3 2003/08/07 11:15:11 agc Exp $");
43 #endif
44 #endif
45 #endif /* not lint */
46 
47 #include <sys/types.h>
48 #include <sys/queue.h>
49 
50 #include <ctype.h>
51 #include <err.h>
52 #include <errno.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 
57 #include "manconf.h"
58 #include "pathnames.h"
59 
60 struct _head head;
61 
62 /*
63  * config --
64  *
65  * Read the configuration file and build a doubly linked
66  * list that looks like:
67  *
68  *	tag1 <-> record <-> record <-> record
69  *	|
70  *	tag2 <-> record <-> record <-> record
71  */
72 void
73 config(fname)
74 	const char *fname;
75 {
76 	TAG *tp;
77 	FILE *cfp;
78 	size_t len;
79 	int lcnt;
80 	char *p, *t, type;
81 
82 	if (fname == NULL)
83 		fname = _PATH_MANCONF;
84 	if ((cfp = fopen(fname, "r")) == NULL)
85 		err(1, "%s", fname);
86 	TAILQ_INIT(&head);
87 	for (lcnt = 1; (p = fgetln(cfp, &len)) != NULL; ++lcnt) {
88 		if (len == 1)			/* Skip empty lines. */
89 			continue;
90 		if (p[len - 1] != '\n') {	/* Skip corrupted lines. */
91 			warnx("%s: line %d corrupted", fname, lcnt);
92 			continue;
93 		}
94 		p[len - 1] = '\0';		/* Terminate the line. */
95 
96 						/* Skip leading space. */
97 		for (; *p != '\0' && isspace((unsigned char)*p); ++p);
98 						/* Skip empty/comment lines. */
99 		if (*p == '\0' || *p == '#')
100 			continue;
101 						/* Find first token. */
102 		for (t = p; *t && !isspace((unsigned char)*t); ++t);
103 		if (*t == '\0')			/* Need more than one token.*/
104 			continue;
105 		*t = '\0';
106 
107 		tp = getlist(p, 1);
108 
109 		/*
110 		 * Attach new records. Check to see if it is a
111 		 * section record or not.
112 		 */
113 
114 		if (*p == '_') {		/* not a section record */
115 			/*
116 			 * Special cases: _build and _crunch take the
117 			 * rest of the line as a single entry.
118 			 */
119 			if (!strcmp(p, "_build") || !strcmp(p, "_crunch")) {
120 				/*
121 				 * The reason we're not just using
122 				 * strtok(3) for all of the parsing is
123 				 * so we don't get caught if a line
124 				 * has only a single token on it.
125 				 */
126 				while (*++t && isspace((unsigned char)*t));
127 				addentry(tp, t, 0);
128 			} else {
129 				for(++t; (p = strtok(t, " \t\n")) != NULL;
130 					t = NULL)
131 					addentry(tp, p, 0);
132 			}
133 
134 		} else {			/* section record */
135 
136 			/*
137 			 * section entries can either be all absolute
138 			 * paths or all relative paths, but not both.
139 			 */
140 			type = (TAILQ_FIRST(&tp->list) != NULL) ?
141 			  *(TAILQ_FIRST(&tp->list)->s) : 0;
142 
143 			for (++t; (p = strtok(t, " \t\n")) != NULL; t = NULL) {
144 
145 				/* ensure an assigned type */
146 				if (type == 0)
147 					type = *p;
148 
149 				/* check for illegal mix */
150 				if (*p != type) {
151 	warnx("section %s: %s: invalid entry, does not match previous types",
152 	      tp->s, p);
153 	warnx("man.conf cannot mix absolute and relative paths in an entry");
154 					continue;
155 				}
156 				addentry(tp, p, 0);
157 			}
158 		}
159 	}
160 
161 	fclose(cfp);
162 }
163 
164 /*
165  * getlist --
166  *	Return the linked list of entries for a tag if it exists.
167  *	If it doesn't exist and create is non zero, create new tag
168  *	and return that, otherwise return NULL.
169  */
170 TAG *
171 getlist(name, create)
172 	const char *name;
173 	int create;
174 {
175 	TAG *tp;
176 
177 	TAILQ_FOREACH(tp, &head, q)
178 		if (!strcmp(name, tp->s))
179 			return (tp);
180 	if (create) {
181 		if ((tp = malloc(sizeof(TAG))) == NULL ||
182 		    (tp->s = strdup(name)) == NULL)
183 			err(1, "malloc");
184 		TAILQ_INIT(&tp->list);
185 		TAILQ_INSERT_TAIL(&head, tp, q);
186 		return (tp);
187 	} else
188 		return (NULL);
189 }
190 
191 /*
192  * addentry --
193  *	add an entry to a list.
194  */
195 void
196 addentry(tp, newent, head)
197 	TAG *tp;
198 	const char *newent;
199 	int head;
200 {
201 	ENTRY *ep;
202 
203 	if ((ep = malloc(sizeof(*ep))) == NULL ||
204 	    (ep->s = strdup(newent)) == NULL)
205 		err(1, "malloc");
206 	if (head)
207 		TAILQ_INSERT_HEAD(&tp->list, ep, q);
208 	else
209 		TAILQ_INSERT_TAIL(&tp->list, ep, q);
210 }
211 
212 #ifdef MANDEBUG
213 void
214 debug(l)
215 	const char *l;
216 {
217 	TAG *tp;
218 	ENTRY *ep;
219 
220 	(void)printf("%s ===============\n", l);
221 	TAILQ_FOREACH(tp, &head, q) {
222 		printf("%s\n", tp->s);
223 		TAILQ_FOREACH(ep, &tp->list, q)
224 			printf("\t%s\n", ep->s);
225 	}
226 }
227 #endif
228