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