1 /* 2 * Copyright (c) 1987, 1993 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\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.5 (Berkeley) 01/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 <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include "../man/config.h" 28 #include "../man/pathnames.h" 29 30 #define MAXLINELEN 1024 /* max line handled */ 31 32 static int *found, foundman; 33 34 int 35 main(argc, argv) 36 int argc; 37 char *argv[]; 38 { 39 extern char *optarg; 40 extern int optind; 41 ENTRY *ep; 42 TAG *tp; 43 int ch, rv; 44 char *conffile, **p, *p_augment, *p_path; 45 46 conffile = NULL; 47 p_augment = p_path = NULL; 48 while ((ch = getopt(argc, argv, "C:M:m:P:")) != EOF) 49 switch (ch) { 50 case 'C': 51 conffile = optarg; 52 break; 53 case 'M': 54 case 'P': /* backward compatible */ 55 p_path = optarg; 56 break; 57 case 'm': 58 p_augment = optarg; 59 break; 60 case '?': 61 default: 62 usage(); 63 } 64 argv += optind; 65 argc -= optind; 66 67 if (argc < 1) 68 usage(); 69 70 if ((found = malloc((u_int)argc * sizeof(int))) == NULL) 71 err(1, NULL); 72 memset(found, 0, argc * sizeof(int)); 73 74 for (p = argv; *p; ++p) /* convert to lower-case */ 75 lowstr(*p, *p); 76 77 if (p_augment) 78 apropos(argv, p_augment, 1); 79 if (p_path || (p_path = getenv("MANPATH"))) 80 apropos(argv, p_path, 1); 81 else { 82 config(conffile); 83 ep = (tp = getlist("_whatdb")) == NULL ? 84 NULL : tp->list.tqh_first; 85 for (; ep != NULL; ep = ep->q.tqe_next) 86 apropos(argv, ep->s, 0); 87 } 88 89 if (!foundman) { 90 (void)fprintf(stderr, 91 "apropos: no %s file found.\n", _PATH_WHATIS); 92 exit(1); 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 apropos(argv, path, buildpath) 104 char **argv, *path; 105 int buildpath; 106 { 107 register char *end, *name, **p; 108 char buf[MAXLINELEN + 1], wbuf[MAXLINELEN + 1]; 109 110 for (name = path; name; name = end) { /* through name list */ 111 if (end = index(name, ':')) 112 *end++ = '\0'; 113 114 if (buildpath) { 115 char hold[MAXPATHLEN + 1]; 116 117 (void)sprintf(hold, "%s/%s", name, _PATH_WHATIS); 118 name = hold; 119 } 120 121 if (!freopen(name, "r", stdin)) 122 continue; 123 124 foundman = 1; 125 126 /* for each file found */ 127 while (fgets(buf, sizeof(buf), stdin)) { 128 if (!index(buf, '\n')) { 129 (void)fprintf(stderr, 130 "apropos: %s line too long.\n", 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 match(bp, str) 154 register char *bp, *str; 155 { 156 register int len; 157 register char test; 158 159 if (!*bp) 160 return(0); 161 /* backward compatible: everything matches empty string */ 162 if (!*str) 163 return(1); 164 for (test = *str++, len = strlen(str); *bp;) 165 if (test == *bp++ && !strncmp(bp, str, len)) 166 return(1); 167 return(0); 168 } 169 170 /* 171 * lowstr -- 172 * convert a string to lower case 173 */ 174 lowstr(from, to) 175 register char *from, *to; 176 { 177 register char ch; 178 179 while ((ch = *from++) && ch != '\n') 180 *to++ = isupper(ch) ? tolower(ch) : ch; 181 *to = '\0'; 182 } 183 184 /* 185 * usage -- 186 * print usage message and die 187 */ 188 usage() 189 { 190 (void)fprintf(stderr, 191 "usage: apropos [-C file] [-M path] [-m path] keyword ...\n"); 192 exit(1); 193 } 194