1*0407c1b8Swiz /* $NetBSD: apropos.c,v 1.30 2009/05/08 12:48:43 wiz Exp $ */
20a334e76Sglass
344aa3887Scgd /*
46662274fSglass * Copyright (c) 1987, 1993, 1994
544aa3887Scgd * The Regents of the University of California. All rights reserved.
644aa3887Scgd *
744aa3887Scgd * Redistribution and use in source and binary forms, with or without
844aa3887Scgd * modification, are permitted provided that the following conditions
944aa3887Scgd * are met:
1044aa3887Scgd * 1. Redistributions of source code must retain the above copyright
1144aa3887Scgd * notice, this list of conditions and the following disclaimer.
1244aa3887Scgd * 2. Redistributions in binary form must reproduce the above copyright
1344aa3887Scgd * notice, this list of conditions and the following disclaimer in the
1444aa3887Scgd * documentation and/or other materials provided with the distribution.
1589aaa1bbSagc * 3. Neither the name of the University nor the names of its contributors
1644aa3887Scgd * may be used to endorse or promote products derived from this software
1744aa3887Scgd * without specific prior written permission.
1844aa3887Scgd *
1944aa3887Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2044aa3887Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2144aa3887Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2244aa3887Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2344aa3887Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2444aa3887Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2544aa3887Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2644aa3887Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2744aa3887Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2844aa3887Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2944aa3887Scgd * SUCH DAMAGE.
3044aa3887Scgd */
3144aa3887Scgd
329653f53eSmikel #include <sys/cdefs.h>
339653f53eSmikel
3444aa3887Scgd #ifndef lint
3598e5374cSlukem __COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\
3698e5374cSlukem The Regents of the University of California. All rights reserved.");
3744aa3887Scgd #endif /* not lint */
3844aa3887Scgd
3944aa3887Scgd #ifndef lint
400a334e76Sglass #if 0
41b1db8b26Stls static char sccsid[] = "@(#)apropos.c 8.8 (Berkeley) 5/4/95";
420a334e76Sglass #else
43*0407c1b8Swiz __RCSID("$NetBSD: apropos.c,v 1.30 2009/05/08 12:48:43 wiz Exp $");
440a334e76Sglass #endif
4544aa3887Scgd #endif /* not lint */
4644aa3887Scgd
4744aa3887Scgd #include <sys/param.h>
4844aa3887Scgd #include <sys/queue.h>
4944aa3887Scgd
5044aa3887Scgd #include <ctype.h>
5144aa3887Scgd #include <err.h>
52effc1539Smikel #include <glob.h>
536662274fSglass #include <limits.h>
546f6f89d2Schristos #include <stdbool.h>
5544aa3887Scgd #include <stdio.h>
5644aa3887Scgd #include <stdlib.h>
5744aa3887Scgd #include <string.h>
58b1db8b26Stls #include <unistd.h>
5944aa3887Scgd
603bcb486fSlukem #include "manconf.h" /* from ../man/ */
613bcb486fSlukem #include "pathnames.h" /* from ../man/ */
6244aa3887Scgd
636f6f89d2Schristos static bool *found;
646f6f89d2Schristos static bool foundman = false;
6544aa3887Scgd
6681a056bcSmrg #define MAXLINELEN 8192 /* max line handled */
6781a056bcSmrg
68*0407c1b8Swiz static void apropos(char **, const char *, bool, const char *, const char *);
69*0407c1b8Swiz static void lowstr(const char *, char *);
70*0407c1b8Swiz static bool match(const char *, const char *);
716f6f89d2Schristos static void usage(void) __dead;
726662274fSglass
7344aa3887Scgd int
main(int argc,char * argv[])74971b39dfSxtraeme main(int argc, char *argv[])
7544aa3887Scgd {
7644aa3887Scgd ENTRY *ep;
7744aa3887Scgd TAG *tp;
7844aa3887Scgd int ch, rv;
79*0407c1b8Swiz char *conffile, *machine, **p, *p_augment, *p_path, *sflag;
80effc1539Smikel glob_t pg;
8144aa3887Scgd
8244aa3887Scgd conffile = NULL;
8344aa3887Scgd p_augment = p_path = NULL;
84*0407c1b8Swiz machine = sflag = NULL;
85*0407c1b8Swiz while ((ch = getopt(argc, argv, "C:M:m:P:S:s:")) != -1) {
8644aa3887Scgd switch (ch) {
8744aa3887Scgd case 'C':
8844aa3887Scgd conffile = optarg;
8944aa3887Scgd break;
9044aa3887Scgd case 'M':
9144aa3887Scgd case 'P': /* backward compatible */
9244aa3887Scgd p_path = optarg;
9344aa3887Scgd break;
9444aa3887Scgd case 'm':
9544aa3887Scgd p_augment = optarg;
9644aa3887Scgd break;
97*0407c1b8Swiz case 'S':
98*0407c1b8Swiz machine = optarg;
99*0407c1b8Swiz lowstr(machine, machine);
100*0407c1b8Swiz break;
101*0407c1b8Swiz case 's':
102*0407c1b8Swiz sflag = optarg;
103*0407c1b8Swiz lowstr(sflag, sflag);
104*0407c1b8Swiz break;
10544aa3887Scgd case '?':
10644aa3887Scgd default:
10744aa3887Scgd usage();
10844aa3887Scgd }
1096f6f89d2Schristos }
11044aa3887Scgd argv += optind;
11144aa3887Scgd argc -= optind;
11244aa3887Scgd
11344aa3887Scgd if (argc < 1)
11444aa3887Scgd usage();
11544aa3887Scgd
1166f6f89d2Schristos if ((found = malloc(argc * sizeof(*found))) == NULL)
1176f6f89d2Schristos err(EXIT_FAILURE, "malloc");
1186f6f89d2Schristos (void)memset(found, 0, argc * sizeof(*found));
11944aa3887Scgd
12044aa3887Scgd for (p = argv; *p; ++p) /* convert to lower-case */
12144aa3887Scgd lowstr(*p, *p);
12244aa3887Scgd
12344aa3887Scgd if (p_augment)
124*0407c1b8Swiz apropos(argv, p_augment, true, sflag, machine);
12544aa3887Scgd if (p_path || (p_path = getenv("MANPATH")))
126*0407c1b8Swiz apropos(argv, p_path, true, sflag, machine);
12744aa3887Scgd else {
12844aa3887Scgd config(conffile);
129d09fe2c4Schuck tp = gettag("_whatdb", 1);
130d09fe2c4Schuck if (!tp)
131d09fe2c4Schuck errx(EXIT_FAILURE, "malloc");
132d09fe2c4Schuck TAILQ_FOREACH(ep, &tp->entrylist, q) {
133d39ba37cSkleink if ((rv = glob(ep->s, GLOB_BRACE | GLOB_NOSORT, NULL,
134d39ba37cSkleink &pg)) != 0) {
135d39ba37cSkleink if (rv == GLOB_NOMATCH)
136d39ba37cSkleink continue;
137d39ba37cSkleink else
1380f794d6dSjdolecek err(EXIT_FAILURE, "glob");
139d39ba37cSkleink }
14044fd5cbfSmikel if (pg.gl_pathc)
14144fd5cbfSmikel for (p = pg.gl_pathv; *p; p++)
142*0407c1b8Swiz apropos(argv, *p, false, sflag,
143*0407c1b8Swiz machine);
144effc1539Smikel globfree(&pg);
145effc1539Smikel }
14644aa3887Scgd }
14744aa3887Scgd
1486662274fSglass if (!foundman)
1496f6f89d2Schristos errx(EXIT_FAILURE, "no %s file found", _PATH_WHATIS);
1506662274fSglass
15144aa3887Scgd rv = 1;
15244aa3887Scgd for (p = argv; *p; ++p)
15344aa3887Scgd if (found[p - argv])
15444aa3887Scgd rv = 0;
15544aa3887Scgd else
15644aa3887Scgd (void)printf("%s: nothing appropriate\n", *p);
1576f6f89d2Schristos return rv;
15844aa3887Scgd }
15944aa3887Scgd
1606f6f89d2Schristos static void
apropos(char ** argv,const char * path,bool buildpath,const char * sflag,const char * machine)161*0407c1b8Swiz apropos(char **argv, const char *path, bool buildpath,
162*0407c1b8Swiz const char *sflag, const char *machine)
16344aa3887Scgd {
164*0407c1b8Swiz char *end, **p;
165*0407c1b8Swiz const char *name;
1666f6f89d2Schristos char buf[MAXLINELEN + 1];
1679653f53eSmikel char hold[MAXPATHLEN + 1];
1686f6f89d2Schristos char wbuf[MAXLINELEN + 1];
169*0407c1b8Swiz size_t slen = 0, mlen = 0;
170*0407c1b8Swiz
171*0407c1b8Swiz if (sflag)
172*0407c1b8Swiz slen = strlen(sflag);
173*0407c1b8Swiz if (machine)
174*0407c1b8Swiz mlen = strlen(machine);
17544aa3887Scgd
17644aa3887Scgd for (name = path; name; name = end) { /* through name list */
1776f6f89d2Schristos if ((end = strchr(name, ':')) != NULL)
17844aa3887Scgd *end++ = '\0';
17944aa3887Scgd
18044aa3887Scgd if (buildpath) {
181d09fe2c4Schuck (void)snprintf(hold, sizeof(hold), "%s/%s", name,
182d09fe2c4Schuck _PATH_WHATIS);
18344aa3887Scgd name = hold;
18444aa3887Scgd }
18544aa3887Scgd
18644aa3887Scgd if (!freopen(name, "r", stdin))
18744aa3887Scgd continue;
18844aa3887Scgd
1896f6f89d2Schristos foundman = true;
19044aa3887Scgd
19144aa3887Scgd /* for each file found */
1926f6f89d2Schristos while (fgets(buf, (int)sizeof(buf), stdin)) {
1936662274fSglass if (!strchr(buf, '\n')) {
1946662274fSglass warnx("%s: line too long", name);
19544aa3887Scgd continue;
19644aa3887Scgd }
19744aa3887Scgd lowstr(buf, wbuf);
198*0407c1b8Swiz if (machine) {
199*0407c1b8Swiz if ((strncmp(wbuf, machine, mlen) != 0) ||
200*0407c1b8Swiz strlen(wbuf) <= mlen || wbuf[mlen] != '/')
201*0407c1b8Swiz continue;
202*0407c1b8Swiz }
203*0407c1b8Swiz if (sflag) {
204*0407c1b8Swiz char *s = strchr(wbuf, '(');
205*0407c1b8Swiz
206*0407c1b8Swiz if (!s)
207*0407c1b8Swiz continue;
208*0407c1b8Swiz if (strncmp(s+1, sflag, slen) != 0)
209*0407c1b8Swiz continue;
210*0407c1b8Swiz }
2116f6f89d2Schristos for (p = argv; *p; ++p) {
21244aa3887Scgd if (match(wbuf, *p)) {
21344aa3887Scgd (void)printf("%s", buf);
2146f6f89d2Schristos found[p - argv] = true;
21544aa3887Scgd
21644aa3887Scgd /* only print line once */
21744aa3887Scgd while (*++p)
21844aa3887Scgd if (match(wbuf, *p))
2196f6f89d2Schristos found[p - argv] = true;
22044aa3887Scgd break;
22144aa3887Scgd }
22244aa3887Scgd }
22344aa3887Scgd }
22444aa3887Scgd }
2256f6f89d2Schristos }
22644aa3887Scgd
22744aa3887Scgd /*
22844aa3887Scgd * match --
22944aa3887Scgd * match anywhere the string appears
23044aa3887Scgd */
2316f6f89d2Schristos static bool
match(const char * bp,const char * str)232*0407c1b8Swiz match(const char *bp, const char *str)
23344aa3887Scgd {
2346f6f89d2Schristos size_t len;
2356662274fSglass char test;
23644aa3887Scgd
23744aa3887Scgd if (!*bp)
2386f6f89d2Schristos return false;
23944aa3887Scgd /* backward compatible: everything matches empty string */
24044aa3887Scgd if (!*str)
2416f6f89d2Schristos return true;
24244aa3887Scgd for (test = *str++, len = strlen(str); *bp;)
24344aa3887Scgd if (test == *bp++ && !strncmp(bp, str, len))
2446f6f89d2Schristos return true;
2456f6f89d2Schristos return false;
24644aa3887Scgd }
24744aa3887Scgd
24844aa3887Scgd /*
24944aa3887Scgd * lowstr --
25044aa3887Scgd * convert a string to lower case
25144aa3887Scgd */
2526f6f89d2Schristos static void
lowstr(const char * from,char * to)253*0407c1b8Swiz lowstr(const char *from, char *to)
25444aa3887Scgd {
2556662274fSglass char ch;
25644aa3887Scgd
25744aa3887Scgd while ((ch = *from++) && ch != '\n')
2583cca093eSdsl *to++ = tolower((unsigned char)ch);
25944aa3887Scgd *to = '\0';
26044aa3887Scgd }
26144aa3887Scgd
26244aa3887Scgd /*
26344aa3887Scgd * usage --
26444aa3887Scgd * print usage message and die
26544aa3887Scgd */
2666f6f89d2Schristos __dead
2676f6f89d2Schristos static void
usage(void)268971b39dfSxtraeme usage(void)
26944aa3887Scgd {
270a8ec668dScgd
27144aa3887Scgd (void)fprintf(stderr,
272*0407c1b8Swiz "usage: %s [-C file] [-M path] [-m path] "
273*0407c1b8Swiz "[-S subsection] [-s section]\n"
274*0407c1b8Swiz " keyword ...\n",
275a8ec668dScgd getprogname());
27644aa3887Scgd exit(1);
27744aa3887Scgd }
278