xref: /netbsd-src/usr.bin/whatis/whatis.c (revision 78eefffb5d7de212ad14c6309f940b881b90a441)
1*78eefffbSjoerg /*	$NetBSD: whatis.c,v 1.24 2011/09/06 18:46:03 joerg Exp $	*/
2c6f1b0a1Stls 
34b370535Scgd /*
44b370535Scgd  * Copyright (c) 1987, 1993
54b370535Scgd  *	The Regents of the University of California.  All rights reserved.
64b370535Scgd  *
74b370535Scgd  * Redistribution and use in source and binary forms, with or without
84b370535Scgd  * modification, are permitted provided that the following conditions
94b370535Scgd  * are met:
104b370535Scgd  * 1. Redistributions of source code must retain the above copyright
114b370535Scgd  *    notice, this list of conditions and the following disclaimer.
124b370535Scgd  * 2. Redistributions in binary form must reproduce the above copyright
134b370535Scgd  *    notice, this list of conditions and the following disclaimer in the
144b370535Scgd  *    documentation and/or other materials provided with the distribution.
1589aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
164b370535Scgd  *    may be used to endorse or promote products derived from this software
174b370535Scgd  *    without specific prior written permission.
184b370535Scgd  *
194b370535Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
204b370535Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
214b370535Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
224b370535Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
234b370535Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
244b370535Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
254b370535Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
264b370535Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
274b370535Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
284b370535Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
294b370535Scgd  * SUCH DAMAGE.
304b370535Scgd  */
314b370535Scgd 
324d52d27cSmikel #include <sys/cdefs.h>
334d52d27cSmikel 
344b370535Scgd #ifndef lint
3598e5374cSlukem __COPYRIGHT("@(#) Copyright (c) 1987, 1993\
3698e5374cSlukem  The Regents of the University of California.  All rights reserved.");
374b370535Scgd #endif /* not lint */
384b370535Scgd 
394b370535Scgd #ifndef lint
40c6f1b0a1Stls #if 0
41c6f1b0a1Stls static char sccsid[] = "@(#)whatis.c	8.5 (Berkeley) 1/2/94";
42c6f1b0a1Stls #else
43*78eefffbSjoerg __RCSID("$NetBSD: whatis.c,v 1.24 2011/09/06 18:46:03 joerg Exp $");
44c6f1b0a1Stls #endif
454b370535Scgd #endif /* not lint */
464b370535Scgd 
474b370535Scgd #include <sys/param.h>
484b370535Scgd #include <sys/queue.h>
494b370535Scgd 
504b370535Scgd #include <ctype.h>
514b370535Scgd #include <err.h>
52462a1eaeSmikel #include <glob.h>
534b370535Scgd #include <stdio.h>
544b370535Scgd #include <stdlib.h>
554b370535Scgd #include <string.h>
56cb9fa15aSperry #include <unistd.h>
574b370535Scgd 
583bcb486fSlukem #include "manconf.h"		/* from ../man/ */
593bcb486fSlukem #include "pathnames.h"		/* from ../man/ */
604b370535Scgd 
6181a056bcSmrg #define	MAXLINELEN	8192			/* max line handled */
624b370535Scgd 
634b370535Scgd static int *found, foundman;
644b370535Scgd 
65*78eefffbSjoerg static void	dashtrunc(char *, char *);
66*78eefffbSjoerg static int	match(char *, char *);
67*78eefffbSjoerg __dead static void	usage(void);
68*78eefffbSjoerg static void	whatis(char **, char *, int);
695720e226Sjtc 
704b370535Scgd int
main(int argc,char ** argv)71d09fe2c4Schuck main(int argc, char **argv)
724b370535Scgd {
734b370535Scgd 	ENTRY *ep;
744b370535Scgd 	TAG *tp;
754b370535Scgd 	int ch, rv;
764b370535Scgd 	char *beg, *conffile, **p, *p_augment, *p_path;
77462a1eaeSmikel 	glob_t pg;
784b370535Scgd 
794b370535Scgd 	conffile = NULL;
804b370535Scgd 	p_augment = p_path = NULL;
813e8e7446Slukem 	while ((ch = getopt(argc, argv, "C:M:m:P:")) != -1)
824b370535Scgd 		switch (ch) {
834b370535Scgd 		case 'C':
844b370535Scgd 			conffile = optarg;
854b370535Scgd 			break;
864b370535Scgd 		case 'M':
874b370535Scgd 		case 'P':		/* backward compatible */
884b370535Scgd 			p_path = optarg;
894b370535Scgd 			break;
904b370535Scgd 		case 'm':
914b370535Scgd 			p_augment = optarg;
924b370535Scgd 			break;
934b370535Scgd 		case '?':
944b370535Scgd 		default:
954b370535Scgd 			usage();
964b370535Scgd 		}
974b370535Scgd 	argv += optind;
984b370535Scgd 	argc -= optind;
994b370535Scgd 
1004b370535Scgd 	if (argc < 1)
1014b370535Scgd 		usage();
1024b370535Scgd 
1034b370535Scgd 	if ((found = malloc((u_int)argc * sizeof(int))) == NULL)
1044d52d27cSmikel 		err(1, "malloc");
1054b370535Scgd 	memset(found, 0, argc * sizeof(int));
1064b370535Scgd 
1074b370535Scgd 	for (p = argv; *p; ++p)			/* trim full paths */
1084d52d27cSmikel 		if ((beg = strrchr(*p, '/')))
1094b370535Scgd 			*p = beg + 1;
1104b370535Scgd 
1114b370535Scgd 	if (p_augment)
1124b370535Scgd 		whatis(argv, p_augment, 1);
1134b370535Scgd 	if (p_path || (p_path = getenv("MANPATH")))
1144b370535Scgd 		whatis(argv, p_path, 1);
1154b370535Scgd 	else {
1164b370535Scgd 		config(conffile);
117d09fe2c4Schuck 		tp = gettag("_whatdb", 0);
118d09fe2c4Schuck 		if (!tp)
119d09fe2c4Schuck 			errx(EXIT_FAILURE,
120d09fe2c4Schuck 			    "no database dirs (_whatdb) in config file");
121d09fe2c4Schuck 		TAILQ_FOREACH(ep, &tp->entrylist, q) {
122d39ba37cSkleink 			if ((rv = glob(ep->s, GLOB_BRACE | GLOB_NOSORT, NULL,
123d39ba37cSkleink 			    &pg)) != 0) {
124d39ba37cSkleink 				if (rv == GLOB_NOMATCH)
125d39ba37cSkleink 					continue;
126d39ba37cSkleink 				else
1270f794d6dSjdolecek 					err(EXIT_FAILURE, "glob");
128d39ba37cSkleink 			}
129dfd29394Smikel 			if (pg.gl_pathc)
130462a1eaeSmikel 				for (p = pg.gl_pathv; *p; p++)
131462a1eaeSmikel 					whatis(argv, *p, 0);
132462a1eaeSmikel 			globfree(&pg);
133462a1eaeSmikel 		}
1344b370535Scgd 	}
1354b370535Scgd 
1364b370535Scgd 	if (!foundman) {
1374b370535Scgd 		fprintf(stderr, "whatis: no %s file found.\n", _PATH_WHATIS);
1384b370535Scgd 		exit(1);
1394b370535Scgd 	}
1404b370535Scgd 	rv = 1;
1414b370535Scgd 	for (p = argv; *p; ++p)
1424b370535Scgd 		if (found[p - argv])
1434b370535Scgd 			rv = 0;
1444b370535Scgd 		else
1454b370535Scgd 			printf("%s: not found\n", *p);
1464b370535Scgd 	exit(rv);
1474b370535Scgd }
1484b370535Scgd 
149*78eefffbSjoerg static void
whatis(char ** argv,char * path,int buildpath)150d09fe2c4Schuck whatis(char **argv, char *path, int buildpath)
1514b370535Scgd {
152451d258eSlukem 	char *end, *name, **p;
1534b370535Scgd 	char buf[MAXLINELEN + 1], wbuf[MAXLINELEN + 1];
1544d52d27cSmikel 	char hold[MAXPATHLEN + 1];
1554b370535Scgd 
1564b370535Scgd 	for (name = path; name; name = end) {	/* through name list */
1574d52d27cSmikel 		if ((end = strchr(name, ':')))
1584b370535Scgd 			*end++ = '\0';
1594b370535Scgd 
1604b370535Scgd 		if (buildpath) {
1614b370535Scgd 			(void)sprintf(hold, "%s/%s", name, _PATH_WHATIS);
1624b370535Scgd 			name = hold;
1634b370535Scgd 		}
1644b370535Scgd 
1654b370535Scgd 		if (!freopen(name, "r", stdin))
1664b370535Scgd 			continue;
1674b370535Scgd 
1684b370535Scgd 		foundman = 1;
1694b370535Scgd 
1704b370535Scgd 		/* for each file found */
1714b370535Scgd 		while (fgets(buf, sizeof(buf), stdin)) {
1724b370535Scgd 			dashtrunc(buf, wbuf);
1734b370535Scgd 			for (p = argv; *p; ++p)
1744b370535Scgd 				if (match(wbuf, *p)) {
1754b370535Scgd 					printf("%s", buf);
1764b370535Scgd 					found[p - argv] = 1;
1774b370535Scgd 
1784b370535Scgd 					/* only print line once */
1794b370535Scgd 					while (*++p)
1804b370535Scgd 						if (match(wbuf, *p))
1814b370535Scgd 							found[p - argv] = 1;
1824b370535Scgd 					break;
1834b370535Scgd 				}
1844b370535Scgd 		}
1854b370535Scgd 	}
1864b370535Scgd }
1874b370535Scgd 
1884b370535Scgd /*
1894b370535Scgd  * match --
1904b370535Scgd  *	match a full word
1914b370535Scgd  */
192*78eefffbSjoerg static int
match(char * bp,char * str)193d09fe2c4Schuck match(char *bp, char *str)
1944b370535Scgd {
195451d258eSlukem 	int len;
196451d258eSlukem 	char *start;
1974b370535Scgd 
1984b370535Scgd 	if (!*str || !*bp)
1994b370535Scgd 		return(0);
2004b370535Scgd 	for (len = strlen(str);;) {
201e606ac2dSrpaulo 		/*
202e606ac2dSrpaulo 		 * /bin/[ is a special case.
203e606ac2dSrpaulo 		 */
204e606ac2dSrpaulo 		for (; *bp && *bp != '[' && !isalnum((unsigned char)*bp); ++bp);
2054b370535Scgd 		if (!*bp)
2064b370535Scgd 			break;
207ce560c1eSdaniel 
208ce560c1eSdaniel 		/* check for word match first */
209ce560c1eSdaniel 		for (start = bp++; *bp && (*bp == '_' ||
210ce560c1eSdaniel 			isalnum((unsigned char) *bp)); ++bp);
211ce560c1eSdaniel 		if (bp - start == len && strncasecmp(start, str, len) == 0) {
2124b370535Scgd 			return(1);
213ce560c1eSdaniel 		} else if (*bp && *bp != ',') {
214ce560c1eSdaniel 			/* check for full string match */
215ce560c1eSdaniel 			for (bp = start; *bp && *bp != ',' && *bp != '(' &&
216ce560c1eSdaniel 				!isspace((unsigned char) *bp); ++bp);
217ce560c1eSdaniel 			if (bp - start == len &&
218ce560c1eSdaniel 				strncasecmp(start, str, len) == 0)
219ce560c1eSdaniel 				return(1);
220ce560c1eSdaniel 		}
2214b370535Scgd 	}
2224b370535Scgd 	return(0);
2234b370535Scgd }
2244b370535Scgd 
2254b370535Scgd /*
2264b370535Scgd  * dashtrunc --
2274b370535Scgd  *	truncate a string at " - "
2284b370535Scgd  */
229*78eefffbSjoerg static void
dashtrunc(char * from,char * to)230d09fe2c4Schuck dashtrunc(char *from, char *to)
2314b370535Scgd {
232451d258eSlukem 	int ch;
2334b370535Scgd 
2344b370535Scgd 	for (; (ch = *from) && ch != '\n' &&
2354b370535Scgd 	    (ch != ' ' || from[1] != '-' || from[2] != ' '); ++from)
2364b370535Scgd 		*to++ = ch;
2374b370535Scgd 	*to = '\0';
2384b370535Scgd }
2394b370535Scgd 
2404b370535Scgd /*
2414b370535Scgd  * usage --
2424b370535Scgd  *	print usage message and die
2434b370535Scgd  */
244*78eefffbSjoerg static void
usage(void)245d09fe2c4Schuck usage(void)
2464b370535Scgd {
2474b370535Scgd 	(void)fprintf(stderr,
2484b370535Scgd 	    "usage: whatis [-C file] [-M path] [-m path] command ...\n");
2494b370535Scgd 	exit(1);
2504b370535Scgd }
251