1*84d9c625SLionel Sambuc /* $NetBSD: manconf.c,v 1.7 2013/07/18 15:39:08 christos 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*84d9c625SLionel Sambuc __RCSID("$NetBSD: manconf.c,v 1.7 2013/07/18 15:39:08 christos 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 * 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 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")) { 1500c3983b2SBen Gras /* 1510c3983b2SBen Gras * The reason we're not just using 1520c3983b2SBen Gras * strtok(3) for all of the parsing is 1530c3983b2SBen Gras * so we don't get caught if a line 1540c3983b2SBen Gras * has only a single token on it. 1550c3983b2SBen Gras */ 1560c3983b2SBen Gras while (*++t && isspace((unsigned char)*t)); 1570c3983b2SBen Gras if (addentry(tp, t, 0) == -1) 1580c3983b2SBen Gras errx(EXIT_FAILURE, 1590c3983b2SBen Gras "addentry: malloc failed"); 1600c3983b2SBen Gras } else { 1610c3983b2SBen Gras for (++t; (p = strtok(t, " \t\n")) != NULL; 1620c3983b2SBen Gras t = NULL) { 1630c3983b2SBen Gras if (addentry(tp, p, 0) == -1) 1640c3983b2SBen Gras errx(EXIT_FAILURE, 1650c3983b2SBen Gras "addentry: malloc failed"); 1660c3983b2SBen Gras } 1670c3983b2SBen Gras } 1680c3983b2SBen Gras 1690c3983b2SBen Gras } else { /* section record */ 1700c3983b2SBen Gras 1710c3983b2SBen Gras /* 1720c3983b2SBen Gras * section entries can either be all absolute 1730c3983b2SBen Gras * paths or all relative paths, but not both. 1740c3983b2SBen Gras */ 175*84d9c625SLionel Sambuc type = (char)((TAILQ_FIRST(&tp->entrylist) != NULL) ? 176*84d9c625SLionel Sambuc *(TAILQ_FIRST(&tp->entrylist)->s) : '\0'); 1770c3983b2SBen Gras 1780c3983b2SBen Gras for (++t; (p = strtok(t, " \t\n")) != NULL; t = NULL) { 1790c3983b2SBen Gras 1800c3983b2SBen Gras /* ensure an assigned type */ 1810c3983b2SBen Gras if (type == 0) 1820c3983b2SBen Gras type = *p; 1830c3983b2SBen Gras 1840c3983b2SBen Gras /* check for illegal mix */ 1850c3983b2SBen Gras if (*p != type) { 1860c3983b2SBen Gras warnx("section %s: %s: invalid entry, does not match previous types", 1870c3983b2SBen Gras tp->s, p); 1880c3983b2SBen Gras warnx("man.conf cannot mix absolute and relative paths in an entry"); 1890c3983b2SBen Gras continue; 1900c3983b2SBen Gras } 1910c3983b2SBen Gras if (addentry(tp, p, 0) == -1) 1920c3983b2SBen Gras errx(EXIT_FAILURE, 1930c3983b2SBen Gras "addentry: malloc failed"); 1940c3983b2SBen Gras } 1950c3983b2SBen Gras } 1960c3983b2SBen Gras } 1970c3983b2SBen Gras (void)fclose(cfp); 1980c3983b2SBen Gras } 1990c3983b2SBen Gras 2000c3983b2SBen Gras /* 2010c3983b2SBen Gras * gettag -- 2020c3983b2SBen Gras * if (!create) return tag for given name if it exists, or NULL otherwise 2030c3983b2SBen Gras * 2040c3983b2SBen Gras * if (create) return tag for given name if it exists, try and create 2050c3983b2SBen Gras * a new tag if it does not exist. return NULL if unable to create new 2060c3983b2SBen Gras * tag. 2070c3983b2SBen Gras */ 2080c3983b2SBen Gras TAG * 2090c3983b2SBen Gras gettag(const char *name, int create) 2100c3983b2SBen Gras { 2110c3983b2SBen Gras TAG *tp; 2120c3983b2SBen Gras 2130c3983b2SBen Gras TAILQ_FOREACH(tp, &head, q) 2140c3983b2SBen Gras if (!strcmp(name, tp->s)) 2150c3983b2SBen Gras return tp; 2160c3983b2SBen Gras if (!create) 2170c3983b2SBen Gras return NULL; 2180c3983b2SBen Gras 2190c3983b2SBen Gras /* try and add it in */ 2200c3983b2SBen Gras tp = malloc(sizeof(*tp)); 2210c3983b2SBen Gras if (tp) 2220c3983b2SBen Gras tp->s = xstrdup(name, &tp->len); 2230c3983b2SBen Gras if (!tp || !tp->s) { 2240c3983b2SBen Gras if (tp) 2250c3983b2SBen Gras free(tp); 2260c3983b2SBen Gras return NULL; 2270c3983b2SBen Gras } 2280c3983b2SBen Gras TAILQ_INIT(&tp->entrylist); 2290c3983b2SBen Gras TAILQ_INSERT_TAIL(&head, tp, q); 2300c3983b2SBen Gras return tp; 2310c3983b2SBen Gras } 2320c3983b2SBen Gras 2330c3983b2SBen Gras /* 2340c3983b2SBen Gras * addentry -- 2350c3983b2SBen Gras * add an entry to a list. 2360c3983b2SBen Gras * returns -1 if malloc failed, otherwise 0. 2370c3983b2SBen Gras */ 2380c3983b2SBen Gras int 2390c3983b2SBen Gras addentry(TAG *tp, const char *newent, int ishead) 2400c3983b2SBen Gras { 2410c3983b2SBen Gras ENTRY *ep; 2420c3983b2SBen Gras 2430c3983b2SBen Gras ep = malloc(sizeof(*ep)); 2440c3983b2SBen Gras if (ep) 2450c3983b2SBen Gras ep->s = xstrdup(newent, &ep->len); 2460c3983b2SBen Gras if (!ep || !ep->s) { 2470c3983b2SBen Gras if (ep) 2480c3983b2SBen Gras free(ep); 2490c3983b2SBen Gras return -1; 2500c3983b2SBen Gras } 2510c3983b2SBen Gras if (ishead) 2520c3983b2SBen Gras TAILQ_INSERT_HEAD(&tp->entrylist, ep, q); 2530c3983b2SBen Gras else 2540c3983b2SBen Gras TAILQ_INSERT_TAIL(&tp->entrylist, ep, q); 2550c3983b2SBen Gras 2560c3983b2SBen Gras return 0; 2570c3983b2SBen Gras } 258