xref: /csrg-svn/usr.bin/man/man.c (revision 42741)
131703Sbostic /*
231703Sbostic  * Copyright (c) 1987 Regents of the University of California.
333054Sbostic  * All rights reserved.
433054Sbostic  *
5*42741Sbostic  * %sccs.include.redist.c%
631703Sbostic  */
731703Sbostic 
831703Sbostic #ifndef lint
931703Sbostic char copyright[] =
1031703Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\
1131703Sbostic  All rights reserved.\n";
1233054Sbostic #endif /* not lint */
1331703Sbostic 
1431703Sbostic #ifndef lint
15*42741Sbostic static char sccsid[] = "@(#)man.c	5.21 (Berkeley) 06/01/90";
1633054Sbostic #endif /* not lint */
1731703Sbostic 
1831703Sbostic #include <sys/param.h>
1931703Sbostic #include <sys/file.h>
2040390Sbostic #include <errno.h>
2131703Sbostic #include <ctype.h>
2240390Sbostic #include <string.h>
2342402Sbostic #include <stdlib.h>
2437892Sbostic #include "pathnames.h"
2531703Sbostic 
2640390Sbostic extern int errno;
2731703Sbostic 
2842402Sbostic int f_all, f_cat, f_where;
2940390Sbostic char *command, *machine, *p_augment, *p_path, *pager, *progname;
3034057Sbostic 
3131703Sbostic main(argc, argv)
3233354Sbostic 	int argc;
3333354Sbostic 	register char **argv;
3431703Sbostic {
3534057Sbostic 	extern char *optarg;
3634057Sbostic 	extern int optind;
3742402Sbostic 	int ch, res;
3842402Sbostic 	char *section[2], *check_pager(), *getpath();
3931703Sbostic 
4040390Sbostic 	progname = "man";
4140390Sbostic 	while ((ch = getopt(argc, argv, "-acfkM:m:P:w")) != EOF)
4234057Sbostic 		switch((char)ch) {
4340390Sbostic 		case 'a':
4440390Sbostic 			f_all = 1;
4531703Sbostic 			break;
4640390Sbostic 		case 'c':
4740390Sbostic 		case '-':		/* deprecated */
4840390Sbostic 			f_cat = 1;
4940390Sbostic 			break;
5040390Sbostic 		case 'm':
5140390Sbostic 			p_augment = optarg;
5240390Sbostic 			break;
5331703Sbostic 		case 'M':
5431703Sbostic 		case 'P':		/* backward compatibility */
5540390Sbostic 			p_path = optarg;
5631703Sbostic 			break;
5742402Sbostic 		/*
5842402Sbostic 		 * "man -f" and "man -k" are backward compatible, undocumented
5942402Sbostic 		 * ways of calling whatis(1) and apropos(1).
6042402Sbostic 		 */
6131703Sbostic 		case 'f':
6234057Sbostic 			jump(argv, "-f", "whatis");
6340390Sbostic 			/* NOTREACHED */
6431703Sbostic 		case 'k':
6534057Sbostic 			jump(argv, "-k", "apropos");
6640390Sbostic 			/* NOTREACHED */
6732565Sbostic 		case 'w':
6840390Sbostic 			f_all = f_where = 1;
6932565Sbostic 			break;
7031703Sbostic 		case '?':
7131703Sbostic 		default:
7234057Sbostic 			usage();
7331703Sbostic 		}
7434057Sbostic 	argv += optind;
7531703Sbostic 
7634057Sbostic 	if (!*argv)
7734057Sbostic 		usage();
7833354Sbostic 
7940390Sbostic 	if (!f_cat)
8031703Sbostic 		if (!isatty(1))
8140390Sbostic 			f_cat = 1;
8240390Sbostic 		else if (pager = getenv("PAGER"))
8340390Sbostic 			pager = check_pager(pager);
8431779Sbostic 		else
8537892Sbostic 			pager = _PATH_PAGER;
8640390Sbostic 
8731703Sbostic 	if (!(machine = getenv("MACHINE")))
8831703Sbostic 		machine = MACHINE;
8940390Sbostic 
9042402Sbostic 	/* see if checking in a specific section */
9142402Sbostic 	if (argc > 1 && getsection(*argv)) {
9242402Sbostic 		section[0] = *argv++;
9342402Sbostic 		section[1] = (char *)NULL;
9442402Sbostic 	} else {
9542402Sbostic 		section[0] = "_default";
9642402Sbostic 		section[1] = (char *)NULL;
9742402Sbostic 	}
9840390Sbostic 
9942402Sbostic 	if (!p_path && !(p_path = getenv("MANPATH")) &&
10042402Sbostic 	    !(p_path = getpath(section)) && !p_augment) {
10142402Sbostic 		(void)fprintf(stderr,
10242402Sbostic 		    "man: no place to search for those manual pages.\n");
10342402Sbostic 		exit(1);
10442402Sbostic 	}
10540390Sbostic 
10642402Sbostic 	for (; *argv; ++argv) {
10742402Sbostic 		if (p_augment)
10842402Sbostic 			res = manual(p_augment, *argv);
10942402Sbostic 		res = manual(p_path, *argv);
11042402Sbostic 		if (res || f_where)
11142402Sbostic 			continue;
11242402Sbostic 		(void)fprintf(stderr,
11342402Sbostic 		    "man: no entry for %s in the manual.\n", *argv);
11442402Sbostic 		exit(1);
11542402Sbostic 	}
11642402Sbostic 
11734752Sbostic 	/* use system(3) in case someone's pager is "pager arg1 arg2" */
11833809Sbostic 	if (command)
11933809Sbostic 		(void)system(command);
12033354Sbostic 	exit(0);
12133354Sbostic }
12231703Sbostic 
12340390Sbostic /*
12431778Sbostic  * manual --
12540390Sbostic  *	given a path, a directory list and a file name, find a file
12640390Sbostic  *	that matches; check ${directory}/${dir}/{file name} and
12733809Sbostic  *	${directory}/${dir}/${machine}/${file name}.
12831778Sbostic  */
12942402Sbostic manual(path, name)
13040390Sbostic 	char *path, *name;
13131703Sbostic {
13242402Sbostic 	register int res;
13340390Sbostic 	register char *end;
13440390Sbostic 	char fname[MAXPATHLEN + 1];
13531703Sbostic 
13640390Sbostic 	for (res = 0;; path = end + 1) {
13742402Sbostic 		if (!*path)				/* foo: */
13842402Sbostic 			break;
13942402Sbostic 		if (end = index(path, ':')) {
14042402Sbostic 			if (end == path + 1)		/* foo::bar */
14142402Sbostic 				continue;
14231703Sbostic 			*end = '\0';
14333809Sbostic 		}
14442402Sbostic 		(void)sprintf(fname, "%s/%s.0", path, name);
14542402Sbostic 		if (access(fname, R_OK)) {
14642402Sbostic 			(void)sprintf(fname, "%s/%s/%s.0", path, machine, name);
14742402Sbostic 			if (access(fname, R_OK))
14842402Sbostic 				continue;
14942402Sbostic 		}
15042402Sbostic 
15142402Sbostic 		if (f_where)
15242402Sbostic 			(void)printf("man: found in %s.\n", fname);
15342402Sbostic 		else if (f_cat)
15442402Sbostic 			cat(fname);
15542402Sbostic 		else
15642402Sbostic 			add(fname);
15742402Sbostic 		if (!f_all)
15842402Sbostic 			return(1);
15942402Sbostic 		res = 1;
16031703Sbostic 		if (!end)
16142402Sbostic 			break;
16233297Sbostic 		*end = ':';
16331703Sbostic 	}
16442402Sbostic 	return(res);
16531703Sbostic }
16631703Sbostic 
16731778Sbostic /*
16833809Sbostic  * cat --
16933809Sbostic  *	cat out the file
17031778Sbostic  */
17133809Sbostic cat(fname)
17233809Sbostic 	char *fname;
17331703Sbostic {
17433809Sbostic 	register int fd, n;
17533809Sbostic 	char buf[BUFSIZ];
17631703Sbostic 
17733809Sbostic 	if (!(fd = open(fname, O_RDONLY, 0))) {
17840390Sbostic 		(void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno));
17933809Sbostic 		exit(1);
18031703Sbostic 	}
18133809Sbostic 	while ((n = read(fd, buf, sizeof(buf))) > 0)
18233809Sbostic 		if (write(1, buf, n) != n) {
18340390Sbostic 			(void)fprintf(stderr,
18440390Sbostic 			    "man: write: %s\n", strerror(errno));
18533809Sbostic 			exit(1);
18633809Sbostic 		}
18733809Sbostic 	if (n == -1) {
18840390Sbostic 		(void)fprintf(stderr, "man: read: %s\n", strerror(errno));
18933809Sbostic 		exit(1);
19033809Sbostic 	}
19133809Sbostic 	(void)close(fd);
19231703Sbostic }
19331703Sbostic 
19431778Sbostic /*
19533809Sbostic  * add --
19633809Sbostic  *	add a file name to the list for future paging
19731778Sbostic  */
19833809Sbostic add(fname)
19933354Sbostic 	char *fname;
20031703Sbostic {
20133809Sbostic 	static u_int buflen;
20233809Sbostic 	static int len;
20333809Sbostic 	static char *cp;
20433809Sbostic 	int flen;
20531703Sbostic 
20633809Sbostic 	if (!command) {
20740390Sbostic 		if (!(command = malloc(buflen = 1024)))
20840390Sbostic 			enomem();
20933809Sbostic 		len = strlen(strcpy(command, pager));
21033809Sbostic 		cp = command + len;
21133809Sbostic 	}
21233809Sbostic 	flen = strlen(fname);
21333809Sbostic 	if (len + flen + 2 > buflen) {		/* +2 == space, EOS */
21440390Sbostic 		if (!(command = realloc(command, buflen += 1024)))
21540390Sbostic 			enomem();
21633809Sbostic 		cp = command + len;
21731703Sbostic 	}
21833809Sbostic 	*cp++ = ' ';
21933809Sbostic 	len += flen + 1;			/* +1 = space */
22033809Sbostic 	(void)strcpy(cp, fname);
22133809Sbostic 	cp += flen;
22231703Sbostic }
22331703Sbostic 
22431778Sbostic /*
22540390Sbostic  * check_pager --
22640390Sbostic  *	check the user supplied page information
22740390Sbostic  */
22840390Sbostic char *
22940390Sbostic check_pager(name)
23040390Sbostic 	char *name;
23140390Sbostic {
23240390Sbostic 	register char *p;
23342402Sbostic 	char *save;
23440390Sbostic 
23540390Sbostic 	/*
23640390Sbostic 	 * if the user uses "more", we make it "more -s"; watch out for
23740390Sbostic 	 * PAGER = "mypager /usr/ucb/more"
23840390Sbostic 	 */
23940390Sbostic 	for (p = name; *p && !isspace(*p); ++p);
24040390Sbostic 	for (; p > name && *p != '/'; --p);
24140390Sbostic 	if (p != name)
24240390Sbostic 		++p;
24340390Sbostic 
24440390Sbostic 	/* make sure it's "more", not "morex" */
24540390Sbostic 	if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){
24640390Sbostic 		save = name;
24740390Sbostic 		/* allocate space to add the "-s" */
24840390Sbostic 		if (!(name =
24940390Sbostic 		    malloc((u_int)(strlen(save) + sizeof("-s") + 1))))
25040390Sbostic 			enomem();
25140390Sbostic 		(void)sprintf(name, "%s %s", save, "-s");
25240390Sbostic 	}
25340390Sbostic 	return(name);
25440390Sbostic }
25540390Sbostic 
25640390Sbostic /*
25734057Sbostic  * jump --
25834057Sbostic  *	strip out flag argument and jump
25934057Sbostic  */
26034057Sbostic jump(argv, flag, name)
26134057Sbostic 	char **argv, *name;
26234057Sbostic 	register char *flag;
26334057Sbostic {
26434057Sbostic 	register char **arg;
26534057Sbostic 
26634057Sbostic 	argv[0] = name;
26734057Sbostic 	for (arg = argv + 1; *arg; ++arg)
26834057Sbostic 		if (!strcmp(*arg, flag))
26934057Sbostic 			break;
27034057Sbostic 	for (; *arg; ++arg)
27134057Sbostic 		arg[0] = arg[1];
27234057Sbostic 	execvp(name, argv);
27342402Sbostic 	(void)fprintf(stderr, "%s: Command not found.\n", name);
27434057Sbostic 	exit(1);
27534057Sbostic }
27634057Sbostic 
27734057Sbostic /*
27834057Sbostic  * usage --
27940390Sbostic  *	print usage message and die
28034057Sbostic  */
28134057Sbostic usage()
28234057Sbostic {
28340390Sbostic 	(void)fprintf(stderr,
28440390Sbostic 	    "usage: man [-ac] [-M path] [-m path] [section] title ...\n");
28534057Sbostic 	exit(1);
28634057Sbostic }
287