pcb lookup cache; IP_RECVDSTADDR support; additional statistics;
[unix-history] / usr / src / usr.bin / man / man.c
CommitLineData
c2c2eae0
KB
1/*
2 * Copyright (c) 1987 Regents of the University of California.
ea9afd82
KB
3 * All rights reserved.
4 *
f15db449 5 * %sccs.include.redist.c%
c2c2eae0
KB
6 */
7
8#ifndef lint
9char copyright[] =
10"@(#) Copyright (c) 1987 Regents of the University of California.\n\
11 All rights reserved.\n";
ea9afd82 12#endif /* not lint */
c2c2eae0
KB
13
14#ifndef lint
a201b3c4 15static char sccsid[] = "@(#)man.c 5.22 (Berkeley) %G%";
ea9afd82 16#endif /* not lint */
c2c2eae0
KB
17
18#include <sys/param.h>
19#include <sys/file.h>
0076013a 20#include <errno.h>
c2c2eae0 21#include <ctype.h>
0076013a 22#include <string.h>
011519cd 23#include <stdlib.h>
ade4c407 24#include "pathnames.h"
4610900a 25
0076013a 26extern int errno;
07b262aa 27
0076013a 28int f_all, f_cat, f_where;
011519cd 29char *command, *machine, *p_augment, *p_path, *pager, *progname;
a201b3c4 30char **arorder, *pathbuf;
c2c2eae0
KB
31
32main(argc, argv)
bb1b89c7
KB
33 int argc;
34 register char **argv;
c2c2eae0 35{
07b262aa
KB
36 extern char *optarg;
37 extern int optind;
011519cd 38 int ch, res;
a201b3c4 39 char *section[2], *check_pager(), *getpath(), **getorder(), *tmp;
c2c2eae0 40
0076013a
KB
41 progname = "man";
42 while ((ch = getopt(argc, argv, "-acfkM:m:P:w")) != EOF)
07b262aa 43 switch((char)ch) {
0076013a
KB
44 case 'a':
45 f_all = 1;
46 break;
47 case 'c':
48 case '-': /* deprecated */
49 f_cat = 1;
50 break;
51 case 'm':
52 p_augment = optarg;
c2c2eae0
KB
53 break;
54 case 'M':
55 case 'P': /* backward compatibility */
0076013a 56 p_path = optarg;
07b262aa 57 break;
011519cd
KB
58 /*
59 * "man -f" and "man -k" are backward compatible, undocumented
60 * ways of calling whatis(1) and apropos(1).
61 */
c2c2eae0 62 case 'f':
07b262aa 63 jump(argv, "-f", "whatis");
0076013a 64 /* NOTREACHED */
c2c2eae0 65 case 'k':
07b262aa 66 jump(argv, "-k", "apropos");
0076013a 67 /* NOTREACHED */
da0e94fc 68 case 'w':
0076013a 69 f_all = f_where = 1;
da0e94fc 70 break;
c2c2eae0
KB
71 case '?':
72 default:
07b262aa 73 usage();
c2c2eae0 74 }
07b262aa 75 argv += optind;
bb1b89c7 76
07b262aa
KB
77 if (!*argv)
78 usage();
c2c2eae0 79
0076013a 80 if (!f_cat)
c2c2eae0 81 if (!isatty(1))
0076013a
KB
82 f_cat = 1;
83 else if (pager = getenv("PAGER"))
84 pager = check_pager(pager);
81cd4ba7 85 else
ade4c407 86 pager = _PATH_PAGER;
0076013a 87
c2c2eae0
KB
88 if (!(machine = getenv("MACHINE")))
89 machine = MACHINE;
0076013a 90
011519cd
KB
91 /* see if checking in a specific section */
92 if (argc > 1 && getsection(*argv)) {
93 section[0] = *argv++;
94 section[1] = (char *)NULL;
95 } else {
96 section[0] = "_default";
97 section[1] = (char *)NULL;
98 }
99
a201b3c4
TH
100 arorder = getorder();
101 if (p_path || (p_path = getenv("MANPATH"))) {
102 char buf[MAXPATHLEN], **av;
103
104 tmp = strtok(p_path, ":");
105 while (tmp) {
106 (void)sprintf(buf, "%s/", tmp);
107 for (av = arorder; *av; ++av)
108 cadd(buf, strlen(buf), *av);
109 tmp = strtok((char *)NULL, ":");
110 }
111 p_path = pathbuf;
112 } else if (!(p_path = getpath(section)) && !p_augment) {
011519cd 113 (void)fprintf(stderr,
a201b3c4 114 "man: no place to search for those manual pages.\n");
011519cd
KB
115 exit(1);
116 }
0076013a 117
011519cd
KB
118 for (; *argv; ++argv) {
119 if (p_augment)
120 res = manual(p_augment, *argv);
121 res = manual(p_path, *argv);
122 if (res || f_where)
123 continue;
124 (void)fprintf(stderr,
125 "man: no entry for %s in the manual.\n", *argv);
126 exit(1);
127 }
0076013a 128
b5e4dc7e 129 /* use system(3) in case someone's pager is "pager arg1 arg2" */
c56621e7
KB
130 if (command)
131 (void)system(command);
bb1b89c7
KB
132 exit(0);
133}
134
8f946e8d
KB
135/*
136 * manual --
0076013a
KB
137 * given a path, a directory list and a file name, find a file
138 * that matches; check ${directory}/${dir}/{file name} and
c56621e7 139 * ${directory}/${dir}/${machine}/${file name}.
8f946e8d 140 */
011519cd 141manual(path, name)
0076013a 142 char *path, *name;
c2c2eae0 143{
c56621e7 144 register int res;
011519cd 145 register char *end;
0076013a 146 char fname[MAXPATHLEN + 1];
c2c2eae0 147
0076013a 148 for (res = 0;; path = end + 1) {
011519cd
KB
149 if (!*path) /* foo: */
150 break;
151 if (end = index(path, ':')) {
152 if (end == path + 1) /* foo::bar */
153 continue;
c2c2eae0 154 *end = '\0';
c56621e7 155 }
011519cd
KB
156 (void)sprintf(fname, "%s/%s.0", path, name);
157 if (access(fname, R_OK)) {
158 (void)sprintf(fname, "%s/%s/%s.0", path, machine, name);
159 if (access(fname, R_OK))
160 continue;
161 }
162
163 if (f_where)
164 (void)printf("man: found in %s.\n", fname);
165 else if (f_cat)
166 cat(fname);
167 else
168 add(fname);
169 if (!f_all)
170 return(1);
171 res = 1;
c2c2eae0 172 if (!end)
011519cd 173 break;
fe684fa4 174 *end = ':';
c2c2eae0 175 }
011519cd 176 return(res);
c2c2eae0
KB
177}
178
8f946e8d 179/*
c56621e7
KB
180 * cat --
181 * cat out the file
8f946e8d 182 */
c56621e7
KB
183cat(fname)
184 char *fname;
c2c2eae0 185{
c56621e7
KB
186 register int fd, n;
187 char buf[BUFSIZ];
c2c2eae0 188
c56621e7 189 if (!(fd = open(fname, O_RDONLY, 0))) {
0076013a 190 (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno));
c56621e7 191 exit(1);
c2c2eae0 192 }
c56621e7
KB
193 while ((n = read(fd, buf, sizeof(buf))) > 0)
194 if (write(1, buf, n) != n) {
0076013a
KB
195 (void)fprintf(stderr,
196 "man: write: %s\n", strerror(errno));
c56621e7
KB
197 exit(1);
198 }
199 if (n == -1) {
0076013a 200 (void)fprintf(stderr, "man: read: %s\n", strerror(errno));
c56621e7
KB
201 exit(1);
202 }
203 (void)close(fd);
c2c2eae0
KB
204}
205
8f946e8d 206/*
c56621e7
KB
207 * add --
208 * add a file name to the list for future paging
8f946e8d 209 */
c56621e7 210add(fname)
bb1b89c7 211 char *fname;
c2c2eae0 212{
c56621e7
KB
213 static u_int buflen;
214 static int len;
215 static char *cp;
216 int flen;
c2c2eae0 217
c56621e7 218 if (!command) {
0076013a
KB
219 if (!(command = malloc(buflen = 1024)))
220 enomem();
c56621e7
KB
221 len = strlen(strcpy(command, pager));
222 cp = command + len;
223 }
224 flen = strlen(fname);
225 if (len + flen + 2 > buflen) { /* +2 == space, EOS */
0076013a
KB
226 if (!(command = realloc(command, buflen += 1024)))
227 enomem();
c56621e7 228 cp = command + len;
c2c2eae0 229 }
c56621e7
KB
230 *cp++ = ' ';
231 len += flen + 1; /* +1 = space */
232 (void)strcpy(cp, fname);
233 cp += flen;
c2c2eae0
KB
234}
235
0076013a
KB
236/*
237 * check_pager --
238 * check the user supplied page information
239 */
240char *
241check_pager(name)
242 char *name;
243{
244 register char *p;
011519cd 245 char *save;
0076013a
KB
246
247 /*
248 * if the user uses "more", we make it "more -s"; watch out for
249 * PAGER = "mypager /usr/ucb/more"
250 */
251 for (p = name; *p && !isspace(*p); ++p);
252 for (; p > name && *p != '/'; --p);
253 if (p != name)
254 ++p;
255
256 /* make sure it's "more", not "morex" */
257 if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){
258 save = name;
259 /* allocate space to add the "-s" */
260 if (!(name =
261 malloc((u_int)(strlen(save) + sizeof("-s") + 1))))
262 enomem();
263 (void)sprintf(name, "%s %s", save, "-s");
bb1b89c7 264 }
0076013a 265 return(name);
c2c2eae0 266}
07b262aa
KB
267
268/*
269 * jump --
270 * strip out flag argument and jump
271 */
07b262aa
KB
272jump(argv, flag, name)
273 char **argv, *name;
274 register char *flag;
275{
276 register char **arg;
277
278 argv[0] = name;
279 for (arg = argv + 1; *arg; ++arg)
280 if (!strcmp(*arg, flag))
281 break;
282 for (; *arg; ++arg)
283 arg[0] = arg[1];
284 execvp(name, argv);
011519cd 285 (void)fprintf(stderr, "%s: Command not found.\n", name);
07b262aa
KB
286 exit(1);
287}
288
289/*
290 * usage --
0076013a 291 * print usage message and die
07b262aa 292 */
07b262aa
KB
293usage()
294{
0076013a
KB
295 (void)fprintf(stderr,
296 "usage: man [-ac] [-M path] [-m path] [section] title ...\n");
07b262aa
KB
297 exit(1);
298}