xref: /csrg-svn/usr.bin/apropos/apropos.c (revision 33054)
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