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