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