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