xref: /original-bsd/usr.bin/apropos/apropos.c (revision e58c8952)
1 /*
2  * Copyright (c) 1987, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1987, 1993, 1994\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)apropos.c	8.7 (Berkeley) 04/02/94";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/queue.h>
20 
21 #include <ctype.h>
22 #include <err.h>
23 #include <limits.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "../man/config.h"
29 #include "../man/pathnames.h"
30 
31 static int *found, foundman;
32 
33 void apropos __P((char **, char *, int));
34 void lowstr __P((char *, char *));
35 int match __P((char *, char *));
36 void usage __P((void));
37 
38 int
39 main(argc, argv)
40 	int argc;
41 	char *argv[];
42 {
43 	ENTRY *ep;
44 	TAG *tp;
45 	int ch, rv;
46 	char *conffile, **p, *p_augment, *p_path;
47 
48 	conffile = NULL;
49 	p_augment = p_path = NULL;
50 	while ((ch = getopt(argc, argv, "C:M:m:P:")) != EOF)
51 		switch (ch) {
52 		case 'C':
53 			conffile = optarg;
54 			break;
55 		case 'M':
56 		case 'P':		/* backward compatible */
57 			p_path = optarg;
58 			break;
59 		case 'm':
60 			p_augment = optarg;
61 			break;
62 		case '?':
63 		default:
64 			usage();
65 		}
66 	argv += optind;
67 	argc -= optind;
68 
69 	if (argc < 1)
70 		usage();
71 
72 	if ((found = malloc((u_int)argc * sizeof(int))) == NULL)
73 		err(1, NULL);
74 	memset(found, 0, argc * sizeof(int));
75 
76 	for (p = argv; *p; ++p)			/* convert to lower-case */
77 		lowstr(*p, *p);
78 
79 	if (p_augment)
80 		apropos(argv, p_augment, 1);
81 	if (p_path || (p_path = getenv("MANPATH")))
82 		apropos(argv, p_path, 1);
83 	else {
84 		config(conffile);
85 		ep = (tp = getlist("_whatdb")) == NULL ?
86 		    NULL : tp->list.tqh_first;
87 		for (; ep != NULL; ep = ep->q.tqe_next)
88 			apropos(argv, ep->s, 0);
89 	}
90 
91 	if (!foundman)
92 		errx(1, "no %s file found", _PATH_WHATIS);
93 
94 	rv = 1;
95 	for (p = argv; *p; ++p)
96 		if (found[p - argv])
97 			rv = 0;
98 		else
99 			(void)printf("%s: nothing appropriate\n", *p);
100 	exit(rv);
101 }
102 
103 void
104 apropos(argv, path, buildpath)
105 	char **argv, *path;
106 	int buildpath;
107 {
108 	char *end, *name, **p;
109 	char buf[LINE_MAX + 1], wbuf[LINE_MAX + 1];
110 
111 	for (name = path; name; name = end) {	/* through name list */
112 		if (end = strchr(name, ':'))
113 			*end++ = '\0';
114 
115 		if (buildpath) {
116 			char hold[MAXPATHLEN + 1];
117 
118 			(void)sprintf(hold, "%s/%s", name, _PATH_WHATIS);
119 			name = hold;
120 		}
121 
122 		if (!freopen(name, "r", stdin))
123 			continue;
124 
125 		foundman = 1;
126 
127 		/* for each file found */
128 		while (fgets(buf, sizeof(buf), stdin)) {
129 			if (!strchr(buf, '\n')) {
130 				warnx("%s: line too long", name);
131 				continue;
132 			}
133 			lowstr(buf, wbuf);
134 			for (p = argv; *p; ++p)
135 				if (match(wbuf, *p)) {
136 					(void)printf("%s", buf);
137 					found[p - argv] = 1;
138 
139 					/* only print line once */
140 					while (*++p)
141 						if (match(wbuf, *p))
142 							found[p - argv] = 1;
143 					break;
144 				}
145 		}
146 	}
147 }
148 
149 /*
150  * match --
151  *	match anywhere the string appears
152  */
153 int
154 match(bp, str)
155 	char *bp, *str;
156 {
157 	int len;
158 	char test;
159 
160 	if (!*bp)
161 		return (0);
162 	/* backward compatible: everything matches empty string */
163 	if (!*str)
164 		return (1);
165 	for (test = *str++, len = strlen(str); *bp;)
166 		if (test == *bp++ && !strncmp(bp, str, len))
167 			return (1);
168 	return (0);
169 }
170 
171 /*
172  * lowstr --
173  *	convert a string to lower case
174  */
175 void
176 lowstr(from, to)
177 	char *from, *to;
178 {
179 	char ch;
180 
181 	while ((ch = *from++) && ch != '\n')
182 		*to++ = isupper(ch) ? tolower(ch) : ch;
183 	*to = '\0';
184 }
185 
186 /*
187  * usage --
188  *	print usage message and die
189  */
190 void
191 usage()
192 {
193 
194 	(void)fprintf(stderr,
195 	    "usage: apropos [-C file] [-M path] [-m path] keyword ...\n");
196 	exit(1);
197 }
198