xref: /minix3/usr.bin/man/manconf.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: manconf.c,v 1.8 2014/02/17 02:53:48 uwe Exp $	*/
20c3983b2SBen Gras 
30c3983b2SBen Gras /*
40c3983b2SBen Gras  * Copyright (c) 1989, 1993, 1995
50c3983b2SBen Gras  *	The Regents of the University of California.  All rights reserved.
60c3983b2SBen Gras  *
70c3983b2SBen Gras  * Redistribution and use in source and binary forms, with or without
80c3983b2SBen Gras  * modification, are permitted provided that the following conditions
90c3983b2SBen Gras  * are met:
100c3983b2SBen Gras  * 1. Redistributions of source code must retain the above copyright
110c3983b2SBen Gras  *    notice, this list of conditions and the following disclaimer.
120c3983b2SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
130c3983b2SBen Gras  *    notice, this list of conditions and the following disclaimer in the
140c3983b2SBen Gras  *    documentation and/or other materials provided with the distribution.
150c3983b2SBen Gras  * 3. Neither the name of the University nor the names of its contributors
160c3983b2SBen Gras  *    may be used to endorse or promote products derived from this software
170c3983b2SBen Gras  *    without specific prior written permission.
180c3983b2SBen Gras  *
190c3983b2SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
200c3983b2SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
210c3983b2SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
220c3983b2SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
230c3983b2SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
240c3983b2SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
250c3983b2SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
260c3983b2SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
270c3983b2SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
280c3983b2SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
290c3983b2SBen Gras  * SUCH DAMAGE.
300c3983b2SBen Gras  */
310c3983b2SBen Gras 
320c3983b2SBen Gras /*
330c3983b2SBen Gras  * manconf.c: provides interface for reading man.conf files
340c3983b2SBen Gras  *
350c3983b2SBen Gras  * note that this code is shared across all programs that read man.conf.
360c3983b2SBen Gras  * (currently: apropos, catman, makewhatis, man, and whatis...)
370c3983b2SBen Gras  */
380c3983b2SBen Gras 
390c3983b2SBen Gras #if HAVE_NBTOOL_CONFIG_H
400c3983b2SBen Gras #include "nbtool_config.h"
410c3983b2SBen Gras #endif
420c3983b2SBen Gras 
430c3983b2SBen Gras #include <sys/cdefs.h>
440c3983b2SBen Gras #ifndef lint
450c3983b2SBen Gras #if 0
460c3983b2SBen Gras static char sccsid[] = "@(#)config.c	8.8 (Berkeley) 1/31/95";
470c3983b2SBen Gras #else
48*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: manconf.c,v 1.8 2014/02/17 02:53:48 uwe Exp $");
490c3983b2SBen Gras #endif
500c3983b2SBen Gras #endif /* not lint */
510c3983b2SBen Gras 
520c3983b2SBen Gras #include <sys/types.h>
530c3983b2SBen Gras #include <sys/queue.h>
540c3983b2SBen Gras 
550c3983b2SBen Gras #include <ctype.h>
560c3983b2SBen Gras #include <err.h>
570c3983b2SBen Gras #include <errno.h>
580c3983b2SBen Gras #include <stdio.h>
590c3983b2SBen Gras #include <stdlib.h>
600c3983b2SBen Gras #include <string.h>
610c3983b2SBen Gras 
620c3983b2SBen Gras #include "manconf.h"
630c3983b2SBen Gras #include "pathnames.h"
640c3983b2SBen Gras 
650c3983b2SBen Gras TAILQ_HEAD(_head, _tag);
660c3983b2SBen Gras static struct _head head;	/* 'head' -- top level data structure */
670c3983b2SBen Gras 
680c3983b2SBen Gras /*
690c3983b2SBen Gras  * xstrdup: like strdup, but also returns length of string in lenp
700c3983b2SBen Gras  */
710c3983b2SBen Gras static char *
xstrdup(const char * str,size_t * lenp)720c3983b2SBen Gras xstrdup(const char *str, size_t *lenp)
730c3983b2SBen Gras {
740c3983b2SBen Gras 	size_t len;
750c3983b2SBen Gras 	char *copy;
760c3983b2SBen Gras 
770c3983b2SBen Gras 	len = strlen(str) + 1;
780c3983b2SBen Gras 	copy = malloc(len);
790c3983b2SBen Gras 	if (!copy)
800c3983b2SBen Gras 		return NULL;
810c3983b2SBen Gras 	(void)memcpy(copy, str, len);
820c3983b2SBen Gras 	if (lenp)
830c3983b2SBen Gras 		*lenp = len - 1;	/* subtract out the null */
840c3983b2SBen Gras 	return copy;
850c3983b2SBen Gras }
860c3983b2SBen Gras 
870c3983b2SBen Gras /*
880c3983b2SBen Gras  * config --
890c3983b2SBen Gras  *
900c3983b2SBen Gras  * Read the configuration file and build a doubly linked
910c3983b2SBen Gras  * list off of "head" that looks like:
920c3983b2SBen Gras  *
930c3983b2SBen Gras  *	tag1 <-> entry <-> entry <-> entry
940c3983b2SBen Gras  *	|
950c3983b2SBen Gras  *	tag2 <-> entry <-> entry <-> entry
960c3983b2SBen Gras  *
970c3983b2SBen Gras  * note: will err/errx out on error (fopen or malloc failure)
980c3983b2SBen Gras  */
990c3983b2SBen Gras void
config(const char * fname)1000c3983b2SBen Gras config(const char *fname)
1010c3983b2SBen Gras {
1020c3983b2SBen Gras 	TAG *tp;
1030c3983b2SBen Gras 	FILE *cfp;
1040c3983b2SBen Gras 	size_t len;
1050c3983b2SBen Gras 	int lcnt;
1060c3983b2SBen Gras 	char *p, *t, type;
1070c3983b2SBen Gras 
1080c3983b2SBen Gras 	if (fname == NULL)
1090c3983b2SBen Gras 		fname = _PATH_MANCONF;
1100c3983b2SBen Gras 	if ((cfp = fopen(fname, "r")) == NULL)
1110c3983b2SBen Gras 		err(EXIT_FAILURE, "%s", fname);
1120c3983b2SBen Gras 	TAILQ_INIT(&head);
1130c3983b2SBen Gras 	for (lcnt = 1; (p = fgetln(cfp, &len)) != NULL; ++lcnt) {
1140c3983b2SBen Gras 		if (len == 1)			/* Skip empty lines. */
1150c3983b2SBen Gras 			continue;
1160c3983b2SBen Gras 		if (p[len - 1] != '\n') {	/* Skip corrupted lines. */
1170c3983b2SBen Gras 			warnx("%s: line %d corrupted", fname, lcnt);
1180c3983b2SBen Gras 			continue;
1190c3983b2SBen Gras 		}
1200c3983b2SBen Gras 		p[len - 1] = '\0';		/* Terminate the line. */
1210c3983b2SBen Gras 
1220c3983b2SBen Gras 						/* Skip leading space. */
1230c3983b2SBen Gras 		for (/*EMPTY*/; *p != '\0' && isspace((unsigned char)*p); ++p)
1240c3983b2SBen Gras 			continue;
1250c3983b2SBen Gras 						/* Skip empty/comment lines. */
1260c3983b2SBen Gras 		if (*p == '\0' || *p == '#')
1270c3983b2SBen Gras 			continue;
1280c3983b2SBen Gras 						/* Find first token. */
1290c3983b2SBen Gras 		for (t = p; *t && !isspace((unsigned char)*t); ++t)
1300c3983b2SBen Gras 			continue;
1310c3983b2SBen Gras 		if (*t == '\0')			/* Need more than one token.*/
1320c3983b2SBen Gras 			continue;
1330c3983b2SBen Gras 		*t = '\0';
1340c3983b2SBen Gras 
1350c3983b2SBen Gras 		tp = gettag(p, 1);
1360c3983b2SBen Gras 		if (!tp)
1370c3983b2SBen Gras 			errx(EXIT_FAILURE, "gettag: malloc failed");
1380c3983b2SBen Gras 
1390c3983b2SBen Gras 		/*
1400c3983b2SBen Gras 		 * Attach new records. Check to see if it is a
1410c3983b2SBen Gras 		 * section record or not.
1420c3983b2SBen Gras 		 */
1430c3983b2SBen Gras 
1440c3983b2SBen Gras 		if (*p == '_') {		/* not a section record */
1450c3983b2SBen Gras 			/*
1460c3983b2SBen Gras 			 * Special cases: _build and _crunch take the
1470c3983b2SBen Gras 			 * rest of the line as a single entry.
1480c3983b2SBen Gras 			 */
1490c3983b2SBen Gras 			if (!strcmp(p, "_build") || !strcmp(p, "_crunch")) {
150*0a6a1f1dSLionel Sambuc 				const char *u;
151*0a6a1f1dSLionel Sambuc 
1520c3983b2SBen Gras 				/*
1530c3983b2SBen Gras 				 * The reason we're not just using
1540c3983b2SBen Gras 				 * strtok(3) for all of the parsing is
1550c3983b2SBen Gras 				 * so we don't get caught if a line
1560c3983b2SBen Gras 				 * has only a single token on it.
1570c3983b2SBen Gras 				 */
1580c3983b2SBen Gras 				while (*++t && isspace((unsigned char)*t));
159*0a6a1f1dSLionel Sambuc #ifndef HAVE_NBTOOL_CONFIG_H
160*0a6a1f1dSLionel Sambuc 				/* pre-verify user-supplied command format */
161*0a6a1f1dSLionel Sambuc 				u = t;
162*0a6a1f1dSLionel Sambuc 				while (*u && !isspace((unsigned char)*u))
163*0a6a1f1dSLionel Sambuc 					++u;
164*0a6a1f1dSLionel Sambuc 				while (*u && isspace((unsigned char)*u))
165*0a6a1f1dSLionel Sambuc 					++u;
166*0a6a1f1dSLionel Sambuc 				if (fmtcheck(u, "%s") != u) {
167*0a6a1f1dSLionel Sambuc 					warnx("%s:%d: invalid %s command ignored",
168*0a6a1f1dSLionel Sambuc 					      fname, lcnt, p);
169*0a6a1f1dSLionel Sambuc 					continue;
170*0a6a1f1dSLionel Sambuc 				}
171*0a6a1f1dSLionel Sambuc #endif	/* !HAVE_NBTOOL_CONFIG_H */
1720c3983b2SBen Gras 				if (addentry(tp, t, 0) == -1)
1730c3983b2SBen Gras 					errx(EXIT_FAILURE,
1740c3983b2SBen Gras 					    "addentry: malloc failed");
1750c3983b2SBen Gras 			} else {
1760c3983b2SBen Gras 				for (++t; (p = strtok(t, " \t\n")) != NULL;
1770c3983b2SBen Gras 				     t = NULL) {
1780c3983b2SBen Gras 					if (addentry(tp, p, 0) == -1)
1790c3983b2SBen Gras 						errx(EXIT_FAILURE,
1800c3983b2SBen Gras 						   "addentry: malloc failed");
1810c3983b2SBen Gras 				}
1820c3983b2SBen Gras 			}
1830c3983b2SBen Gras 
1840c3983b2SBen Gras 		} else {			/* section record */
1850c3983b2SBen Gras 
1860c3983b2SBen Gras 			/*
1870c3983b2SBen Gras 			 * section entries can either be all absolute
1880c3983b2SBen Gras 			 * paths or all relative paths, but not both.
1890c3983b2SBen Gras 			 */
19084d9c625SLionel Sambuc 			type = (char)((TAILQ_FIRST(&tp->entrylist) != NULL) ?
19184d9c625SLionel Sambuc 			    *(TAILQ_FIRST(&tp->entrylist)->s) : '\0');
1920c3983b2SBen Gras 
1930c3983b2SBen Gras 			for (++t; (p = strtok(t, " \t\n")) != NULL; t = NULL) {
1940c3983b2SBen Gras 
1950c3983b2SBen Gras 				/* ensure an assigned type */
1960c3983b2SBen Gras 				if (type == 0)
1970c3983b2SBen Gras 					type = *p;
1980c3983b2SBen Gras 
1990c3983b2SBen Gras 				/* check for illegal mix */
2000c3983b2SBen Gras 				if (*p != type) {
2010c3983b2SBen Gras 	warnx("section %s: %s: invalid entry, does not match previous types",
2020c3983b2SBen Gras 	      tp->s, p);
2030c3983b2SBen Gras 	warnx("man.conf cannot mix absolute and relative paths in an entry");
2040c3983b2SBen Gras 					continue;
2050c3983b2SBen Gras 				}
2060c3983b2SBen Gras 				if (addentry(tp, p, 0) == -1)
2070c3983b2SBen Gras 					errx(EXIT_FAILURE,
2080c3983b2SBen Gras 					    "addentry: malloc failed");
2090c3983b2SBen Gras 			}
2100c3983b2SBen Gras 		}
2110c3983b2SBen Gras 	}
2120c3983b2SBen Gras 	(void)fclose(cfp);
2130c3983b2SBen Gras }
2140c3983b2SBen Gras 
2150c3983b2SBen Gras /*
2160c3983b2SBen Gras  * gettag --
2170c3983b2SBen Gras  *	if (!create) return tag for given name if it exists, or NULL otherwise
2180c3983b2SBen Gras  *
2190c3983b2SBen Gras  *	if (create) return tag for given name if it exists, try and create
2200c3983b2SBen Gras  *	a new tag if it does not exist.  return NULL if unable to create new
2210c3983b2SBen Gras  *	tag.
2220c3983b2SBen Gras  */
2230c3983b2SBen Gras TAG *
gettag(const char * name,int create)2240c3983b2SBen Gras gettag(const char *name, int create)
2250c3983b2SBen Gras {
2260c3983b2SBen Gras 	TAG *tp;
2270c3983b2SBen Gras 
2280c3983b2SBen Gras 	TAILQ_FOREACH(tp, &head, q)
2290c3983b2SBen Gras 		if (!strcmp(name, tp->s))
2300c3983b2SBen Gras 			return tp;
2310c3983b2SBen Gras 	if (!create)
2320c3983b2SBen Gras 		return NULL;
2330c3983b2SBen Gras 
2340c3983b2SBen Gras 	/* try and add it in */
2350c3983b2SBen Gras 	tp = malloc(sizeof(*tp));
2360c3983b2SBen Gras 	if (tp)
2370c3983b2SBen Gras 		tp->s = xstrdup(name, &tp->len);
2380c3983b2SBen Gras 	if (!tp || !tp->s) {
2390c3983b2SBen Gras 		if (tp)
2400c3983b2SBen Gras 			free(tp);
2410c3983b2SBen Gras 		return NULL;
2420c3983b2SBen Gras 	}
2430c3983b2SBen Gras 	TAILQ_INIT(&tp->entrylist);
2440c3983b2SBen Gras 	TAILQ_INSERT_TAIL(&head, tp, q);
2450c3983b2SBen Gras 	return tp;
2460c3983b2SBen Gras }
2470c3983b2SBen Gras 
2480c3983b2SBen Gras /*
2490c3983b2SBen Gras  * addentry --
2500c3983b2SBen Gras  *	add an entry to a list.
2510c3983b2SBen Gras  *	returns -1 if malloc failed, otherwise 0.
2520c3983b2SBen Gras  */
2530c3983b2SBen Gras int
addentry(TAG * tp,const char * newent,int ishead)2540c3983b2SBen Gras addentry(TAG *tp, const char *newent, int ishead)
2550c3983b2SBen Gras {
2560c3983b2SBen Gras 	ENTRY *ep;
2570c3983b2SBen Gras 
2580c3983b2SBen Gras 	ep = malloc(sizeof(*ep));
2590c3983b2SBen Gras 	if (ep)
2600c3983b2SBen Gras 		ep->s = xstrdup(newent, &ep->len);
2610c3983b2SBen Gras 	if (!ep || !ep->s) {
2620c3983b2SBen Gras 		if (ep)
2630c3983b2SBen Gras 			free(ep);
2640c3983b2SBen Gras 		return -1;
2650c3983b2SBen Gras 	}
2660c3983b2SBen Gras 	if (ishead)
2670c3983b2SBen Gras 		TAILQ_INSERT_HEAD(&tp->entrylist, ep, q);
2680c3983b2SBen Gras 	else
2690c3983b2SBen Gras 		TAILQ_INSERT_TAIL(&tp->entrylist, ep, q);
2700c3983b2SBen Gras 
2710c3983b2SBen Gras 	return 0;
2720c3983b2SBen Gras }
273