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