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