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 6*34886Sbostic * provided that the above copyright notice and this paragraph are 7*34886Sbostic * duplicated in all such forms and that any documentation, 8*34886Sbostic * advertising materials, and other materials related to such 9*34886Sbostic * distribution and use acknowledge that the software was developed 10*34886Sbostic * by the University of California, Berkeley. The name of the 11*34886Sbostic * University may not be used to endorse or promote products derived 12*34886Sbostic * from this software without specific prior written permission. 13*34886Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34886Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34886Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1631702Sbostic */ 1731702Sbostic 1831702Sbostic #ifndef lint 1931702Sbostic char copyright[] = 2031702Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 2131702Sbostic All rights reserved.\n"; 2233054Sbostic #endif /* not lint */ 2331702Sbostic 2431702Sbostic #ifndef lint 25*34886Sbostic static char sccsid[] = "@(#)apropos.c 5.6 (Berkeley) 06/29/88"; 2633054Sbostic #endif /* not lint */ 2731702Sbostic 2831702Sbostic #include <sys/param.h> 2931702Sbostic #include <stdio.h> 3031702Sbostic #include <ctype.h> 3133808Sbostic #include <strings.h> 3231702Sbostic 3331974Sbostic #define DEF_PATH "/usr/man:/usr/new/man:/usr/local/man" 3431712Sbostic #define MAXLINELEN 1000 /* max line handled */ 3531702Sbostic #define WHATIS "whatis" /* database name */ 3631702Sbostic 3733808Sbostic #define NO 0 /* no/false */ 3833808Sbostic #define YES 1 /* yes/true */ 3931702Sbostic 4033808Sbostic static char *myname; 4133808Sbostic 4231702Sbostic main(argc, argv) 4333808Sbostic int argc; 4433808Sbostic char **argv; 4531702Sbostic { 4633808Sbostic extern char *optarg; 4733808Sbostic extern int optind; 4833808Sbostic register char *beg, *end, **C; 4933808Sbostic int ch, foundman = NO, *found, isapropos; 5033808Sbostic int a_match(), w_match(), (*match)(); 5133808Sbostic char *manpath = NULL, buf[MAXLINELEN + 1], fname[MAXPATHLEN + 1]; 5233808Sbostic char wbuf[MAXLINELEN + 1], *getenv(), *malloc(); 5331702Sbostic 5431702Sbostic myname = (beg = rindex(*argv, '/')) ? beg + 1 : *argv; 5531702Sbostic if (!strcmp(myname, "apropos")) { 5631702Sbostic isapropos = YES; 5731702Sbostic match = a_match; 5831702Sbostic } 5931702Sbostic else { 6031702Sbostic isapropos = NO; 6131702Sbostic match = w_match; 6231702Sbostic } 6331702Sbostic while ((ch = getopt(argc, argv, "M:P:")) != EOF) 6431702Sbostic switch((char)ch) { 6531702Sbostic case 'M': 6631702Sbostic case 'P': /* backward contemptible */ 6731702Sbostic manpath = optarg; 6831702Sbostic break; 6931702Sbostic case '?': 7031702Sbostic default: 7131702Sbostic usage(); 7231702Sbostic } 7331702Sbostic argv += optind; 7431702Sbostic argc -= optind; 7531702Sbostic if (argc < 1) 7631702Sbostic usage(); 7731702Sbostic 7831702Sbostic if (!(manpath = getenv("MANPATH"))) 7931702Sbostic manpath = DEF_PATH; 8031702Sbostic 8131702Sbostic /*NOSTRICT*/ 8231702Sbostic if (!(found = (int *)malloc((u_int)argc))) { 8331702Sbostic fprintf(stderr, "%s: out of space.\n", myname); 8431702Sbostic exit(1); 8531702Sbostic } 8633808Sbostic bzero((char *)found, argc * sizeof(int)); 8731702Sbostic 8833808Sbostic if (isapropos) 8933808Sbostic for (C = argv; *C; ++C) /* convert to lower-case */ 9033808Sbostic lowstr(*C, *C); 9133808Sbostic else for (C = argv; *C; ++C) /* trim full paths */ 9233808Sbostic if (beg = rindex(*C, '/')) 9333808Sbostic *C = beg + 1; 9431702Sbostic 9531702Sbostic for (beg = manpath; beg; beg = end) { /* through path list */ 9631702Sbostic end = index(beg, ':'); 9731702Sbostic if (!end) 9831702Sbostic (void)sprintf(fname, "%s/%s", beg, WHATIS); 9931702Sbostic else { 10031702Sbostic (void)sprintf(fname, "%.*s/%s", end - beg, beg, WHATIS); 10131702Sbostic ++end; 10231702Sbostic } 10333808Sbostic if (!freopen(fname, "r", stdin)) 10433808Sbostic continue; 10533808Sbostic 10631702Sbostic /* for each file found */ 10733808Sbostic for (foundman = YES; gets(buf);) { 10833808Sbostic if (isapropos) 10931702Sbostic lowstr(buf, wbuf); 11033808Sbostic else 11133808Sbostic dashtrunc(buf, wbuf); 11233808Sbostic for (C = argv; *C; ++C) 11333808Sbostic if ((*match)(wbuf, *C)) { 11433808Sbostic puts(buf); 11533808Sbostic found[C - argv] = YES; 11631702Sbostic 11733808Sbostic /* only print line once */ 11833808Sbostic while (*++C) 11933808Sbostic if ((*match)(wbuf, *C)) 12033808Sbostic found[C - argv] = YES; 12133808Sbostic break; 12233808Sbostic } 12331702Sbostic } 12431702Sbostic } 12531702Sbostic if (!foundman) { 12631702Sbostic fprintf(stderr, "%s: no %s file found in %s.\n", myname, WHATIS, manpath); 12731702Sbostic exit(1); 12831702Sbostic } 12933808Sbostic for (C = argv; *C; ++C) 13031702Sbostic if (!found[C - argv]) 13131702Sbostic printf("%s: %s\n", *C, isapropos ? "nothing appropriate" : "not found"); 13231702Sbostic } 13331702Sbostic 13433808Sbostic /* 13533808Sbostic * a_match -- 13633808Sbostic * match for apropos; anywhere the string appears 13733808Sbostic */ 13831702Sbostic static 13931702Sbostic a_match(bp, str) 14033808Sbostic register char *bp, *str; 14131702Sbostic { 14233808Sbostic register int len; 14333808Sbostic register char test; 14431702Sbostic 14531702Sbostic if (!*bp) 14631702Sbostic return(NO); 14733808Sbostic /* backward compatible: everything matches empty string */ 14831702Sbostic if (!*str) 14931702Sbostic return(YES); 15033808Sbostic for (test = *str++, len = strlen(str); *bp;) 15133808Sbostic if (test == *bp++ && !strncmp(bp, str, len)) 15233808Sbostic return(YES); 15331702Sbostic return(NO); 15431702Sbostic } 15531702Sbostic 15633808Sbostic /* 15733808Sbostic * w_match -- 15833808Sbostic * match for whatis; looks for full word match 15933808Sbostic */ 16031702Sbostic static 16131702Sbostic w_match(bp, str) 16233808Sbostic register char *bp, *str; 16331702Sbostic { 16433808Sbostic register int len; 16533808Sbostic register char *start; 16631702Sbostic 16731702Sbostic if (!*str || !*bp) 16831702Sbostic return(NO); 16933808Sbostic for (len = strlen(str);;) { 17033808Sbostic for (; *bp && !isdigit(*bp) && !isalpha(*bp); ++bp); 17133808Sbostic if (!*bp) 17233808Sbostic break; 17333808Sbostic for (start = bp++; *bp && (isdigit(*bp) || isalpha(*bp)); ++bp); 17433808Sbostic if (bp - start == len && !strncasecmp(start, str, len)) 17533808Sbostic return(YES); 17633808Sbostic } 17731702Sbostic return(NO); 17831702Sbostic } 17931702Sbostic 18033808Sbostic /* 18133808Sbostic * dashtrunc -- 18233808Sbostic * truncate a string at " - " 18333808Sbostic */ 18431702Sbostic static 18533808Sbostic dashtrunc(from, to) 18633808Sbostic register char *from, *to; 18731702Sbostic { 18833808Sbostic do { 18933808Sbostic if (from[0] == ' ' && from[1] == '-' && from[2] == ' ') 19033808Sbostic break; 19133808Sbostic } while (*to++ = *from++); 19231702Sbostic *to = '\0'; 19331702Sbostic } 19431702Sbostic 19533808Sbostic /* 19633808Sbostic * lowstr -- 19733808Sbostic * convert a string to lower case 19833808Sbostic */ 19931702Sbostic static 20033808Sbostic lowstr(from, to) 20133808Sbostic register char *from, *to; 20233808Sbostic { 20333808Sbostic do { 20433808Sbostic *to++ = isupper(*from) ? tolower(*from) : *from; 20533808Sbostic } while (*from++); 20633808Sbostic } 20733808Sbostic 20833808Sbostic /* 20933808Sbostic * usage -- 21033808Sbostic * print usage message and die 21133808Sbostic */ 21233808Sbostic static 21331702Sbostic usage() 21431702Sbostic { 21531702Sbostic fprintf(stderr, "usage: %s [-M path] string ...\n", myname); 21631702Sbostic exit(1); 21731702Sbostic } 218