131702Sbostic /* 231702Sbostic * Copyright (c) 1987 Regents of the University of California. 3*33054Sbostic * All rights reserved. 4*33054Sbostic * 5*33054Sbostic * Redistribution and use in source and binary forms are permitted 6*33054Sbostic * provided that this notice is preserved and that due credit is given 7*33054Sbostic * to the University of California at Berkeley. The name of the University 8*33054Sbostic * may not be used to endorse or promote products derived from this 9*33054Sbostic * software without specific prior written permission. This software 10*33054Sbostic * 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"; 17*33054Sbostic #endif /* not lint */ 1831702Sbostic 1931702Sbostic #ifndef lint 20*33054Sbostic static char sccsid[] = "@(#)apropos.c 5.4 (Berkeley) 12/16/87"; 21*33054Sbostic #endif /* not lint */ 2231702Sbostic 2331702Sbostic #include <sys/param.h> 2431702Sbostic #include <stdio.h> 2531702Sbostic #include <ctype.h> 2631702Sbostic 2731974Sbostic #define DEF_PATH "/usr/man:/usr/new/man:/usr/local/man" 2831712Sbostic #define MAXLINELEN 1000 /* max line handled */ 2931702Sbostic #define NO 0 /* no/false */ 3031702Sbostic #define WHATIS "whatis" /* database name */ 3131702Sbostic #define YES 1 /* yes/true */ 3231702Sbostic 3331702Sbostic static char *myname; 3431702Sbostic 3531702Sbostic main(argc, argv) 3631702Sbostic int argc; 3731702Sbostic char **argv; 3831702Sbostic { 3931702Sbostic extern char *optarg; 4031702Sbostic extern int optind; 4131702Sbostic register char *beg, *end, **C; 4231702Sbostic int ch, foundman = NO, *found, isapropos, 4331702Sbostic a_match(), w_match(), (*match)(); 4431702Sbostic char *manpath = NULL, 4531702Sbostic buf[MAXLINELEN + 1], fname[MAXPATHLEN + 1], 4631702Sbostic wbuf[MAXLINELEN + 1], 4731702Sbostic *getenv(), *index(), *malloc(), *rindex(); 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 } 8131712Sbostic bzero((char *)found, argc * sizeof(int)); /* calloc is silly */ 8231702Sbostic 8331702Sbostic if (!isapropos) 8431712Sbostic for (C = argv; *C; ++C) { /* trim full paths */ 8531702Sbostic if (beg = rindex(*C, '/')) 8631702Sbostic *C = beg + 1; 8731702Sbostic } 8831702Sbostic for (C = argv; *C; ++C) /* convert to lower-case */ 8931702Sbostic lowstr(*C, *C); 9031702Sbostic 9131702Sbostic for (beg = manpath; beg; beg = end) { /* through path list */ 9231702Sbostic end = index(beg, ':'); 9331702Sbostic if (!end) 9431702Sbostic (void)sprintf(fname, "%s/%s", beg, WHATIS); 9531702Sbostic else { 9631702Sbostic (void)sprintf(fname, "%.*s/%s", end - beg, beg, WHATIS); 9731702Sbostic ++end; 9831702Sbostic } 9931702Sbostic /* for each file found */ 10031702Sbostic if (freopen(fname, "r", stdin)) { 10131702Sbostic foundman = YES; 10231702Sbostic while (gets(buf)) { /* read & convert to lcase */ 10331702Sbostic lowstr(buf, wbuf); 10431702Sbostic for (C = argv; *C; ++C) 10531702Sbostic if ((*match)(wbuf, *C)) { 10631702Sbostic puts(buf); 10731702Sbostic found[C - argv] = YES; 10831702Sbostic 10931702Sbostic /* only print line once */ 11031702Sbostic while (*++C) 11131702Sbostic if ((*match)(wbuf, *C)) 11231702Sbostic found[C - argv] = YES; 11331702Sbostic break; 11431702Sbostic } 11531702Sbostic } 11631702Sbostic } 11731702Sbostic } 11831702Sbostic if (!foundman) { 11931702Sbostic fprintf(stderr, "%s: no %s file found in %s.\n", myname, WHATIS, manpath); 12031702Sbostic exit(1); 12131702Sbostic } 12231702Sbostic for (C = argv; *C; C++) 12331702Sbostic if (!found[C - argv]) 12431702Sbostic printf("%s: %s\n", *C, isapropos ? "nothing appropriate" : "not found"); 12531702Sbostic } 12631702Sbostic 12731702Sbostic static 12831702Sbostic a_match(bp, str) 12931702Sbostic register char *bp, *str; 13031702Sbostic { 13131702Sbostic register char test, *Cs, *Cb; 13231702Sbostic 13331702Sbostic if (!*bp) 13431702Sbostic return(NO); 13531702Sbostic /* backward contemptible: everything matches empty string */ 13631702Sbostic if (!*str) 13731702Sbostic return(YES); 13831702Sbostic for (test = *str++; *bp;) 13931702Sbostic if (test == *bp++) { 14031702Sbostic Cs = str; 14131702Sbostic Cb = bp; 14231702Sbostic do { 14331702Sbostic if (!*Cs) 14431702Sbostic return(YES); 14531702Sbostic } while (*Cb++ == *Cs++); 14631702Sbostic } 14731702Sbostic return(NO); 14831702Sbostic } 14931702Sbostic 15031702Sbostic static 15131702Sbostic w_match(bp, str) 15231702Sbostic register char *bp, *str; 15331702Sbostic { 15431702Sbostic register char test, *Cs, *Cb; 15531702Sbostic 15631702Sbostic if (!*str || !*bp) 15731702Sbostic return(NO); 15831702Sbostic for (test = *str++; *bp;) 15931702Sbostic if (test == *bp++) { 16031702Sbostic for (Cs = str, Cb = bp; *Cs == *Cb; ++Cs, ++Cb); 16131702Sbostic if (!*Cs && (isspace(*Cb) || *Cb == '(' || *Cb == ',')) 16231702Sbostic return(YES); 16331702Sbostic } 16431702Sbostic return(NO); 16531702Sbostic } 16631702Sbostic 16731702Sbostic static 16831702Sbostic lowstr(from, to) 16931702Sbostic register char *from, *to; 17031702Sbostic { 17131702Sbostic for (; *from; ++from, ++to) 17231702Sbostic *to = isupper(*from) ? tolower(*from) : *from; 17331702Sbostic *to = '\0'; 17431702Sbostic } 17531702Sbostic 17631702Sbostic static 17731702Sbostic usage() 17831702Sbostic { 17931702Sbostic fprintf(stderr, "usage: %s [-M path] string ...\n", myname); 18031702Sbostic exit(1); 18131702Sbostic } 182