1 /* 2 * Copyright (c) 1987 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 */ 12 13 #ifndef lint 14 char copyright[] = 15 "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 16 All rights reserved.\n"; 17 #endif /* not lint */ 18 19 #ifndef lint 20 static char sccsid[] = "@(#)apropos.c 5.5 (Berkeley) 03/28/88"; 21 #endif /* not lint */ 22 23 #include <sys/param.h> 24 #include <stdio.h> 25 #include <ctype.h> 26 #include <strings.h> 27 28 #define DEF_PATH "/usr/man:/usr/new/man:/usr/local/man" 29 #define MAXLINELEN 1000 /* max line handled */ 30 #define WHATIS "whatis" /* database name */ 31 32 #define NO 0 /* no/false */ 33 #define YES 1 /* yes/true */ 34 35 static char *myname; 36 37 main(argc, argv) 38 int argc; 39 char **argv; 40 { 41 extern char *optarg; 42 extern int optind; 43 register char *beg, *end, **C; 44 int ch, foundman = NO, *found, isapropos; 45 int a_match(), w_match(), (*match)(); 46 char *manpath = NULL, buf[MAXLINELEN + 1], fname[MAXPATHLEN + 1]; 47 char wbuf[MAXLINELEN + 1], *getenv(), *malloc(); 48 49 myname = (beg = rindex(*argv, '/')) ? beg + 1 : *argv; 50 if (!strcmp(myname, "apropos")) { 51 isapropos = YES; 52 match = a_match; 53 } 54 else { 55 isapropos = NO; 56 match = w_match; 57 } 58 while ((ch = getopt(argc, argv, "M:P:")) != EOF) 59 switch((char)ch) { 60 case 'M': 61 case 'P': /* backward contemptible */ 62 manpath = optarg; 63 break; 64 case '?': 65 default: 66 usage(); 67 } 68 argv += optind; 69 argc -= optind; 70 if (argc < 1) 71 usage(); 72 73 if (!(manpath = getenv("MANPATH"))) 74 manpath = DEF_PATH; 75 76 /*NOSTRICT*/ 77 if (!(found = (int *)malloc((u_int)argc))) { 78 fprintf(stderr, "%s: out of space.\n", myname); 79 exit(1); 80 } 81 bzero((char *)found, argc * sizeof(int)); 82 83 if (isapropos) 84 for (C = argv; *C; ++C) /* convert to lower-case */ 85 lowstr(*C, *C); 86 else for (C = argv; *C; ++C) /* trim full paths */ 87 if (beg = rindex(*C, '/')) 88 *C = beg + 1; 89 90 for (beg = manpath; beg; beg = end) { /* through path list */ 91 end = index(beg, ':'); 92 if (!end) 93 (void)sprintf(fname, "%s/%s", beg, WHATIS); 94 else { 95 (void)sprintf(fname, "%.*s/%s", end - beg, beg, WHATIS); 96 ++end; 97 } 98 if (!freopen(fname, "r", stdin)) 99 continue; 100 101 /* for each file found */ 102 for (foundman = YES; gets(buf);) { 103 if (isapropos) 104 lowstr(buf, wbuf); 105 else 106 dashtrunc(buf, wbuf); 107 for (C = argv; *C; ++C) 108 if ((*match)(wbuf, *C)) { 109 puts(buf); 110 found[C - argv] = YES; 111 112 /* only print line once */ 113 while (*++C) 114 if ((*match)(wbuf, *C)) 115 found[C - argv] = YES; 116 break; 117 } 118 } 119 } 120 if (!foundman) { 121 fprintf(stderr, "%s: no %s file found in %s.\n", myname, WHATIS, manpath); 122 exit(1); 123 } 124 for (C = argv; *C; ++C) 125 if (!found[C - argv]) 126 printf("%s: %s\n", *C, isapropos ? "nothing appropriate" : "not found"); 127 } 128 129 /* 130 * a_match -- 131 * match for apropos; anywhere the string appears 132 */ 133 static 134 a_match(bp, str) 135 register char *bp, *str; 136 { 137 register int len; 138 register char test; 139 140 if (!*bp) 141 return(NO); 142 /* backward compatible: everything matches empty string */ 143 if (!*str) 144 return(YES); 145 for (test = *str++, len = strlen(str); *bp;) 146 if (test == *bp++ && !strncmp(bp, str, len)) 147 return(YES); 148 return(NO); 149 } 150 151 /* 152 * w_match -- 153 * match for whatis; looks for full word match 154 */ 155 static 156 w_match(bp, str) 157 register char *bp, *str; 158 { 159 register int len; 160 register char *start; 161 162 if (!*str || !*bp) 163 return(NO); 164 for (len = strlen(str);;) { 165 for (; *bp && !isdigit(*bp) && !isalpha(*bp); ++bp); 166 if (!*bp) 167 break; 168 for (start = bp++; *bp && (isdigit(*bp) || isalpha(*bp)); ++bp); 169 if (bp - start == len && !strncasecmp(start, str, len)) 170 return(YES); 171 } 172 return(NO); 173 } 174 175 /* 176 * dashtrunc -- 177 * truncate a string at " - " 178 */ 179 static 180 dashtrunc(from, to) 181 register char *from, *to; 182 { 183 do { 184 if (from[0] == ' ' && from[1] == '-' && from[2] == ' ') 185 break; 186 } while (*to++ = *from++); 187 *to = '\0'; 188 } 189 190 /* 191 * lowstr -- 192 * convert a string to lower case 193 */ 194 static 195 lowstr(from, to) 196 register char *from, *to; 197 { 198 do { 199 *to++ = isupper(*from) ? tolower(*from) : *from; 200 } while (*from++); 201 } 202 203 /* 204 * usage -- 205 * print usage message and die 206 */ 207 static 208 usage() 209 { 210 fprintf(stderr, "usage: %s [-M path] string ...\n", myname); 211 exit(1); 212 } 213