xref: /csrg-svn/usr.bin/apropos/apropos.c (revision 31702)
1*31702Sbostic /*
2*31702Sbostic  * Copyright (c) 1987 Regents of the University of California.
3*31702Sbostic  * All rights reserved.  The Berkeley software License Agreement
4*31702Sbostic  * specifies the terms and conditions for redistribution.
5*31702Sbostic  */
6*31702Sbostic 
7*31702Sbostic #ifndef lint
8*31702Sbostic char copyright[] =
9*31702Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\
10*31702Sbostic  All rights reserved.\n";
11*31702Sbostic #endif not lint
12*31702Sbostic 
13*31702Sbostic #ifndef lint
14*31702Sbostic static char sccsid[] = "@(#)apropos.c	5.1 (Berkeley) 06/29/87";
15*31702Sbostic #endif not lint
16*31702Sbostic 
17*31702Sbostic #include <sys/param.h>
18*31702Sbostic #include <stdio.h>
19*31702Sbostic #include <ctype.h>
20*31702Sbostic 
21*31702Sbostic #define	DEF_PATH	"/usr/man"		/* default man path */
22*31702Sbostic #define	MAXLINELEN	500			/* max line handled */
23*31702Sbostic #define	NO		0			/* no/false */
24*31702Sbostic #define	WHATIS		"whatis"		/* database name */
25*31702Sbostic #define	YES		1			/* yes/true */
26*31702Sbostic 
27*31702Sbostic static char	*myname;
28*31702Sbostic 
29*31702Sbostic main(argc, argv)
30*31702Sbostic 	int	argc;
31*31702Sbostic 	char	**argv;
32*31702Sbostic {
33*31702Sbostic 	extern char	*optarg;
34*31702Sbostic 	extern int	optind;
35*31702Sbostic 	register char	*beg, *end, **C;
36*31702Sbostic 	int	ch, foundman = NO, *found, isapropos,
37*31702Sbostic 		a_match(), w_match(), (*match)();
38*31702Sbostic 	char	*manpath = NULL,
39*31702Sbostic 		buf[MAXLINELEN + 1], fname[MAXPATHLEN + 1],
40*31702Sbostic 		wbuf[MAXLINELEN + 1],
41*31702Sbostic 		*getenv(), *index(), *malloc(), *rindex();
42*31702Sbostic 
43*31702Sbostic 	myname = (beg = rindex(*argv, '/')) ? beg + 1 : *argv;
44*31702Sbostic 	if (!strcmp(myname, "apropos")) {
45*31702Sbostic 		isapropos = YES;
46*31702Sbostic 		match = a_match;
47*31702Sbostic 	}
48*31702Sbostic 	else {
49*31702Sbostic 		isapropos = NO;
50*31702Sbostic 		match = w_match;
51*31702Sbostic 	}
52*31702Sbostic 	while ((ch = getopt(argc, argv, "M:P:")) != EOF)
53*31702Sbostic 		switch((char)ch) {
54*31702Sbostic 			case 'M':
55*31702Sbostic 			case 'P':		/* backward contemptible */
56*31702Sbostic 				manpath = optarg;
57*31702Sbostic 				break;
58*31702Sbostic 			case '?':
59*31702Sbostic 			default:
60*31702Sbostic 				usage();
61*31702Sbostic 		}
62*31702Sbostic 	argv += optind;
63*31702Sbostic 	argc -= optind;
64*31702Sbostic 	if (argc < 1)
65*31702Sbostic 		usage();
66*31702Sbostic 
67*31702Sbostic 	if (!(manpath = getenv("MANPATH")))
68*31702Sbostic 		manpath = DEF_PATH;
69*31702Sbostic 
70*31702Sbostic 	/*NOSTRICT*/
71*31702Sbostic 	if (!(found = (int *)malloc((u_int)argc))) {
72*31702Sbostic 		fprintf(stderr, "%s: out of space.\n", myname);
73*31702Sbostic 		exit(1);
74*31702Sbostic 	}
75*31702Sbostic 	bzero(found, argc * sizeof(int));	/* calloc is silly */
76*31702Sbostic 
77*31702Sbostic 	if (!isapropos)
78*31702Sbostic 		for (C = argv; *C; ++C) {	/* trim full paths */
79*31702Sbostic 			if (beg = rindex(*C, '/'))
80*31702Sbostic 				*C = beg + 1;
81*31702Sbostic 		}
82*31702Sbostic 	for (C = argv; *C; ++C)			/* convert to lower-case */
83*31702Sbostic 		lowstr(*C, *C);
84*31702Sbostic 
85*31702Sbostic 	for (beg = manpath; beg; beg = end) {	/* through path list */
86*31702Sbostic 		end = index(beg, ':');
87*31702Sbostic 		if (!end)
88*31702Sbostic 			(void)sprintf(fname, "%s/%s", beg, WHATIS);
89*31702Sbostic 		else {
90*31702Sbostic 			(void)sprintf(fname, "%.*s/%s", end - beg, beg, WHATIS);
91*31702Sbostic 			++end;
92*31702Sbostic 		}
93*31702Sbostic 						/* for each file found */
94*31702Sbostic 		if (freopen(fname, "r", stdin)) {
95*31702Sbostic 			foundman = YES;
96*31702Sbostic 			while (gets(buf)) {	/* read & convert to lcase */
97*31702Sbostic 				lowstr(buf, wbuf);
98*31702Sbostic 				for (C = argv; *C; ++C)
99*31702Sbostic 					if ((*match)(wbuf, *C)) {
100*31702Sbostic 						puts(buf);
101*31702Sbostic 						found[C - argv] = YES;
102*31702Sbostic 
103*31702Sbostic 						/* only print line once */
104*31702Sbostic 						while (*++C)
105*31702Sbostic 							if ((*match)(wbuf, *C))
106*31702Sbostic 								found[C - argv] = YES;
107*31702Sbostic 						break;
108*31702Sbostic 					}
109*31702Sbostic 			}
110*31702Sbostic 		}
111*31702Sbostic 	}
112*31702Sbostic 	if (!foundman) {
113*31702Sbostic 		fprintf(stderr, "%s: no %s file found in %s.\n", myname, WHATIS, manpath);
114*31702Sbostic 		exit(1);
115*31702Sbostic 	}
116*31702Sbostic 	for (C = argv; *C; C++)
117*31702Sbostic 		if (!found[C - argv])
118*31702Sbostic 			printf("%s: %s\n", *C, isapropos ? "nothing appropriate" : "not found");
119*31702Sbostic }
120*31702Sbostic 
121*31702Sbostic static
122*31702Sbostic a_match(bp, str)
123*31702Sbostic 	register char	*bp, *str;
124*31702Sbostic {
125*31702Sbostic 	register char	test, *Cs, *Cb;
126*31702Sbostic 
127*31702Sbostic 	if (!*bp)
128*31702Sbostic 		return(NO);
129*31702Sbostic 	/* backward contemptible: everything matches empty string */
130*31702Sbostic 	if (!*str)
131*31702Sbostic 		return(YES);
132*31702Sbostic 	for (test = *str++; *bp;)
133*31702Sbostic 		if (test == *bp++) {
134*31702Sbostic 			Cs = str;
135*31702Sbostic 			Cb = bp;
136*31702Sbostic 			do {
137*31702Sbostic 				if (!*Cs)
138*31702Sbostic 					return(YES);
139*31702Sbostic 			} while (*Cb++ == *Cs++);
140*31702Sbostic 		}
141*31702Sbostic 	return(NO);
142*31702Sbostic }
143*31702Sbostic 
144*31702Sbostic static
145*31702Sbostic w_match(bp, str)
146*31702Sbostic 	register char	*bp, *str;
147*31702Sbostic {
148*31702Sbostic 	register char	test, *Cs, *Cb;
149*31702Sbostic 
150*31702Sbostic 	if (!*str || !*bp)
151*31702Sbostic 		return(NO);
152*31702Sbostic 	for (test = *str++; *bp;)
153*31702Sbostic 		if (test == *bp++) {
154*31702Sbostic 			for (Cs = str, Cb = bp; *Cs == *Cb; ++Cs, ++Cb);
155*31702Sbostic 			if (!*Cs && (isspace(*Cb) || *Cb == '(' || *Cb == ','))
156*31702Sbostic 				return(YES);
157*31702Sbostic 		}
158*31702Sbostic 	return(NO);
159*31702Sbostic }
160*31702Sbostic 
161*31702Sbostic static
162*31702Sbostic lowstr(from, to)
163*31702Sbostic 	register char	*from, *to;
164*31702Sbostic {
165*31702Sbostic 	for (; *from; ++from, ++to)
166*31702Sbostic 		*to = isupper(*from) ? tolower(*from) : *from;
167*31702Sbostic 	*to = '\0';
168*31702Sbostic }
169*31702Sbostic 
170*31702Sbostic static
171*31702Sbostic usage()
172*31702Sbostic {
173*31702Sbostic 	fprintf(stderr, "usage: %s [-M path] string ...\n", myname);
174*31702Sbostic 	exit(1);
175*31702Sbostic }
176*31702Sbostic 
177