1*66601c7fSThomas Cort /* $NetBSD: whatis.c,v 1.24 2011/09/06 18:46:03 joerg Exp $ */
2*66601c7fSThomas Cort
3*66601c7fSThomas Cort /*
4*66601c7fSThomas Cort * Copyright (c) 1987, 1993
5*66601c7fSThomas Cort * The Regents of the University of California. All rights reserved.
6*66601c7fSThomas Cort *
7*66601c7fSThomas Cort * Redistribution and use in source and binary forms, with or without
8*66601c7fSThomas Cort * modification, are permitted provided that the following conditions
9*66601c7fSThomas Cort * are met:
10*66601c7fSThomas Cort * 1. Redistributions of source code must retain the above copyright
11*66601c7fSThomas Cort * notice, this list of conditions and the following disclaimer.
12*66601c7fSThomas Cort * 2. Redistributions in binary form must reproduce the above copyright
13*66601c7fSThomas Cort * notice, this list of conditions and the following disclaimer in the
14*66601c7fSThomas Cort * documentation and/or other materials provided with the distribution.
15*66601c7fSThomas Cort * 3. Neither the name of the University nor the names of its contributors
16*66601c7fSThomas Cort * may be used to endorse or promote products derived from this software
17*66601c7fSThomas Cort * without specific prior written permission.
18*66601c7fSThomas Cort *
19*66601c7fSThomas Cort * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*66601c7fSThomas Cort * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*66601c7fSThomas Cort * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*66601c7fSThomas Cort * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*66601c7fSThomas Cort * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*66601c7fSThomas Cort * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*66601c7fSThomas Cort * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*66601c7fSThomas Cort * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*66601c7fSThomas Cort * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*66601c7fSThomas Cort * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*66601c7fSThomas Cort * SUCH DAMAGE.
30*66601c7fSThomas Cort */
31*66601c7fSThomas Cort
32*66601c7fSThomas Cort #include <sys/cdefs.h>
33*66601c7fSThomas Cort
34*66601c7fSThomas Cort #ifndef lint
35*66601c7fSThomas Cort __COPYRIGHT("@(#) Copyright (c) 1987, 1993\
36*66601c7fSThomas Cort The Regents of the University of California. All rights reserved.");
37*66601c7fSThomas Cort #endif /* not lint */
38*66601c7fSThomas Cort
39*66601c7fSThomas Cort #ifndef lint
40*66601c7fSThomas Cort #if 0
41*66601c7fSThomas Cort static char sccsid[] = "@(#)whatis.c 8.5 (Berkeley) 1/2/94";
42*66601c7fSThomas Cort #else
43*66601c7fSThomas Cort __RCSID("$NetBSD: whatis.c,v 1.24 2011/09/06 18:46:03 joerg Exp $");
44*66601c7fSThomas Cort #endif
45*66601c7fSThomas Cort #endif /* not lint */
46*66601c7fSThomas Cort
47*66601c7fSThomas Cort #include <sys/param.h>
48*66601c7fSThomas Cort #include <sys/queue.h>
49*66601c7fSThomas Cort
50*66601c7fSThomas Cort #include <ctype.h>
51*66601c7fSThomas Cort #include <err.h>
52*66601c7fSThomas Cort #include <glob.h>
53*66601c7fSThomas Cort #include <stdio.h>
54*66601c7fSThomas Cort #include <stdlib.h>
55*66601c7fSThomas Cort #include <string.h>
56*66601c7fSThomas Cort #include <unistd.h>
57*66601c7fSThomas Cort
58*66601c7fSThomas Cort #include "manconf.h" /* from ../man/ */
59*66601c7fSThomas Cort #include "pathnames.h" /* from ../man/ */
60*66601c7fSThomas Cort
61*66601c7fSThomas Cort #define MAXLINELEN 8192 /* max line handled */
62*66601c7fSThomas Cort
63*66601c7fSThomas Cort static int *found, foundman;
64*66601c7fSThomas Cort
65*66601c7fSThomas Cort static void dashtrunc(char *, char *);
66*66601c7fSThomas Cort static int match(char *, char *);
67*66601c7fSThomas Cort __dead static void usage(void);
68*66601c7fSThomas Cort static void whatis(char **, char *, int);
69*66601c7fSThomas Cort
70*66601c7fSThomas Cort int
main(int argc,char ** argv)71*66601c7fSThomas Cort main(int argc, char **argv)
72*66601c7fSThomas Cort {
73*66601c7fSThomas Cort ENTRY *ep;
74*66601c7fSThomas Cort TAG *tp;
75*66601c7fSThomas Cort int ch, rv;
76*66601c7fSThomas Cort char *beg, *conffile, **p, *p_augment, *p_path;
77*66601c7fSThomas Cort glob_t pg;
78*66601c7fSThomas Cort
79*66601c7fSThomas Cort conffile = NULL;
80*66601c7fSThomas Cort p_augment = p_path = NULL;
81*66601c7fSThomas Cort while ((ch = getopt(argc, argv, "C:M:m:P:")) != -1)
82*66601c7fSThomas Cort switch (ch) {
83*66601c7fSThomas Cort case 'C':
84*66601c7fSThomas Cort conffile = optarg;
85*66601c7fSThomas Cort break;
86*66601c7fSThomas Cort case 'M':
87*66601c7fSThomas Cort case 'P': /* backward compatible */
88*66601c7fSThomas Cort p_path = optarg;
89*66601c7fSThomas Cort break;
90*66601c7fSThomas Cort case 'm':
91*66601c7fSThomas Cort p_augment = optarg;
92*66601c7fSThomas Cort break;
93*66601c7fSThomas Cort case '?':
94*66601c7fSThomas Cort default:
95*66601c7fSThomas Cort usage();
96*66601c7fSThomas Cort }
97*66601c7fSThomas Cort argv += optind;
98*66601c7fSThomas Cort argc -= optind;
99*66601c7fSThomas Cort
100*66601c7fSThomas Cort if (argc < 1)
101*66601c7fSThomas Cort usage();
102*66601c7fSThomas Cort
103*66601c7fSThomas Cort if ((found = malloc((u_int)argc * sizeof(int))) == NULL)
104*66601c7fSThomas Cort err(1, "malloc");
105*66601c7fSThomas Cort memset(found, 0, argc * sizeof(int));
106*66601c7fSThomas Cort
107*66601c7fSThomas Cort for (p = argv; *p; ++p) /* trim full paths */
108*66601c7fSThomas Cort if ((beg = strrchr(*p, '/')))
109*66601c7fSThomas Cort *p = beg + 1;
110*66601c7fSThomas Cort
111*66601c7fSThomas Cort if (p_augment)
112*66601c7fSThomas Cort whatis(argv, p_augment, 1);
113*66601c7fSThomas Cort if (p_path || (p_path = getenv("MANPATH")))
114*66601c7fSThomas Cort whatis(argv, p_path, 1);
115*66601c7fSThomas Cort else {
116*66601c7fSThomas Cort config(conffile);
117*66601c7fSThomas Cort tp = gettag("_whatdb", 0);
118*66601c7fSThomas Cort if (!tp)
119*66601c7fSThomas Cort errx(EXIT_FAILURE,
120*66601c7fSThomas Cort "no database dirs (_whatdb) in config file");
121*66601c7fSThomas Cort TAILQ_FOREACH(ep, &tp->entrylist, q) {
122*66601c7fSThomas Cort if ((rv = glob(ep->s, GLOB_BRACE | GLOB_NOSORT, NULL,
123*66601c7fSThomas Cort &pg)) != 0) {
124*66601c7fSThomas Cort if (rv == GLOB_NOMATCH)
125*66601c7fSThomas Cort continue;
126*66601c7fSThomas Cort else
127*66601c7fSThomas Cort err(EXIT_FAILURE, "glob");
128*66601c7fSThomas Cort }
129*66601c7fSThomas Cort if (pg.gl_pathc)
130*66601c7fSThomas Cort for (p = pg.gl_pathv; *p; p++)
131*66601c7fSThomas Cort whatis(argv, *p, 0);
132*66601c7fSThomas Cort globfree(&pg);
133*66601c7fSThomas Cort }
134*66601c7fSThomas Cort }
135*66601c7fSThomas Cort
136*66601c7fSThomas Cort if (!foundman) {
137*66601c7fSThomas Cort fprintf(stderr, "whatis: no %s file found.\n", _PATH_WHATIS);
138*66601c7fSThomas Cort exit(1);
139*66601c7fSThomas Cort }
140*66601c7fSThomas Cort rv = 1;
141*66601c7fSThomas Cort for (p = argv; *p; ++p)
142*66601c7fSThomas Cort if (found[p - argv])
143*66601c7fSThomas Cort rv = 0;
144*66601c7fSThomas Cort else
145*66601c7fSThomas Cort printf("%s: not found\n", *p);
146*66601c7fSThomas Cort exit(rv);
147*66601c7fSThomas Cort }
148*66601c7fSThomas Cort
149*66601c7fSThomas Cort static void
whatis(char ** argv,char * path,int buildpath)150*66601c7fSThomas Cort whatis(char **argv, char *path, int buildpath)
151*66601c7fSThomas Cort {
152*66601c7fSThomas Cort char *end, *name, **p;
153*66601c7fSThomas Cort char buf[MAXLINELEN + 1], wbuf[MAXLINELEN + 1];
154*66601c7fSThomas Cort char hold[MAXPATHLEN + 1];
155*66601c7fSThomas Cort
156*66601c7fSThomas Cort for (name = path; name; name = end) { /* through name list */
157*66601c7fSThomas Cort if ((end = strchr(name, ':')))
158*66601c7fSThomas Cort *end++ = '\0';
159*66601c7fSThomas Cort
160*66601c7fSThomas Cort if (buildpath) {
161*66601c7fSThomas Cort (void)sprintf(hold, "%s/%s", name, _PATH_WHATIS);
162*66601c7fSThomas Cort name = hold;
163*66601c7fSThomas Cort }
164*66601c7fSThomas Cort
165*66601c7fSThomas Cort if (!freopen(name, "r", stdin))
166*66601c7fSThomas Cort continue;
167*66601c7fSThomas Cort
168*66601c7fSThomas Cort foundman = 1;
169*66601c7fSThomas Cort
170*66601c7fSThomas Cort /* for each file found */
171*66601c7fSThomas Cort while (fgets(buf, sizeof(buf), stdin)) {
172*66601c7fSThomas Cort dashtrunc(buf, wbuf);
173*66601c7fSThomas Cort for (p = argv; *p; ++p)
174*66601c7fSThomas Cort if (match(wbuf, *p)) {
175*66601c7fSThomas Cort printf("%s", buf);
176*66601c7fSThomas Cort found[p - argv] = 1;
177*66601c7fSThomas Cort
178*66601c7fSThomas Cort /* only print line once */
179*66601c7fSThomas Cort while (*++p)
180*66601c7fSThomas Cort if (match(wbuf, *p))
181*66601c7fSThomas Cort found[p - argv] = 1;
182*66601c7fSThomas Cort break;
183*66601c7fSThomas Cort }
184*66601c7fSThomas Cort }
185*66601c7fSThomas Cort }
186*66601c7fSThomas Cort }
187*66601c7fSThomas Cort
188*66601c7fSThomas Cort /*
189*66601c7fSThomas Cort * match --
190*66601c7fSThomas Cort * match a full word
191*66601c7fSThomas Cort */
192*66601c7fSThomas Cort static int
match(char * bp,char * str)193*66601c7fSThomas Cort match(char *bp, char *str)
194*66601c7fSThomas Cort {
195*66601c7fSThomas Cort int len;
196*66601c7fSThomas Cort char *start;
197*66601c7fSThomas Cort
198*66601c7fSThomas Cort if (!*str || !*bp)
199*66601c7fSThomas Cort return(0);
200*66601c7fSThomas Cort for (len = strlen(str);;) {
201*66601c7fSThomas Cort /*
202*66601c7fSThomas Cort * /bin/[ is a special case.
203*66601c7fSThomas Cort */
204*66601c7fSThomas Cort for (; *bp && *bp != '[' && !isalnum((unsigned char)*bp); ++bp);
205*66601c7fSThomas Cort if (!*bp)
206*66601c7fSThomas Cort break;
207*66601c7fSThomas Cort
208*66601c7fSThomas Cort /* check for word match first */
209*66601c7fSThomas Cort for (start = bp++; *bp && (*bp == '_' ||
210*66601c7fSThomas Cort isalnum((unsigned char) *bp)); ++bp);
211*66601c7fSThomas Cort if (bp - start == len && strncasecmp(start, str, len) == 0) {
212*66601c7fSThomas Cort return(1);
213*66601c7fSThomas Cort } else if (*bp && *bp != ',') {
214*66601c7fSThomas Cort /* check for full string match */
215*66601c7fSThomas Cort for (bp = start; *bp && *bp != ',' && *bp != '(' &&
216*66601c7fSThomas Cort !isspace((unsigned char) *bp); ++bp);
217*66601c7fSThomas Cort if (bp - start == len &&
218*66601c7fSThomas Cort strncasecmp(start, str, len) == 0)
219*66601c7fSThomas Cort return(1);
220*66601c7fSThomas Cort }
221*66601c7fSThomas Cort }
222*66601c7fSThomas Cort return(0);
223*66601c7fSThomas Cort }
224*66601c7fSThomas Cort
225*66601c7fSThomas Cort /*
226*66601c7fSThomas Cort * dashtrunc --
227*66601c7fSThomas Cort * truncate a string at " - "
228*66601c7fSThomas Cort */
229*66601c7fSThomas Cort static void
dashtrunc(char * from,char * to)230*66601c7fSThomas Cort dashtrunc(char *from, char *to)
231*66601c7fSThomas Cort {
232*66601c7fSThomas Cort int ch;
233*66601c7fSThomas Cort
234*66601c7fSThomas Cort for (; (ch = *from) && ch != '\n' &&
235*66601c7fSThomas Cort (ch != ' ' || from[1] != '-' || from[2] != ' '); ++from)
236*66601c7fSThomas Cort *to++ = ch;
237*66601c7fSThomas Cort *to = '\0';
238*66601c7fSThomas Cort }
239*66601c7fSThomas Cort
240*66601c7fSThomas Cort /*
241*66601c7fSThomas Cort * usage --
242*66601c7fSThomas Cort * print usage message and die
243*66601c7fSThomas Cort */
244*66601c7fSThomas Cort static void
usage(void)245*66601c7fSThomas Cort usage(void)
246*66601c7fSThomas Cort {
247*66601c7fSThomas Cort (void)fprintf(stderr,
248*66601c7fSThomas Cort "usage: whatis [-C file] [-M path] [-m path] command ...\n");
249*66601c7fSThomas Cort exit(1);
250*66601c7fSThomas Cort }
251