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) 6/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: }