| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: apropos.c,v 1.29 2008/07/21 14:19:20 lukem Exp $ */ | | 1 | /* $NetBSD: apropos.c,v 1.30 2009/05/08 12:48:43 wiz Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1987, 1993, 1994 | | 4 | * Copyright (c) 1987, 1993, 1994 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -30,215 +30,248 @@ | | | @@ -30,215 +30,248 @@ |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | | | 33 | |
34 | #ifndef lint | | 34 | #ifndef lint |
35 | __COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\ | | 35 | __COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\ |
36 | The Regents of the University of California. All rights reserved."); | | 36 | The Regents of the University of California. All rights reserved."); |
37 | #endif /* not lint */ | | 37 | #endif /* not lint */ |
38 | | | 38 | |
39 | #ifndef lint | | 39 | #ifndef lint |
40 | #if 0 | | 40 | #if 0 |
41 | static char sccsid[] = "@(#)apropos.c 8.8 (Berkeley) 5/4/95"; | | 41 | static char sccsid[] = "@(#)apropos.c 8.8 (Berkeley) 5/4/95"; |
42 | #else | | 42 | #else |
43 | __RCSID("$NetBSD: apropos.c,v 1.29 2008/07/21 14:19:20 lukem Exp $"); | | 43 | __RCSID("$NetBSD: apropos.c,v 1.30 2009/05/08 12:48:43 wiz Exp $"); |
44 | #endif | | 44 | #endif |
45 | #endif /* not lint */ | | 45 | #endif /* not lint */ |
46 | | | 46 | |
47 | #include <sys/param.h> | | 47 | #include <sys/param.h> |
48 | #include <sys/queue.h> | | 48 | #include <sys/queue.h> |
49 | | | 49 | |
50 | #include <ctype.h> | | 50 | #include <ctype.h> |
51 | #include <err.h> | | 51 | #include <err.h> |
52 | #include <glob.h> | | 52 | #include <glob.h> |
53 | #include <limits.h> | | 53 | #include <limits.h> |
54 | #include <stdbool.h> | | 54 | #include <stdbool.h> |
55 | #include <stdio.h> | | 55 | #include <stdio.h> |
56 | #include <stdlib.h> | | 56 | #include <stdlib.h> |
57 | #include <string.h> | | 57 | #include <string.h> |
58 | #include <unistd.h> | | 58 | #include <unistd.h> |
59 | | | 59 | |
60 | #include "manconf.h" /* from ../man/ */ | | 60 | #include "manconf.h" /* from ../man/ */ |
61 | #include "pathnames.h" /* from ../man/ */ | | 61 | #include "pathnames.h" /* from ../man/ */ |
62 | | | 62 | |
63 | static bool *found; | | 63 | static bool *found; |
64 | static bool foundman = false; | | 64 | static bool foundman = false; |
65 | | | 65 | |
66 | #define MAXLINELEN 8192 /* max line handled */ | | 66 | #define MAXLINELEN 8192 /* max line handled */ |
67 | | | 67 | |
68 | static void apropos(char **, char *, bool); | | 68 | static void apropos(char **, const char *, bool, const char *, const char *); |
69 | static void lowstr(char *, char *); | | 69 | static void lowstr(const char *, char *); |
70 | static bool match(char *, char *); | | 70 | static bool match(const char *, const char *); |
71 | static void usage(void) __dead; | | 71 | static void usage(void) __dead; |
72 | | | 72 | |
73 | int | | 73 | int |
74 | main(int argc, char *argv[]) | | 74 | main(int argc, char *argv[]) |
75 | { | | 75 | { |
76 | ENTRY *ep; | | 76 | ENTRY *ep; |
77 | TAG *tp; | | 77 | TAG *tp; |
78 | int ch, rv; | | 78 | int ch, rv; |
79 | char *conffile, **p, *p_augment, *p_path; | | 79 | char *conffile, *machine, **p, *p_augment, *p_path, *sflag; |
80 | glob_t pg; | | 80 | glob_t pg; |
81 | | | 81 | |
82 | conffile = NULL; | | 82 | conffile = NULL; |
83 | p_augment = p_path = NULL; | | 83 | p_augment = p_path = NULL; |
84 | while ((ch = getopt(argc, argv, "C:M:m:P:")) != -1) { | | 84 | machine = sflag = NULL; |
| | | 85 | while ((ch = getopt(argc, argv, "C:M:m:P:S:s:")) != -1) { |
85 | switch (ch) { | | 86 | switch (ch) { |
86 | case 'C': | | 87 | case 'C': |
87 | conffile = optarg; | | 88 | conffile = optarg; |
88 | break; | | 89 | break; |
89 | case 'M': | | 90 | case 'M': |
90 | case 'P': /* backward compatible */ | | 91 | case 'P': /* backward compatible */ |
91 | p_path = optarg; | | 92 | p_path = optarg; |
92 | break; | | 93 | break; |
93 | case 'm': | | 94 | case 'm': |
94 | p_augment = optarg; | | 95 | p_augment = optarg; |
95 | break; | | 96 | break; |
| | | 97 | case 'S': |
| | | 98 | machine = optarg; |
| | | 99 | lowstr(machine, machine); |
| | | 100 | break; |
| | | 101 | case 's': |
| | | 102 | sflag = optarg; |
| | | 103 | lowstr(sflag, sflag); |
| | | 104 | break; |
96 | case '?': | | 105 | case '?': |
97 | default: | | 106 | default: |
98 | usage(); | | 107 | usage(); |
99 | } | | 108 | } |
100 | } | | 109 | } |
101 | argv += optind; | | 110 | argv += optind; |
102 | argc -= optind; | | 111 | argc -= optind; |
103 | | | 112 | |
104 | if (argc < 1) | | 113 | if (argc < 1) |
105 | usage(); | | 114 | usage(); |
106 | | | 115 | |
107 | if ((found = malloc(argc * sizeof(*found))) == NULL) | | 116 | if ((found = malloc(argc * sizeof(*found))) == NULL) |
108 | err(EXIT_FAILURE, "malloc"); | | 117 | err(EXIT_FAILURE, "malloc"); |
109 | (void)memset(found, 0, argc * sizeof(*found)); | | 118 | (void)memset(found, 0, argc * sizeof(*found)); |
110 | | | 119 | |
111 | for (p = argv; *p; ++p) /* convert to lower-case */ | | 120 | for (p = argv; *p; ++p) /* convert to lower-case */ |
112 | lowstr(*p, *p); | | 121 | lowstr(*p, *p); |
113 | | | 122 | |
114 | if (p_augment) | | 123 | if (p_augment) |
115 | apropos(argv, p_augment, true); | | 124 | apropos(argv, p_augment, true, sflag, machine); |
116 | if (p_path || (p_path = getenv("MANPATH"))) | | 125 | if (p_path || (p_path = getenv("MANPATH"))) |
117 | apropos(argv, p_path, true); | | 126 | apropos(argv, p_path, true, sflag, machine); |
118 | else { | | 127 | else { |
119 | config(conffile); | | 128 | config(conffile); |
120 | tp = gettag("_whatdb", 1); | | 129 | tp = gettag("_whatdb", 1); |
121 | if (!tp) | | 130 | if (!tp) |
122 | errx(EXIT_FAILURE, "malloc"); | | 131 | errx(EXIT_FAILURE, "malloc"); |
123 | TAILQ_FOREACH(ep, &tp->entrylist, q) { | | 132 | TAILQ_FOREACH(ep, &tp->entrylist, q) { |
124 | if ((rv = glob(ep->s, GLOB_BRACE | GLOB_NOSORT, NULL, | | 133 | if ((rv = glob(ep->s, GLOB_BRACE | GLOB_NOSORT, NULL, |
125 | &pg)) != 0) { | | 134 | &pg)) != 0) { |
126 | if (rv == GLOB_NOMATCH) | | 135 | if (rv == GLOB_NOMATCH) |
127 | continue; | | 136 | continue; |
128 | else | | 137 | else |
129 | err(EXIT_FAILURE, "glob"); | | 138 | err(EXIT_FAILURE, "glob"); |
130 | } | | 139 | } |
131 | if (pg.gl_pathc) | | 140 | if (pg.gl_pathc) |
132 | for (p = pg.gl_pathv; *p; p++) | | 141 | for (p = pg.gl_pathv; *p; p++) |
133 | apropos(argv, *p, false); | | 142 | apropos(argv, *p, false, sflag, |
| | | 143 | machine); |
134 | globfree(&pg); | | 144 | globfree(&pg); |
135 | } | | 145 | } |
136 | } | | 146 | } |
137 | | | 147 | |
138 | if (!foundman) | | 148 | if (!foundman) |
139 | errx(EXIT_FAILURE, "no %s file found", _PATH_WHATIS); | | 149 | errx(EXIT_FAILURE, "no %s file found", _PATH_WHATIS); |
140 | | | 150 | |
141 | rv = 1; | | 151 | rv = 1; |
142 | for (p = argv; *p; ++p) | | 152 | for (p = argv; *p; ++p) |
143 | if (found[p - argv]) | | 153 | if (found[p - argv]) |
144 | rv = 0; | | 154 | rv = 0; |
145 | else | | 155 | else |
146 | (void)printf("%s: nothing appropriate\n", *p); | | 156 | (void)printf("%s: nothing appropriate\n", *p); |
147 | return rv; | | 157 | return rv; |
148 | } | | 158 | } |
149 | | | 159 | |
150 | static void | | 160 | static void |
151 | apropos(char **argv, char *path, bool buildpath) | | 161 | apropos(char **argv, const char *path, bool buildpath, |
| | | 162 | const char *sflag, const char *machine) |
152 | { | | 163 | { |
153 | char *end, *name, **p; | | 164 | char *end, **p; |
| | | 165 | const char *name; |
154 | char buf[MAXLINELEN + 1]; | | 166 | char buf[MAXLINELEN + 1]; |
155 | char hold[MAXPATHLEN + 1]; | | 167 | char hold[MAXPATHLEN + 1]; |
156 | char wbuf[MAXLINELEN + 1]; | | 168 | char wbuf[MAXLINELEN + 1]; |
| | | 169 | size_t slen = 0, mlen = 0; |
| | | 170 | |
| | | 171 | if (sflag) |
| | | 172 | slen = strlen(sflag); |
| | | 173 | if (machine) |
| | | 174 | mlen = strlen(machine); |
157 | | | 175 | |
158 | for (name = path; name; name = end) { /* through name list */ | | 176 | for (name = path; name; name = end) { /* through name list */ |
159 | if ((end = strchr(name, ':')) != NULL) | | 177 | if ((end = strchr(name, ':')) != NULL) |
160 | *end++ = '\0'; | | 178 | *end++ = '\0'; |
161 | | | 179 | |
162 | if (buildpath) { | | 180 | if (buildpath) { |
163 | (void)snprintf(hold, sizeof(hold), "%s/%s", name, | | 181 | (void)snprintf(hold, sizeof(hold), "%s/%s", name, |
164 | _PATH_WHATIS); | | 182 | _PATH_WHATIS); |
165 | name = hold; | | 183 | name = hold; |
166 | } | | 184 | } |
167 | | | 185 | |
168 | if (!freopen(name, "r", stdin)) | | 186 | if (!freopen(name, "r", stdin)) |
169 | continue; | | 187 | continue; |
170 | | | 188 | |
171 | foundman = true; | | 189 | foundman = true; |
172 | | | 190 | |
173 | /* for each file found */ | | 191 | /* for each file found */ |
174 | while (fgets(buf, (int)sizeof(buf), stdin)) { | | 192 | while (fgets(buf, (int)sizeof(buf), stdin)) { |
175 | if (!strchr(buf, '\n')) { | | 193 | if (!strchr(buf, '\n')) { |
176 | warnx("%s: line too long", name); | | 194 | warnx("%s: line too long", name); |
177 | continue; | | 195 | continue; |
178 | } | | 196 | } |
179 | lowstr(buf, wbuf); | | 197 | lowstr(buf, wbuf); |
| | | 198 | if (machine) { |
| | | 199 | if ((strncmp(wbuf, machine, mlen) != 0) || |
| | | 200 | strlen(wbuf) <= mlen || wbuf[mlen] != '/') |
| | | 201 | continue; |
| | | 202 | } |
| | | 203 | if (sflag) { |
| | | 204 | char *s = strchr(wbuf, '('); |
| | | 205 | |
| | | 206 | if (!s) |
| | | 207 | continue; |
| | | 208 | if (strncmp(s+1, sflag, slen) != 0) |
| | | 209 | continue; |
| | | 210 | } |
180 | for (p = argv; *p; ++p) { | | 211 | for (p = argv; *p; ++p) { |
181 | if (match(wbuf, *p)) { | | 212 | if (match(wbuf, *p)) { |
182 | (void)printf("%s", buf); | | 213 | (void)printf("%s", buf); |
183 | found[p - argv] = true; | | 214 | found[p - argv] = true; |
184 | | | 215 | |
185 | /* only print line once */ | | 216 | /* only print line once */ |
186 | while (*++p) | | 217 | while (*++p) |
187 | if (match(wbuf, *p)) | | 218 | if (match(wbuf, *p)) |
188 | found[p - argv] = true; | | 219 | found[p - argv] = true; |
189 | break; | | 220 | break; |
190 | } | | 221 | } |
191 | } | | 222 | } |
192 | } | | 223 | } |
193 | } | | 224 | } |
194 | } | | 225 | } |
195 | | | 226 | |
196 | /* | | 227 | /* |
197 | * match -- | | 228 | * match -- |
198 | * match anywhere the string appears | | 229 | * match anywhere the string appears |
199 | */ | | 230 | */ |
200 | static bool | | 231 | static bool |
201 | match(char *bp, char *str) | | 232 | match(const char *bp, const char *str) |
202 | { | | 233 | { |
203 | size_t len; | | 234 | size_t len; |
204 | char test; | | 235 | char test; |
205 | | | 236 | |
206 | if (!*bp) | | 237 | if (!*bp) |
207 | return false; | | 238 | return false; |
208 | /* backward compatible: everything matches empty string */ | | 239 | /* backward compatible: everything matches empty string */ |
209 | if (!*str) | | 240 | if (!*str) |
210 | return true; | | 241 | return true; |
211 | for (test = *str++, len = strlen(str); *bp;) | | 242 | for (test = *str++, len = strlen(str); *bp;) |
212 | if (test == *bp++ && !strncmp(bp, str, len)) | | 243 | if (test == *bp++ && !strncmp(bp, str, len)) |
213 | return true; | | 244 | return true; |
214 | return false; | | 245 | return false; |
215 | } | | 246 | } |
216 | | | 247 | |
217 | /* | | 248 | /* |
218 | * lowstr -- | | 249 | * lowstr -- |
219 | * convert a string to lower case | | 250 | * convert a string to lower case |
220 | */ | | 251 | */ |
221 | static void | | 252 | static void |
222 | lowstr(char *from, char *to) | | 253 | lowstr(const char *from, char *to) |
223 | { | | 254 | { |
224 | char ch; | | 255 | char ch; |
225 | | | 256 | |
226 | while ((ch = *from++) && ch != '\n') | | 257 | while ((ch = *from++) && ch != '\n') |
227 | *to++ = tolower((unsigned char)ch); | | 258 | *to++ = tolower((unsigned char)ch); |
228 | *to = '\0'; | | 259 | *to = '\0'; |
229 | } | | 260 | } |
230 | | | 261 | |
231 | /* | | 262 | /* |
232 | * usage -- | | 263 | * usage -- |
233 | * print usage message and die | | 264 | * print usage message and die |
234 | */ | | 265 | */ |
235 | __dead | | 266 | __dead |
236 | static void | | 267 | static void |
237 | usage(void) | | 268 | usage(void) |
238 | { | | 269 | { |
239 | | | 270 | |
240 | (void)fprintf(stderr, | | 271 | (void)fprintf(stderr, |
241 | "usage: %s [-C file] [-M path] [-m path] keyword ...\n", | | 272 | "usage: %s [-C file] [-M path] [-m path] " |
| | | 273 | "[-S subsection] [-s section]\n" |
| | | 274 | " keyword ...\n", |
242 | getprogname()); | | 275 | getprogname()); |
243 | exit(1); | | 276 | exit(1); |
244 | } | | 277 | } |