131702Sbostic /*
266644Spendry * Copyright (c) 1987, 1993, 1994
362098Sbostic * The Regents of the University of California. All rights reserved.
433054Sbostic *
542741Sbostic * %sccs.include.redist.c%
631702Sbostic */
731702Sbostic
831702Sbostic #ifndef lint
962098Sbostic static char copyright[] =
1066644Spendry "@(#) Copyright (c) 1987, 1993, 1994\n\
1162098Sbostic The Regents of the University of California. All rights reserved.\n";
1233054Sbostic #endif /* not lint */
1331702Sbostic
1431702Sbostic #ifndef lint
15*69226Sbostic static char sccsid[] = "@(#)apropos.c 8.8 (Berkeley) 05/04/95";
1633054Sbostic #endif /* not lint */
1731702Sbostic
1831702Sbostic #include <sys/param.h>
1965268Sbostic #include <sys/queue.h>
2065268Sbostic
2165268Sbostic #include <ctype.h>
2265268Sbostic #include <err.h>
2366566Spendry #include <limits.h>
2431702Sbostic #include <stdio.h>
2565268Sbostic #include <stdlib.h>
2642051Sbostic #include <string.h>
27*69226Sbostic #include <unistd.h>
2865268Sbostic
2965268Sbostic #include "../man/config.h"
3040389Sbostic #include "../man/pathnames.h"
3131702Sbostic
3242403Sbostic static int *found, foundman;
3342403Sbostic
3466566Spendry void apropos __P((char **, char *, int));
3566566Spendry void lowstr __P((char *, char *));
3666566Spendry int match __P((char *, char *));
3766566Spendry void usage __P((void));
3866566Spendry
3965268Sbostic int
main(argc,argv)4031702Sbostic main(argc, argv)
4133808Sbostic int argc;
4265268Sbostic char *argv[];
4331702Sbostic {
4465268Sbostic ENTRY *ep;
4565271Sbostic TAG *tp;
4665270Sbostic int ch, rv;
4765269Sbostic char *conffile, **p, *p_augment, *p_path;
4831702Sbostic
4965269Sbostic conffile = NULL;
5040389Sbostic p_augment = p_path = NULL;
5165269Sbostic while ((ch = getopt(argc, argv, "C:M:m:P:")) != EOF)
5265268Sbostic switch (ch) {
5365269Sbostic case 'C':
5465269Sbostic conffile = optarg;
5565269Sbostic break;
5635534Sbostic case 'M':
5735534Sbostic case 'P': /* backward compatible */
5840389Sbostic p_path = optarg;
5935534Sbostic break;
6040389Sbostic case 'm':
6140389Sbostic p_augment = optarg;
6240389Sbostic break;
6335534Sbostic case '?':
6435534Sbostic default:
6535534Sbostic usage();
6631702Sbostic }
6731702Sbostic argv += optind;
6831702Sbostic argc -= optind;
6940389Sbostic
7031702Sbostic if (argc < 1)
7131702Sbostic usage();
7231702Sbostic
7365270Sbostic if ((found = malloc((u_int)argc * sizeof(int))) == NULL)
7465268Sbostic err(1, NULL);
7565268Sbostic memset(found, 0, argc * sizeof(int));
7631702Sbostic
7735534Sbostic for (p = argv; *p; ++p) /* convert to lower-case */
7835534Sbostic lowstr(*p, *p);
7940389Sbostic
8040389Sbostic if (p_augment)
8142403Sbostic apropos(argv, p_augment, 1);
8242403Sbostic if (p_path || (p_path = getenv("MANPATH")))
8342403Sbostic apropos(argv, p_path, 1);
8465268Sbostic else {
8565269Sbostic config(conffile);
8665271Sbostic ep = (tp = getlist("_whatdb")) == NULL ?
8765271Sbostic NULL : tp->list.tqh_first;
8865271Sbostic for (; ep != NULL; ep = ep->q.tqe_next)
8965268Sbostic apropos(argv, ep->s, 0);
9065268Sbostic }
9142403Sbostic
9266566Spendry if (!foundman)
9366566Spendry errx(1, "no %s file found", _PATH_WHATIS);
9466566Spendry
9565270Sbostic rv = 1;
9640389Sbostic for (p = argv; *p; ++p)
9765270Sbostic if (found[p - argv])
9865270Sbostic rv = 0;
9965270Sbostic else
10040389Sbostic (void)printf("%s: nothing appropriate\n", *p);
10165270Sbostic exit(rv);
10240389Sbostic }
10340389Sbostic
10466566Spendry void
apropos(argv,path,buildpath)10542403Sbostic apropos(argv, path, buildpath)
10640389Sbostic char **argv, *path;
10742403Sbostic int buildpath;
10840389Sbostic {
10966566Spendry char *end, *name, **p;
11066566Spendry char buf[LINE_MAX + 1], wbuf[LINE_MAX + 1];
11140389Sbostic
11242403Sbostic for (name = path; name; name = end) { /* through name list */
11366566Spendry if (end = strchr(name, ':'))
11442403Sbostic *end++ = '\0';
11542403Sbostic
11642403Sbostic if (buildpath) {
11742403Sbostic char hold[MAXPATHLEN + 1];
11842403Sbostic
11942403Sbostic (void)sprintf(hold, "%s/%s", name, _PATH_WHATIS);
12042403Sbostic name = hold;
12131702Sbostic }
12242403Sbostic
12342403Sbostic if (!freopen(name, "r", stdin))
12433808Sbostic continue;
12533808Sbostic
12642403Sbostic foundman = 1;
12742403Sbostic
12835534Sbostic /* for each file found */
12942403Sbostic while (fgets(buf, sizeof(buf), stdin)) {
13066566Spendry if (!strchr(buf, '\n')) {
13166566Spendry warnx("%s: line too long", name);
13251191Sbostic continue;
13340389Sbostic }
13435534Sbostic lowstr(buf, wbuf);
13535534Sbostic for (p = argv; *p; ++p)
13635534Sbostic if (match(wbuf, *p)) {
13740389Sbostic (void)printf("%s", buf);
13835534Sbostic found[p - argv] = 1;
13931702Sbostic
14033808Sbostic /* only print line once */
14135534Sbostic while (*++p)
14235534Sbostic if (match(wbuf, *p))
14335534Sbostic found[p - argv] = 1;
14433808Sbostic break;
14533808Sbostic }
14631702Sbostic }
14731702Sbostic }
14831702Sbostic }
14931702Sbostic
15033808Sbostic /*
15135534Sbostic * match --
15235534Sbostic * match anywhere the string appears
15333808Sbostic */
15466566Spendry int
match(bp,str)15535534Sbostic match(bp, str)
15666566Spendry char *bp, *str;
15731702Sbostic {
15866566Spendry int len;
15966566Spendry char test;
16031702Sbostic
16131702Sbostic if (!*bp)
16266566Spendry return (0);
16333808Sbostic /* backward compatible: everything matches empty string */
16431702Sbostic if (!*str)
16566566Spendry return (1);
16633808Sbostic for (test = *str++, len = strlen(str); *bp;)
16733808Sbostic if (test == *bp++ && !strncmp(bp, str, len))
16866566Spendry return (1);
16966566Spendry return (0);
17031702Sbostic }
17131702Sbostic
17233808Sbostic /*
17333808Sbostic * lowstr --
17433808Sbostic * convert a string to lower case
17533808Sbostic */
17666566Spendry void
lowstr(from,to)17733808Sbostic lowstr(from, to)
17866566Spendry char *from, *to;
17933808Sbostic {
18066566Spendry char ch;
18135534Sbostic
18235534Sbostic while ((ch = *from++) && ch != '\n')
18335534Sbostic *to++ = isupper(ch) ? tolower(ch) : ch;
18435534Sbostic *to = '\0';
18533808Sbostic }
18633808Sbostic
18733808Sbostic /*
18833808Sbostic * usage --
18933808Sbostic * print usage message and die
19033808Sbostic */
19166566Spendry void
usage()19231702Sbostic usage()
19331702Sbostic {
19466566Spendry
19540389Sbostic (void)fprintf(stderr,
19665269Sbostic "usage: apropos [-C file] [-M path] [-m path] keyword ...\n");
19731702Sbostic exit(1);
19831702Sbostic }
199