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