xref: /csrg-svn/usr.bin/man/man.c (revision 42402)
131703Sbostic /*
231703Sbostic  * 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
634886Sbostic  * provided that the above copyright notice and this paragraph are
734886Sbostic  * duplicated in all such forms and that any documentation,
834886Sbostic  * advertising materials, and other materials related to such
934886Sbostic  * distribution and use acknowledge that the software was developed
1034886Sbostic  * by the University of California, Berkeley.  The name of the
1134886Sbostic  * University may not be used to endorse or promote products derived
1234886Sbostic  * from this software without specific prior written permission.
1334886Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434886Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534886Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1631703Sbostic  */
1731703Sbostic 
1831703Sbostic #ifndef lint
1931703Sbostic char copyright[] =
2031703Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\
2131703Sbostic  All rights reserved.\n";
2233054Sbostic #endif /* not lint */
2331703Sbostic 
2431703Sbostic #ifndef lint
25*42402Sbostic static char sccsid[] = "@(#)man.c	5.20 (Berkeley) 05/27/90";
2633054Sbostic #endif /* not lint */
2731703Sbostic 
2831703Sbostic #include <sys/param.h>
2931703Sbostic #include <sys/file.h>
3040390Sbostic #include <errno.h>
3131703Sbostic #include <ctype.h>
3240390Sbostic #include <string.h>
33*42402Sbostic #include <stdlib.h>
3437892Sbostic #include "pathnames.h"
3531703Sbostic 
3640390Sbostic extern int errno;
3731703Sbostic 
38*42402Sbostic int f_all, f_cat, f_where;
3940390Sbostic char *command, *machine, *p_augment, *p_path, *pager, *progname;
4034057Sbostic 
4131703Sbostic main(argc, argv)
4233354Sbostic 	int argc;
4333354Sbostic 	register char **argv;
4431703Sbostic {
4534057Sbostic 	extern char *optarg;
4634057Sbostic 	extern int optind;
47*42402Sbostic 	int ch, res;
48*42402Sbostic 	char *section[2], *check_pager(), *getpath();
4931703Sbostic 
5040390Sbostic 	progname = "man";
5140390Sbostic 	while ((ch = getopt(argc, argv, "-acfkM:m:P:w")) != EOF)
5234057Sbostic 		switch((char)ch) {
5340390Sbostic 		case 'a':
5440390Sbostic 			f_all = 1;
5531703Sbostic 			break;
5640390Sbostic 		case 'c':
5740390Sbostic 		case '-':		/* deprecated */
5840390Sbostic 			f_cat = 1;
5940390Sbostic 			break;
6040390Sbostic 		case 'm':
6140390Sbostic 			p_augment = optarg;
6240390Sbostic 			break;
6331703Sbostic 		case 'M':
6431703Sbostic 		case 'P':		/* backward compatibility */
6540390Sbostic 			p_path = optarg;
6631703Sbostic 			break;
67*42402Sbostic 		/*
68*42402Sbostic 		 * "man -f" and "man -k" are backward compatible, undocumented
69*42402Sbostic 		 * ways of calling whatis(1) and apropos(1).
70*42402Sbostic 		 */
7131703Sbostic 		case 'f':
7234057Sbostic 			jump(argv, "-f", "whatis");
7340390Sbostic 			/* NOTREACHED */
7431703Sbostic 		case 'k':
7534057Sbostic 			jump(argv, "-k", "apropos");
7640390Sbostic 			/* NOTREACHED */
7732565Sbostic 		case 'w':
7840390Sbostic 			f_all = f_where = 1;
7932565Sbostic 			break;
8031703Sbostic 		case '?':
8131703Sbostic 		default:
8234057Sbostic 			usage();
8331703Sbostic 		}
8434057Sbostic 	argv += optind;
8531703Sbostic 
8634057Sbostic 	if (!*argv)
8734057Sbostic 		usage();
8833354Sbostic 
8940390Sbostic 	if (!f_cat)
9031703Sbostic 		if (!isatty(1))
9140390Sbostic 			f_cat = 1;
9240390Sbostic 		else if (pager = getenv("PAGER"))
9340390Sbostic 			pager = check_pager(pager);
9431779Sbostic 		else
9537892Sbostic 			pager = _PATH_PAGER;
9640390Sbostic 
9731703Sbostic 	if (!(machine = getenv("MACHINE")))
9831703Sbostic 		machine = MACHINE;
9940390Sbostic 
100*42402Sbostic 	/* see if checking in a specific section */
101*42402Sbostic 	if (argc > 1 && getsection(*argv)) {
102*42402Sbostic 		section[0] = *argv++;
103*42402Sbostic 		section[1] = (char *)NULL;
104*42402Sbostic 	} else {
105*42402Sbostic 		section[0] = "_default";
106*42402Sbostic 		section[1] = (char *)NULL;
107*42402Sbostic 	}
10840390Sbostic 
109*42402Sbostic 	if (!p_path && !(p_path = getenv("MANPATH")) &&
110*42402Sbostic 	    !(p_path = getpath(section)) && !p_augment) {
111*42402Sbostic 		(void)fprintf(stderr,
112*42402Sbostic 		    "man: no place to search for those manual pages.\n");
113*42402Sbostic 		exit(1);
114*42402Sbostic 	}
11540390Sbostic 
116*42402Sbostic 	for (; *argv; ++argv) {
117*42402Sbostic 		if (p_augment)
118*42402Sbostic 			res = manual(p_augment, *argv);
119*42402Sbostic 		res = manual(p_path, *argv);
120*42402Sbostic 		if (res || f_where)
121*42402Sbostic 			continue;
122*42402Sbostic 		(void)fprintf(stderr,
123*42402Sbostic 		    "man: no entry for %s in the manual.\n", *argv);
124*42402Sbostic 		exit(1);
125*42402Sbostic 	}
126*42402Sbostic 
12734752Sbostic 	/* use system(3) in case someone's pager is "pager arg1 arg2" */
12833809Sbostic 	if (command)
12933809Sbostic 		(void)system(command);
13033354Sbostic 	exit(0);
13133354Sbostic }
13231703Sbostic 
13340390Sbostic /*
13431778Sbostic  * manual --
13540390Sbostic  *	given a path, a directory list and a file name, find a file
13640390Sbostic  *	that matches; check ${directory}/${dir}/{file name} and
13733809Sbostic  *	${directory}/${dir}/${machine}/${file name}.
13831778Sbostic  */
139*42402Sbostic manual(path, name)
14040390Sbostic 	char *path, *name;
14131703Sbostic {
142*42402Sbostic 	register int res;
14340390Sbostic 	register char *end;
14440390Sbostic 	char fname[MAXPATHLEN + 1];
14531703Sbostic 
14640390Sbostic 	for (res = 0;; path = end + 1) {
147*42402Sbostic 		if (!*path)				/* foo: */
148*42402Sbostic 			break;
149*42402Sbostic 		if (end = index(path, ':')) {
150*42402Sbostic 			if (end == path + 1)		/* foo::bar */
151*42402Sbostic 				continue;
15231703Sbostic 			*end = '\0';
15333809Sbostic 		}
154*42402Sbostic 		(void)sprintf(fname, "%s/%s.0", path, name);
155*42402Sbostic 		if (access(fname, R_OK)) {
156*42402Sbostic 			(void)sprintf(fname, "%s/%s/%s.0", path, machine, name);
157*42402Sbostic 			if (access(fname, R_OK))
158*42402Sbostic 				continue;
159*42402Sbostic 		}
160*42402Sbostic 
161*42402Sbostic 		if (f_where)
162*42402Sbostic 			(void)printf("man: found in %s.\n", fname);
163*42402Sbostic 		else if (f_cat)
164*42402Sbostic 			cat(fname);
165*42402Sbostic 		else
166*42402Sbostic 			add(fname);
167*42402Sbostic 		if (!f_all)
168*42402Sbostic 			return(1);
169*42402Sbostic 		res = 1;
17031703Sbostic 		if (!end)
171*42402Sbostic 			break;
17233297Sbostic 		*end = ':';
17331703Sbostic 	}
174*42402Sbostic 	return(res);
17531703Sbostic }
17631703Sbostic 
17731778Sbostic /*
17833809Sbostic  * cat --
17933809Sbostic  *	cat out the file
18031778Sbostic  */
18133809Sbostic cat(fname)
18233809Sbostic 	char *fname;
18331703Sbostic {
18433809Sbostic 	register int fd, n;
18533809Sbostic 	char buf[BUFSIZ];
18631703Sbostic 
18733809Sbostic 	if (!(fd = open(fname, O_RDONLY, 0))) {
18840390Sbostic 		(void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno));
18933809Sbostic 		exit(1);
19031703Sbostic 	}
19133809Sbostic 	while ((n = read(fd, buf, sizeof(buf))) > 0)
19233809Sbostic 		if (write(1, buf, n) != n) {
19340390Sbostic 			(void)fprintf(stderr,
19440390Sbostic 			    "man: write: %s\n", strerror(errno));
19533809Sbostic 			exit(1);
19633809Sbostic 		}
19733809Sbostic 	if (n == -1) {
19840390Sbostic 		(void)fprintf(stderr, "man: read: %s\n", strerror(errno));
19933809Sbostic 		exit(1);
20033809Sbostic 	}
20133809Sbostic 	(void)close(fd);
20231703Sbostic }
20331703Sbostic 
20431778Sbostic /*
20533809Sbostic  * add --
20633809Sbostic  *	add a file name to the list for future paging
20731778Sbostic  */
20833809Sbostic add(fname)
20933354Sbostic 	char *fname;
21031703Sbostic {
21133809Sbostic 	static u_int buflen;
21233809Sbostic 	static int len;
21333809Sbostic 	static char *cp;
21433809Sbostic 	int flen;
21531703Sbostic 
21633809Sbostic 	if (!command) {
21740390Sbostic 		if (!(command = malloc(buflen = 1024)))
21840390Sbostic 			enomem();
21933809Sbostic 		len = strlen(strcpy(command, pager));
22033809Sbostic 		cp = command + len;
22133809Sbostic 	}
22233809Sbostic 	flen = strlen(fname);
22333809Sbostic 	if (len + flen + 2 > buflen) {		/* +2 == space, EOS */
22440390Sbostic 		if (!(command = realloc(command, buflen += 1024)))
22540390Sbostic 			enomem();
22633809Sbostic 		cp = command + len;
22731703Sbostic 	}
22833809Sbostic 	*cp++ = ' ';
22933809Sbostic 	len += flen + 1;			/* +1 = space */
23033809Sbostic 	(void)strcpy(cp, fname);
23133809Sbostic 	cp += flen;
23231703Sbostic }
23331703Sbostic 
23431778Sbostic /*
23540390Sbostic  * check_pager --
23640390Sbostic  *	check the user supplied page information
23740390Sbostic  */
23840390Sbostic char *
23940390Sbostic check_pager(name)
24040390Sbostic 	char *name;
24140390Sbostic {
24240390Sbostic 	register char *p;
243*42402Sbostic 	char *save;
24440390Sbostic 
24540390Sbostic 	/*
24640390Sbostic 	 * if the user uses "more", we make it "more -s"; watch out for
24740390Sbostic 	 * PAGER = "mypager /usr/ucb/more"
24840390Sbostic 	 */
24940390Sbostic 	for (p = name; *p && !isspace(*p); ++p);
25040390Sbostic 	for (; p > name && *p != '/'; --p);
25140390Sbostic 	if (p != name)
25240390Sbostic 		++p;
25340390Sbostic 
25440390Sbostic 	/* make sure it's "more", not "morex" */
25540390Sbostic 	if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){
25640390Sbostic 		save = name;
25740390Sbostic 		/* allocate space to add the "-s" */
25840390Sbostic 		if (!(name =
25940390Sbostic 		    malloc((u_int)(strlen(save) + sizeof("-s") + 1))))
26040390Sbostic 			enomem();
26140390Sbostic 		(void)sprintf(name, "%s %s", save, "-s");
26240390Sbostic 	}
26340390Sbostic 	return(name);
26440390Sbostic }
26540390Sbostic 
26640390Sbostic /*
26734057Sbostic  * jump --
26834057Sbostic  *	strip out flag argument and jump
26934057Sbostic  */
27034057Sbostic jump(argv, flag, name)
27134057Sbostic 	char **argv, *name;
27234057Sbostic 	register char *flag;
27334057Sbostic {
27434057Sbostic 	register char **arg;
27534057Sbostic 
27634057Sbostic 	argv[0] = name;
27734057Sbostic 	for (arg = argv + 1; *arg; ++arg)
27834057Sbostic 		if (!strcmp(*arg, flag))
27934057Sbostic 			break;
28034057Sbostic 	for (; *arg; ++arg)
28134057Sbostic 		arg[0] = arg[1];
28234057Sbostic 	execvp(name, argv);
283*42402Sbostic 	(void)fprintf(stderr, "%s: Command not found.\n", name);
28434057Sbostic 	exit(1);
28534057Sbostic }
28634057Sbostic 
28734057Sbostic /*
28834057Sbostic  * usage --
28940390Sbostic  *	print usage message and die
29034057Sbostic  */
29134057Sbostic usage()
29234057Sbostic {
29340390Sbostic 	(void)fprintf(stderr,
29440390Sbostic 	    "usage: man [-ac] [-M path] [-m path] [section] title ...\n");
29534057Sbostic 	exit(1);
29634057Sbostic }
297