xref: /csrg-svn/usr.bin/man/man.c (revision 31703)
1*31703Sbostic /*
2*31703Sbostic  * Copyright (c) 1987 Regents of the University of California.
3*31703Sbostic  * All rights reserved.  The Berkeley software License Agreement
4*31703Sbostic  * specifies the terms and conditions for redistribution.
5*31703Sbostic  */
6*31703Sbostic 
7*31703Sbostic #ifndef lint
8*31703Sbostic char copyright[] =
9*31703Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\
10*31703Sbostic  All rights reserved.\n";
11*31703Sbostic #endif not lint
12*31703Sbostic 
13*31703Sbostic #ifndef lint
14*31703Sbostic static char sccsid[] = "@(#)man.c	5.1 (Berkeley) 06/29/87";
15*31703Sbostic #endif not lint
16*31703Sbostic 
17*31703Sbostic #include <sys/param.h>
18*31703Sbostic #include <sys/file.h>
19*31703Sbostic #include <ctype.h>
20*31703Sbostic 
21*31703Sbostic #define	DEF_PAGER	"more -s"	/* paging filter */
22*31703Sbostic #define	DEF_PATH	"/usr/man"	/* default path */
23*31703Sbostic #define	NO		0		/* no/false */
24*31703Sbostic #define	YES		1		/* yes/true */
25*31703Sbostic 
26*31703Sbostic /*
27*31703Sbostic  * See code for more info on this kludge; suffice it to say that the
28*31703Sbostic  * local, new and old defines *have* to map into the dirlist array
29*31703Sbostic  * correctly.  Notice also that cat1 is in array slot 1, etc. etc.
30*31703Sbostic  * Continue to notice that it's also ordered for searching, i.e.
31*31703Sbostic  * slots 1 - N are in the order you wish to search the directories.
32*31703Sbostic  */
33*31703Sbostic #define	NO_SECTION	0
34*31703Sbostic #define	LOCAL_SECTION	9
35*31703Sbostic #define	NEW_SECTION	10
36*31703Sbostic #define	OLD_SECTION	11
37*31703Sbostic #define	isname(x)	(x==LOCAL_SECTION || x==NEW_SECTION || x==OLD_SECTION)
38*31703Sbostic static char	*machine,		/* machine type */
39*31703Sbostic 		*manpath,		/* search path */
40*31703Sbostic 		*pager,			/* pager */
41*31703Sbostic 		*dirlist[] = {		/* sub-directory list */
42*31703Sbostic 	"notused", 	"cat1",		"cat2",		"cat3",
43*31703Sbostic 	"cat4",		"cat5",		"cat6",		"cat7",
44*31703Sbostic 	"cat8",		"local",	"new",		"old",
45*31703Sbostic 	NULL,
46*31703Sbostic };
47*31703Sbostic 
48*31703Sbostic static int	nomore;			/* don't use more */
49*31703Sbostic 
50*31703Sbostic main(argc, argv)
51*31703Sbostic 	int	argc;
52*31703Sbostic 	char	**argv;
53*31703Sbostic {
54*31703Sbostic 	int	section;
55*31703Sbostic 	char	**arg_start, **arg,
56*31703Sbostic 		*getenv();
57*31703Sbostic 
58*31703Sbostic 	arg_start = argv;
59*31703Sbostic 	for (--argc, ++argv; argc && (*argv)[0] == '-'; --argc, ++argv)
60*31703Sbostic 		switch((*argv)[1]) {
61*31703Sbostic 		case 0:			/* just write to stdout */
62*31703Sbostic 			nomore = YES;
63*31703Sbostic 			break;
64*31703Sbostic 		case 'M':
65*31703Sbostic 		case 'P':		/* backward compatibility */
66*31703Sbostic 			if ((*argv)[2])
67*31703Sbostic 				manpath = *argv + 2;
68*31703Sbostic 			else {
69*31703Sbostic 				if (argc < 2) {
70*31703Sbostic 					fprintf(stderr, "%s: missing path\n", *argv);
71*31703Sbostic 					exit(1);
72*31703Sbostic 				}
73*31703Sbostic 				--argc;
74*31703Sbostic 				manpath = *++argv;
75*31703Sbostic 			}
76*31703Sbostic 			break;
77*31703Sbostic 		/*
78*31703Sbostic 		 * "man -f" and "man -k" are undocumented ways of calling
79*31703Sbostic 		 * whatis(1) and apropos(1).  Just strip out the flag
80*31703Sbostic 		 * argument and jump.
81*31703Sbostic 		 */
82*31703Sbostic 		case 'f':
83*31703Sbostic 			for (arg = argv; arg[0] = arg[1]; ++arg);
84*31703Sbostic 			*arg_start = "whatis";
85*31703Sbostic 			execvp(*arg_start, arg_start);
86*31703Sbostic 			fputs("whatis: Command not found.\n", stderr);
87*31703Sbostic 			exit(1);
88*31703Sbostic 		case 'k':
89*31703Sbostic 			for (arg = argv; *arg = arg[1]; ++arg);
90*31703Sbostic 			*arg_start = "apropos";
91*31703Sbostic 			execvp(*arg_start, arg_start);
92*31703Sbostic 			fputs("apropos: Command not found.\n", stderr);
93*31703Sbostic 			exit(1);
94*31703Sbostic 		case '?':
95*31703Sbostic 		default:
96*31703Sbostic 			usage();
97*31703Sbostic 		}
98*31703Sbostic 	if (!argc)
99*31703Sbostic 		usage();
100*31703Sbostic 
101*31703Sbostic 	if (!nomore)
102*31703Sbostic 		if (!isatty(1))
103*31703Sbostic 			nomore = YES;
104*31703Sbostic 		else if (!(pager = getenv("PAGER")))
105*31703Sbostic 			pager = DEF_PAGER;
106*31703Sbostic 	if (!(machine = getenv("MACHINE")))
107*31703Sbostic 		machine = MACHINE;
108*31703Sbostic 	if (!manpath && !(manpath = getenv("MANPATH")))
109*31703Sbostic 		manpath = DEF_PATH;
110*31703Sbostic 	for (; *manpath && *manpath == ':'; ++manpath);
111*31703Sbostic 
112*31703Sbostic 	for (; *argv; ++argv) {
113*31703Sbostic 		section = NO_SECTION;
114*31703Sbostic 		switch(**argv) {
115*31703Sbostic 		/*
116*31703Sbostic 		 * hardwired section numbers, fix here if they do; note,
117*31703Sbostic 		 * only works for single digits.
118*31703Sbostic 		 */
119*31703Sbostic 		case '1': case '2': case '3': case '4':
120*31703Sbostic 		case '5': case '6': case '7': case '8':
121*31703Sbostic 			if (!(*argv)[1]) {
122*31703Sbostic 				section = (*argv)[0] - '0';
123*31703Sbostic 				if (!*++argv) {
124*31703Sbostic 					fprintf(stderr, "man: what do you want from section %d?\n", section);
125*31703Sbostic 					exit(1);
126*31703Sbostic 				}
127*31703Sbostic 			}
128*31703Sbostic 			break;
129*31703Sbostic 		/*
130*31703Sbostic 		 * backward compatibility: manl == local, mann == new,
131*31703Sbostic 		 * mano == old;
132*31703Sbostic 		 */
133*31703Sbostic 		case 'l':
134*31703Sbostic 			if (!*argv[1] || !strcmp(*argv, dirlist[LOCAL_SECTION])) {
135*31703Sbostic 				section = LOCAL_SECTION;
136*31703Sbostic 				goto argtest;
137*31703Sbostic 			}
138*31703Sbostic 			break;
139*31703Sbostic 		case 'n':
140*31703Sbostic 			if (!*argv[1] || !strcmp(*argv, dirlist[NEW_SECTION])) {
141*31703Sbostic 				section = NEW_SECTION;
142*31703Sbostic 				goto argtest;
143*31703Sbostic 			}
144*31703Sbostic 			break;
145*31703Sbostic 		case 'o':
146*31703Sbostic 			if (!*argv[1] || !strcmp(*argv, dirlist[OLD_SECTION])) {
147*31703Sbostic 				section = OLD_SECTION;
148*31703Sbostic argtest:			if (!*++argv) {
149*31703Sbostic 					fprintf(stderr, "man: what do you want from the %s section?\n", dirlist[section]);
150*31703Sbostic 					exit(1);
151*31703Sbostic 				}
152*31703Sbostic 			}
153*31703Sbostic 			break;
154*31703Sbostic 		}
155*31703Sbostic 		if (!manual(section, *argv))
156*31703Sbostic 			if (section == NO_SECTION)
157*31703Sbostic 				fprintf(stderr, "No manual entry for %s.\n", *argv);
158*31703Sbostic 			else if (isname(section))
159*31703Sbostic 				fprintf(stderr, "No entry for %s in the %s section of the manual.\n", *argv, dirlist[section]);
160*31703Sbostic 			else
161*31703Sbostic 				fprintf(stderr, "No entry for %s in section %d of the manual.\n", *argv, section);
162*31703Sbostic 	}
163*31703Sbostic 	exit(0);
164*31703Sbostic }
165*31703Sbostic 
166*31703Sbostic static
167*31703Sbostic manual(section, name)
168*31703Sbostic 	int	section;
169*31703Sbostic 	char	*name;
170*31703Sbostic {
171*31703Sbostic 	register char	*beg, *end, **dir;
172*31703Sbostic 	char	*index();
173*31703Sbostic 
174*31703Sbostic 	for (beg = manpath;; beg = end + 1) {
175*31703Sbostic 		if (end = index(beg, ':'))
176*31703Sbostic 			*end = '\0';
177*31703Sbostic 		if (section == NO_SECTION) {
178*31703Sbostic 			/* notice the +1... */
179*31703Sbostic 			for (dir = dirlist + 1; *dir; ++dir)
180*31703Sbostic 				if (find(beg, *dir, name))
181*31703Sbostic 					return(YES);
182*31703Sbostic 		}
183*31703Sbostic 		else if (find(beg, dirlist[section], name))
184*31703Sbostic 			return(YES);
185*31703Sbostic 		if (!end)
186*31703Sbostic 			return(NO);
187*31703Sbostic 	}
188*31703Sbostic 	/*NOTREACHED*/
189*31703Sbostic }
190*31703Sbostic 
191*31703Sbostic static
192*31703Sbostic find(beg, dir, name)
193*31703Sbostic 	char	*beg, *dir, *name;
194*31703Sbostic {
195*31703Sbostic 	char	fname[MAXPATHLEN + 1];
196*31703Sbostic 
197*31703Sbostic 	(void)sprintf(fname, "%s/%s/%s", beg, dir, name);
198*31703Sbostic 	if (!access(fname, R_OK)) {
199*31703Sbostic 		show(fname);
200*31703Sbostic 		return(YES);
201*31703Sbostic 	}
202*31703Sbostic 	(void)sprintf(fname, "%s/%s/%s/%s", beg, dir, machine, name);
203*31703Sbostic 	if (!access(fname, R_OK)) {
204*31703Sbostic 		show(fname);
205*31703Sbostic 		return(YES);
206*31703Sbostic 	}
207*31703Sbostic 	return(NO);
208*31703Sbostic }
209*31703Sbostic 
210*31703Sbostic static
211*31703Sbostic show(fname)
212*31703Sbostic 	char	*fname;
213*31703Sbostic {
214*31703Sbostic 	register int	fd, n;
215*31703Sbostic 	char	buf[BUFSIZ];
216*31703Sbostic 
217*31703Sbostic 	if (nomore) {
218*31703Sbostic 		if (!(fd = open(fname, O_RDONLY, 0))) {
219*31703Sbostic 			perror("man: open");
220*31703Sbostic 			exit(1);
221*31703Sbostic 		}
222*31703Sbostic 		while ((n = read(fd, buf, sizeof(buf))) > 0)
223*31703Sbostic 			if (write(1, buf, n) != n) {
224*31703Sbostic 				perror("man: write");
225*31703Sbostic 				exit(1);
226*31703Sbostic 			}
227*31703Sbostic 		if (n == -1) {
228*31703Sbostic 			perror("man: read");
229*31703Sbostic 			exit(1);
230*31703Sbostic 		}
231*31703Sbostic 		(void)close(fd);
232*31703Sbostic 	}
233*31703Sbostic 	else {
234*31703Sbostic 		/*
235*31703Sbostic 		 * use system(2) in case someone's pager is
236*31703Sbostic 		 * "command arg1 arg2"
237*31703Sbostic 		 */
238*31703Sbostic 		(void)sprintf(buf, "%s %s", pager, fname);
239*31703Sbostic 		(void)system(buf);
240*31703Sbostic 	}
241*31703Sbostic }
242*31703Sbostic 
243*31703Sbostic static
244*31703Sbostic usage()
245*31703Sbostic {
246*31703Sbostic 	fputs("usage: man [-] [-M path] [section] title ...\n", stderr);
247*31703Sbostic 	exit(1);
248*31703Sbostic }
249