131702Sbostic /* 231702Sbostic * Copyright (c) 1987 Regents of the University of California. 333054Sbostic * All rights reserved. 433054Sbostic * 533054Sbostic * Redistribution and use in source and binary forms are permitted 633054Sbostic * provided that this notice is preserved and that due credit is given 733054Sbostic * to the University of California at Berkeley. The name of the University 833054Sbostic * may not be used to endorse or promote products derived from this 933054Sbostic * software without specific prior written permission. This software 1033054Sbostic * is provided ``as is'' without express or implied warranty. 1131702Sbostic */ 1231702Sbostic 1331702Sbostic #ifndef lint 1431702Sbostic char copyright[] = 1531702Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 1631702Sbostic All rights reserved.\n"; 1733054Sbostic #endif /* not lint */ 1831702Sbostic 1931702Sbostic #ifndef lint 20*33808Sbostic static char sccsid[] = "@(#)apropos.c 5.5 (Berkeley) 03/28/88"; 2133054Sbostic #endif /* not lint */ 2231702Sbostic 2331702Sbostic #include <sys/param.h> 2431702Sbostic #include <stdio.h> 2531702Sbostic #include <ctype.h> 26*33808Sbostic #include <strings.h> 2731702Sbostic 2831974Sbostic #define DEF_PATH "/usr/man:/usr/new/man:/usr/local/man" 2931712Sbostic #define MAXLINELEN 1000 /* max line handled */ 3031702Sbostic #define WHATIS "whatis" /* database name */ 3131702Sbostic 32*33808Sbostic #define NO 0 /* no/false */ 33*33808Sbostic #define YES 1 /* yes/true */ 3431702Sbostic 35*33808Sbostic static char *myname; 36*33808Sbostic 3731702Sbostic main(argc, argv) 38*33808Sbostic int argc; 39*33808Sbostic char **argv; 4031702Sbostic { 41*33808Sbostic extern char *optarg; 42*33808Sbostic extern int optind; 43*33808Sbostic register char *beg, *end, **C; 44*33808Sbostic int ch, foundman = NO, *found, isapropos; 45*33808Sbostic int a_match(), w_match(), (*match)(); 46*33808Sbostic char *manpath = NULL, buf[MAXLINELEN + 1], fname[MAXPATHLEN + 1]; 47*33808Sbostic char wbuf[MAXLINELEN + 1], *getenv(), *malloc(); 4831702Sbostic 4931702Sbostic myname = (beg = rindex(*argv, '/')) ? beg + 1 : *argv; 5031702Sbostic if (!strcmp(myname, "apropos")) { 5131702Sbostic isapropos = YES; 5231702Sbostic match = a_match; 5331702Sbostic } 5431702Sbostic else { 5531702Sbostic isapropos = NO; 5631702Sbostic match = w_match; 5731702Sbostic } 5831702Sbostic while ((ch = getopt(argc, argv, "M:P:")) != EOF) 5931702Sbostic switch((char)ch) { 6031702Sbostic case 'M': 6131702Sbostic case 'P': /* backward contemptible */ 6231702Sbostic manpath = optarg; 6331702Sbostic break; 6431702Sbostic case '?': 6531702Sbostic default: 6631702Sbostic usage(); 6731702Sbostic } 6831702Sbostic argv += optind; 6931702Sbostic argc -= optind; 7031702Sbostic if (argc < 1) 7131702Sbostic usage(); 7231702Sbostic 7331702Sbostic if (!(manpath = getenv("MANPATH"))) 7431702Sbostic manpath = DEF_PATH; 7531702Sbostic 7631702Sbostic /*NOSTRICT*/ 7731702Sbostic if (!(found = (int *)malloc((u_int)argc))) { 7831702Sbostic fprintf(stderr, "%s: out of space.\n", myname); 7931702Sbostic exit(1); 8031702Sbostic } 81*33808Sbostic bzero((char *)found, argc * sizeof(int)); 8231702Sbostic 83*33808Sbostic if (isapropos) 84*33808Sbostic for (C = argv; *C; ++C) /* convert to lower-case */ 85*33808Sbostic lowstr(*C, *C); 86*33808Sbostic else for (C = argv; *C; ++C) /* trim full paths */ 87*33808Sbostic if (beg = rindex(*C, '/')) 88*33808Sbostic *C = beg + 1; 8931702Sbostic 9031702Sbostic for (beg = manpath; beg; beg = end) { /* through path list */ 9131702Sbostic end = index(beg, ':'); 9231702Sbostic if (!end) 9331702Sbostic (void)sprintf(fname, "%s/%s", beg, WHATIS); 9431702Sbostic else { 9531702Sbostic (void)sprintf(fname, "%.*s/%s", end - beg, beg, WHATIS); 9631702Sbostic ++end; 9731702Sbostic } 98*33808Sbostic if (!freopen(fname, "r", stdin)) 99*33808Sbostic continue; 100*33808Sbostic 10131702Sbostic /* for each file found */ 102*33808Sbostic for (foundman = YES; gets(buf);) { 103*33808Sbostic if (isapropos) 10431702Sbostic lowstr(buf, wbuf); 105*33808Sbostic else 106*33808Sbostic dashtrunc(buf, wbuf); 107*33808Sbostic for (C = argv; *C; ++C) 108*33808Sbostic if ((*match)(wbuf, *C)) { 109*33808Sbostic puts(buf); 110*33808Sbostic found[C - argv] = YES; 11131702Sbostic 112*33808Sbostic /* only print line once */ 113*33808Sbostic while (*++C) 114*33808Sbostic if ((*match)(wbuf, *C)) 115*33808Sbostic found[C - argv] = YES; 116*33808Sbostic break; 117*33808Sbostic } 11831702Sbostic } 11931702Sbostic } 12031702Sbostic if (!foundman) { 12131702Sbostic fprintf(stderr, "%s: no %s file found in %s.\n", myname, WHATIS, manpath); 12231702Sbostic exit(1); 12331702Sbostic } 124*33808Sbostic for (C = argv; *C; ++C) 12531702Sbostic if (!found[C - argv]) 12631702Sbostic printf("%s: %s\n", *C, isapropos ? "nothing appropriate" : "not found"); 12731702Sbostic } 12831702Sbostic 129*33808Sbostic /* 130*33808Sbostic * a_match -- 131*33808Sbostic * match for apropos; anywhere the string appears 132*33808Sbostic */ 13331702Sbostic static 13431702Sbostic a_match(bp, str) 135*33808Sbostic register char *bp, *str; 13631702Sbostic { 137*33808Sbostic register int len; 138*33808Sbostic register char test; 13931702Sbostic 14031702Sbostic if (!*bp) 14131702Sbostic return(NO); 142*33808Sbostic /* backward compatible: everything matches empty string */ 14331702Sbostic if (!*str) 14431702Sbostic return(YES); 145*33808Sbostic for (test = *str++, len = strlen(str); *bp;) 146*33808Sbostic if (test == *bp++ && !strncmp(bp, str, len)) 147*33808Sbostic return(YES); 14831702Sbostic return(NO); 14931702Sbostic } 15031702Sbostic 151*33808Sbostic /* 152*33808Sbostic * w_match -- 153*33808Sbostic * match for whatis; looks for full word match 154*33808Sbostic */ 15531702Sbostic static 15631702Sbostic w_match(bp, str) 157*33808Sbostic register char *bp, *str; 15831702Sbostic { 159*33808Sbostic register int len; 160*33808Sbostic register char *start; 16131702Sbostic 16231702Sbostic if (!*str || !*bp) 16331702Sbostic return(NO); 164*33808Sbostic for (len = strlen(str);;) { 165*33808Sbostic for (; *bp && !isdigit(*bp) && !isalpha(*bp); ++bp); 166*33808Sbostic if (!*bp) 167*33808Sbostic break; 168*33808Sbostic for (start = bp++; *bp && (isdigit(*bp) || isalpha(*bp)); ++bp); 169*33808Sbostic if (bp - start == len && !strncasecmp(start, str, len)) 170*33808Sbostic return(YES); 171*33808Sbostic } 17231702Sbostic return(NO); 17331702Sbostic } 17431702Sbostic 175*33808Sbostic /* 176*33808Sbostic * dashtrunc -- 177*33808Sbostic * truncate a string at " - " 178*33808Sbostic */ 17931702Sbostic static 180*33808Sbostic dashtrunc(from, to) 181*33808Sbostic register char *from, *to; 18231702Sbostic { 183*33808Sbostic do { 184*33808Sbostic if (from[0] == ' ' && from[1] == '-' && from[2] == ' ') 185*33808Sbostic break; 186*33808Sbostic } while (*to++ = *from++); 18731702Sbostic *to = '\0'; 18831702Sbostic } 18931702Sbostic 190*33808Sbostic /* 191*33808Sbostic * lowstr -- 192*33808Sbostic * convert a string to lower case 193*33808Sbostic */ 19431702Sbostic static 195*33808Sbostic lowstr(from, to) 196*33808Sbostic register char *from, *to; 197*33808Sbostic { 198*33808Sbostic do { 199*33808Sbostic *to++ = isupper(*from) ? tolower(*from) : *from; 200*33808Sbostic } while (*from++); 201*33808Sbostic } 202*33808Sbostic 203*33808Sbostic /* 204*33808Sbostic * usage -- 205*33808Sbostic * print usage message and die 206*33808Sbostic */ 207*33808Sbostic static 20831702Sbostic usage() 20931702Sbostic { 21031702Sbostic fprintf(stderr, "usage: %s [-M path] string ...\n", myname); 21131702Sbostic exit(1); 21231702Sbostic } 213