xref: /csrg-svn/usr.bin/man/man.c (revision 65282)
131703Sbostic /*
263537Sbostic  * Copyright (c) 1987, 1993
363537Sbostic  *	The Regents of the University of California.  All rights reserved.
433054Sbostic  *
542741Sbostic  * %sccs.include.redist.c%
631703Sbostic  */
731703Sbostic 
831703Sbostic #ifndef lint
963537Sbostic static char copyright[] =
1063537Sbostic "@(#) Copyright (c) 1987, 1993\n\
1163537Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1233054Sbostic #endif /* not lint */
1331703Sbostic 
1431703Sbostic #ifndef lint
15*65282Sbostic static char sccsid[] = "@(#)man.c	8.2 (Berkeley) 01/02/94";
1633054Sbostic #endif /* not lint */
1731703Sbostic 
1831703Sbostic #include <sys/param.h>
1963536Sbostic 
2063536Sbostic #include <ctype.h>
2140390Sbostic #include <errno.h>
2263536Sbostic #include <fcntl.h>
2363536Sbostic #include <stdio.h>
2463536Sbostic #include <stdlib.h>
2540390Sbostic #include <string.h>
2663536Sbostic #include <unistd.h>
2763536Sbostic 
2837892Sbostic #include "pathnames.h"
2931703Sbostic 
3040390Sbostic extern int errno;
3131703Sbostic 
3244938Sbostic int f_all, f_cat, f_how, f_where;
3340390Sbostic char *command, *machine, *p_augment, *p_path, *pager, *progname;
3444597Strent extern char **arorder, *pathbuf;
3534057Sbostic 
3631703Sbostic main(argc, argv)
3733354Sbostic 	int argc;
3833354Sbostic 	register char **argv;
3931703Sbostic {
4034057Sbostic 	extern char *optarg;
4134057Sbostic 	extern int optind;
4242402Sbostic 	int ch, res;
4344418Strent 	char *section[2], *check_pager(), *getpath(), **getorder(), *tmp;
4431703Sbostic 
4540390Sbostic 	progname = "man";
4644938Sbostic 	while ((ch = getopt(argc, argv, "-acfhkM:m:P:w")) != EOF)
4734057Sbostic 		switch((char)ch) {
4840390Sbostic 		case 'a':
4940390Sbostic 			f_all = 1;
5031703Sbostic 			break;
5140390Sbostic 		case 'c':
5240390Sbostic 		case '-':		/* deprecated */
5340390Sbostic 			f_cat = 1;
5440390Sbostic 			break;
5544938Sbostic 		case 'h':
5644938Sbostic 			f_how = 1;
5744938Sbostic 			break;
5840390Sbostic 		case 'm':
5940390Sbostic 			p_augment = optarg;
6040390Sbostic 			break;
6131703Sbostic 		case 'M':
6231703Sbostic 		case 'P':		/* backward compatibility */
6340390Sbostic 			p_path = optarg;
6431703Sbostic 			break;
6542402Sbostic 		/*
6642402Sbostic 		 * "man -f" and "man -k" are backward compatible, undocumented
6742402Sbostic 		 * ways of calling whatis(1) and apropos(1).
6842402Sbostic 		 */
6931703Sbostic 		case 'f':
7034057Sbostic 			jump(argv, "-f", "whatis");
7140390Sbostic 			/* NOTREACHED */
7231703Sbostic 		case 'k':
7334057Sbostic 			jump(argv, "-k", "apropos");
7440390Sbostic 			/* NOTREACHED */
7532565Sbostic 		case 'w':
7640390Sbostic 			f_all = f_where = 1;
7732565Sbostic 			break;
7831703Sbostic 		case '?':
7931703Sbostic 		default:
8034057Sbostic 			usage();
8131703Sbostic 		}
82*65282Sbostic 	argc -= optind;
8334057Sbostic 	argv += optind;
8431703Sbostic 
8534057Sbostic 	if (!*argv)
8634057Sbostic 		usage();
8733354Sbostic 
8844938Sbostic 	if (!f_cat && !f_how)
8931703Sbostic 		if (!isatty(1))
9040390Sbostic 			f_cat = 1;
9140390Sbostic 		else if (pager = getenv("PAGER"))
9240390Sbostic 			pager = check_pager(pager);
9331779Sbostic 		else
9437892Sbostic 			pager = _PATH_PAGER;
9540390Sbostic 
9631703Sbostic 	if (!(machine = getenv("MACHINE")))
9731703Sbostic 		machine = MACHINE;
9840390Sbostic 
9942402Sbostic 	/* see if checking in a specific section */
10042402Sbostic 	if (argc > 1 && getsection(*argv)) {
10142402Sbostic 		section[0] = *argv++;
10242402Sbostic 		section[1] = (char *)NULL;
10342402Sbostic 	} else {
10442402Sbostic 		section[0] = "_default";
10542402Sbostic 		section[1] = (char *)NULL;
10642402Sbostic 	}
10740390Sbostic 
10844418Strent 	arorder = getorder();
10944418Strent 	if (p_path || (p_path = getenv("MANPATH"))) {
11044418Strent 		char buf[MAXPATHLEN], **av;
11144418Strent 
11263515Sbostic 		tmp = strtok(p_path, ":");
11344418Strent 		while (tmp) {
11452473Sbostic 			(void)snprintf(buf, sizeof(buf), "%s/", tmp);
11544418Strent 			for (av = arorder; *av; ++av)
11663515Sbostic 				cadd(buf, strlen(buf), *av);
11763515Sbostic 			tmp = strtok(NULL, ":");
11844418Strent 		}
11944418Strent 		p_path = pathbuf;
12044418Strent 	} else if (!(p_path = getpath(section)) && !p_augment) {
12142402Sbostic 		(void)fprintf(stderr,
12244418Strent 			"man: no place to search for those manual pages.\n");
12342402Sbostic 		exit(1);
12442402Sbostic 	}
12540390Sbostic 
12642402Sbostic 	for (; *argv; ++argv) {
12742402Sbostic 		if (p_augment)
12842402Sbostic 			res = manual(p_augment, *argv);
12942402Sbostic 		res = manual(p_path, *argv);
13054706Sbostic 		if (!res && !f_where)
13154706Sbostic 			(void)fprintf(stderr,
13254706Sbostic 			    "man: no entry for %s in the manual.\n", *argv);
13342402Sbostic 	}
13442402Sbostic 
13534752Sbostic 	/* use system(3) in case someone's pager is "pager arg1 arg2" */
13633809Sbostic 	if (command)
13733809Sbostic 		(void)system(command);
13833354Sbostic 	exit(0);
13933354Sbostic }
14031703Sbostic 
14140390Sbostic /*
14231778Sbostic  * manual --
14340390Sbostic  *	given a path, a directory list and a file name, find a file
14440390Sbostic  *	that matches; check ${directory}/${dir}/{file name} and
14533809Sbostic  *	${directory}/${dir}/${machine}/${file name}.
14631778Sbostic  */
14742402Sbostic manual(path, name)
14840390Sbostic 	char *path, *name;
14931703Sbostic {
15042402Sbostic 	register int res;
15163515Sbostic 	register char *cp;
15240390Sbostic 	char fname[MAXPATHLEN + 1];
15331703Sbostic 
15463515Sbostic 	for (res = 0; path != NULL && *path != '\0'; path = cp) {
15563515Sbostic 		if (cp = strchr(path, ':')) {
15663515Sbostic 			if (cp == path + 1) {		/* foo::bar */
15763515Sbostic 				++cp;
15842402Sbostic 				continue;
15963515Sbostic 			}
16063515Sbostic 			*cp = '\0';
16133809Sbostic 		}
16263536Sbostic 		(void)snprintf(fname, sizeof(fname), "%s/%s.0", path, name);
16342402Sbostic 		if (access(fname, R_OK)) {
16463536Sbostic 			(void)snprintf(fname, sizeof(fname),
16563536Sbostic 			    "%s/%s/%s.0", path, machine, name);
16663515Sbostic 			if (access(fname, R_OK)) {
16763536Sbostic 				if (cp != NULL)
16863536Sbostic 					*cp++ = ':';
16942402Sbostic 				continue;
17063515Sbostic 			}
17142402Sbostic 		}
17242402Sbostic 
17342402Sbostic 		if (f_where)
17442402Sbostic 			(void)printf("man: found in %s.\n", fname);
17542402Sbostic 		else if (f_cat)
17642402Sbostic 			cat(fname);
17744938Sbostic 		else if (f_how)
17844938Sbostic 			how(fname);
17942402Sbostic 		else
18042402Sbostic 			add(fname);
18142402Sbostic 		if (!f_all)
18242402Sbostic 			return(1);
18342402Sbostic 		res = 1;
18463536Sbostic 		if (cp != NULL)
18563515Sbostic 			*cp++ = ':';
18631703Sbostic 	}
18742402Sbostic 	return(res);
18831703Sbostic }
18931703Sbostic 
19031778Sbostic /*
19144938Sbostic  * how --
19244938Sbostic  *	display how information
19344938Sbostic  */
19444938Sbostic how(fname)
19544938Sbostic 	char *fname;
19644938Sbostic {
19744938Sbostic 	register FILE *fp;
19844938Sbostic 
19944938Sbostic 	register int lcnt, print;
20044938Sbostic 	register char *p;
20144938Sbostic 	char buf[BUFSIZ];
20244938Sbostic 
20344938Sbostic 	if (!(fp = fopen(fname, "r"))) {
20444938Sbostic 		(void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno));
20544938Sbostic 		exit(1);
20644938Sbostic 	}
20744938Sbostic #define	S1	"SYNOPSIS"
20844938Sbostic #define	S2	"S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS"
20944938Sbostic #define	D1	"DESCRIPTION"
21044938Sbostic #define	D2	"D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN"
21144938Sbostic 	for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) {
21244938Sbostic 		if (!strncmp(buf, S1, sizeof(S1) - 1) ||
21344938Sbostic 		    !strncmp(buf, S2, sizeof(S2) - 1)) {
21444938Sbostic 			print = 1;
21544938Sbostic 			continue;
21644938Sbostic 		} else if (!strncmp(buf, D1, sizeof(D1) - 1) ||
21744938Sbostic 		    !strncmp(buf, D2, sizeof(D2) - 1))
21844938Sbostic 			return;
21944938Sbostic 		if (!print)
22044938Sbostic 			continue;
22144938Sbostic 		if (*buf == '\n')
22244938Sbostic 			++lcnt;
22344938Sbostic 		else {
22444938Sbostic 			for(; lcnt; --lcnt)
22544938Sbostic 				(void)putchar('\n');
22644938Sbostic 			for (p = buf; isspace(*p); ++p);
22744938Sbostic 			(void)fputs(p, stdout);
22844938Sbostic 		}
22944938Sbostic 	}
23044938Sbostic 	(void)fclose(fp);
23144938Sbostic }
23244938Sbostic /*
23333809Sbostic  * cat --
23433809Sbostic  *	cat out the file
23531778Sbostic  */
23633809Sbostic cat(fname)
23733809Sbostic 	char *fname;
23831703Sbostic {
23933809Sbostic 	register int fd, n;
24033809Sbostic 	char buf[BUFSIZ];
24131703Sbostic 
24244938Sbostic 	if ((fd = open(fname, O_RDONLY, 0)) < 0) {
24340390Sbostic 		(void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno));
24433809Sbostic 		exit(1);
24531703Sbostic 	}
24633809Sbostic 	while ((n = read(fd, buf, sizeof(buf))) > 0)
24733809Sbostic 		if (write(1, buf, n) != n) {
24840390Sbostic 			(void)fprintf(stderr,
24940390Sbostic 			    "man: write: %s\n", strerror(errno));
25033809Sbostic 			exit(1);
25133809Sbostic 		}
25233809Sbostic 	if (n == -1) {
25340390Sbostic 		(void)fprintf(stderr, "man: read: %s\n", strerror(errno));
25433809Sbostic 		exit(1);
25533809Sbostic 	}
25633809Sbostic 	(void)close(fd);
25731703Sbostic }
25831703Sbostic 
25931778Sbostic /*
26033809Sbostic  * add --
26133809Sbostic  *	add a file name to the list for future paging
26231778Sbostic  */
26333809Sbostic add(fname)
26433354Sbostic 	char *fname;
26531703Sbostic {
26633809Sbostic 	static u_int buflen;
26733809Sbostic 	static int len;
26833809Sbostic 	static char *cp;
26933809Sbostic 	int flen;
27031703Sbostic 
27133809Sbostic 	if (!command) {
27240390Sbostic 		if (!(command = malloc(buflen = 1024)))
27340390Sbostic 			enomem();
27433809Sbostic 		len = strlen(strcpy(command, pager));
27533809Sbostic 		cp = command + len;
27633809Sbostic 	}
27733809Sbostic 	flen = strlen(fname);
27833809Sbostic 	if (len + flen + 2 > buflen) {		/* +2 == space, EOS */
27940390Sbostic 		if (!(command = realloc(command, buflen += 1024)))
28040390Sbostic 			enomem();
28133809Sbostic 		cp = command + len;
28231703Sbostic 	}
28333809Sbostic 	*cp++ = ' ';
28433809Sbostic 	len += flen + 1;			/* +1 = space */
28533809Sbostic 	(void)strcpy(cp, fname);
28633809Sbostic 	cp += flen;
28731703Sbostic }
28831703Sbostic 
28931778Sbostic /*
29040390Sbostic  * check_pager --
29140390Sbostic  *	check the user supplied page information
29240390Sbostic  */
29340390Sbostic char *
29440390Sbostic check_pager(name)
29540390Sbostic 	char *name;
29640390Sbostic {
29740390Sbostic 	register char *p;
29842402Sbostic 	char *save;
29940390Sbostic 
30040390Sbostic 	/*
30140390Sbostic 	 * if the user uses "more", we make it "more -s"; watch out for
30240390Sbostic 	 * PAGER = "mypager /usr/ucb/more"
30340390Sbostic 	 */
30440390Sbostic 	for (p = name; *p && !isspace(*p); ++p);
30540390Sbostic 	for (; p > name && *p != '/'; --p);
30640390Sbostic 	if (p != name)
30740390Sbostic 		++p;
30840390Sbostic 
30940390Sbostic 	/* make sure it's "more", not "morex" */
31040390Sbostic 	if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){
31140390Sbostic 		save = name;
31240390Sbostic 		/* allocate space to add the "-s" */
31340390Sbostic 		if (!(name =
31440390Sbostic 		    malloc((u_int)(strlen(save) + sizeof("-s") + 1))))
31540390Sbostic 			enomem();
31640390Sbostic 		(void)sprintf(name, "%s %s", save, "-s");
31740390Sbostic 	}
31840390Sbostic 	return(name);
31940390Sbostic }
32040390Sbostic 
32140390Sbostic /*
32234057Sbostic  * jump --
32334057Sbostic  *	strip out flag argument and jump
32434057Sbostic  */
32534057Sbostic jump(argv, flag, name)
32634057Sbostic 	char **argv, *name;
32734057Sbostic 	register char *flag;
32834057Sbostic {
32934057Sbostic 	register char **arg;
33034057Sbostic 
33134057Sbostic 	argv[0] = name;
33234057Sbostic 	for (arg = argv + 1; *arg; ++arg)
33334057Sbostic 		if (!strcmp(*arg, flag))
33434057Sbostic 			break;
33534057Sbostic 	for (; *arg; ++arg)
33634057Sbostic 		arg[0] = arg[1];
33734057Sbostic 	execvp(name, argv);
33842402Sbostic 	(void)fprintf(stderr, "%s: Command not found.\n", name);
33934057Sbostic 	exit(1);
34034057Sbostic }
34134057Sbostic 
34234057Sbostic /*
34334057Sbostic  * usage --
34440390Sbostic  *	print usage message and die
34534057Sbostic  */
34634057Sbostic usage()
34734057Sbostic {
34840390Sbostic 	(void)fprintf(stderr,
34940390Sbostic 	    "usage: man [-ac] [-M path] [-m path] [section] title ...\n");
35034057Sbostic 	exit(1);
35134057Sbostic }
352