`man tty 4' dumped core on the sparc
[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
9c51a900 15static char sccsid[] = "@(#)man.c 5.27 (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
92b48820 28int f_all, f_cat, f_how, f_where;
011519cd 29char *command, *machine, *p_augment, *p_path, *pager, *progname;
5db167c0 30extern char **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 41 progname = "man";
92b48820 42 while ((ch = getopt(argc, argv, "-acfhkM: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;
92b48820
KB
51 case 'h':
52 f_how = 1;
53 break;
0076013a
KB
54 case 'm':
55 p_augment = optarg;
c2c2eae0
KB
56 break;
57 case 'M':
58 case 'P': /* backward compatibility */
0076013a 59 p_path = optarg;
07b262aa 60 break;
011519cd
KB
61 /*
62 * "man -f" and "man -k" are backward compatible, undocumented
63 * ways of calling whatis(1) and apropos(1).
64 */
c2c2eae0 65 case 'f':
07b262aa 66 jump(argv, "-f", "whatis");
0076013a 67 /* NOTREACHED */
c2c2eae0 68 case 'k':
07b262aa 69 jump(argv, "-k", "apropos");
0076013a 70 /* NOTREACHED */
da0e94fc 71 case 'w':
0076013a 72 f_all = f_where = 1;
da0e94fc 73 break;
c2c2eae0
KB
74 case '?':
75 default:
07b262aa 76 usage();
c2c2eae0 77 }
07b262aa 78 argv += optind;
bb1b89c7 79
07b262aa
KB
80 if (!*argv)
81 usage();
c2c2eae0 82
92b48820 83 if (!f_cat && !f_how)
c2c2eae0 84 if (!isatty(1))
0076013a
KB
85 f_cat = 1;
86 else if (pager = getenv("PAGER"))
87 pager = check_pager(pager);
81cd4ba7 88 else
ade4c407 89 pager = _PATH_PAGER;
0076013a 90
c2c2eae0
KB
91 if (!(machine = getenv("MACHINE")))
92 machine = MACHINE;
0076013a 93
011519cd
KB
94 /* see if checking in a specific section */
95 if (argc > 1 && getsection(*argv)) {
96 section[0] = *argv++;
97 section[1] = (char *)NULL;
98 } else {
99 section[0] = "_default";
100 section[1] = (char *)NULL;
101 }
102
a201b3c4
TH
103 arorder = getorder();
104 if (p_path || (p_path = getenv("MANPATH"))) {
105 char buf[MAXPATHLEN], **av;
106
9c51a900 107 tmp = strtok(p_path, ":");
a201b3c4 108 while (tmp) {
e2c0cfa0 109 (void)snprintf(buf, sizeof(buf), "%s/", tmp);
a201b3c4 110 for (av = arorder; *av; ++av)
9c51a900
KB
111 cadd(buf, strlen(buf), *av);
112 tmp = strtok(NULL, ":");
a201b3c4
TH
113 }
114 p_path = pathbuf;
115 } else if (!(p_path = getpath(section)) && !p_augment) {
011519cd 116 (void)fprintf(stderr,
a201b3c4 117 "man: no place to search for those manual pages.\n");
011519cd
KB
118 exit(1);
119 }
0076013a 120
011519cd
KB
121 for (; *argv; ++argv) {
122 if (p_augment)
123 res = manual(p_augment, *argv);
124 res = manual(p_path, *argv);
732d562d
KB
125 if (!res && !f_where)
126 (void)fprintf(stderr,
127 "man: no entry for %s in the manual.\n", *argv);
011519cd 128 }
0076013a 129
b5e4dc7e 130 /* use system(3) in case someone's pager is "pager arg1 arg2" */
c56621e7
KB
131 if (command)
132 (void)system(command);
bb1b89c7
KB
133 exit(0);
134}
135
8f946e8d
KB
136/*
137 * manual --
0076013a
KB
138 * given a path, a directory list and a file name, find a file
139 * that matches; check ${directory}/${dir}/{file name} and
c56621e7 140 * ${directory}/${dir}/${machine}/${file name}.
8f946e8d 141 */
011519cd 142manual(path, name)
0076013a 143 char *path, *name;
c2c2eae0 144{
c56621e7 145 register int res;
9c51a900 146 register char *cp;
0076013a 147 char fname[MAXPATHLEN + 1];
c2c2eae0 148
9c51a900
KB
149 for (res = 0; path != NULL && *path != '\0'; path = cp) {
150 if (cp = strchr(path, ':')) {
151 if (cp == path + 1) { /* foo::bar */
152 ++cp;
011519cd 153 continue;
9c51a900
KB
154 }
155 *cp = '\0';
c56621e7 156 }
011519cd
KB
157 (void)sprintf(fname, "%s/%s.0", path, name);
158 if (access(fname, R_OK)) {
159 (void)sprintf(fname, "%s/%s/%s.0", path, machine, name);
9c51a900
KB
160 if (access(fname, R_OK)) {
161 ++cp;
011519cd 162 continue;
9c51a900 163 }
011519cd
KB
164 }
165
166 if (f_where)
167 (void)printf("man: found in %s.\n", fname);
168 else if (f_cat)
169 cat(fname);
92b48820
KB
170 else if (f_how)
171 how(fname);
011519cd
KB
172 else
173 add(fname);
174 if (!f_all)
175 return(1);
176 res = 1;
9c51a900
KB
177 if (cp)
178 *cp++ = ':';
c2c2eae0 179 }
011519cd 180 return(res);
c2c2eae0
KB
181}
182
92b48820
KB
183/*
184 * how --
185 * display how information
186 */
187how(fname)
188 char *fname;
189{
190 register FILE *fp;
191
192 register int lcnt, print;
193 register char *p;
194 char buf[BUFSIZ];
195
196 if (!(fp = fopen(fname, "r"))) {
197 (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno));
198 exit(1);
199 }
200#define S1 "SYNOPSIS"
201#define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS"
202#define D1 "DESCRIPTION"
203#define D2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN"
204 for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) {
205 if (!strncmp(buf, S1, sizeof(S1) - 1) ||
206 !strncmp(buf, S2, sizeof(S2) - 1)) {
207 print = 1;
208 continue;
209 } else if (!strncmp(buf, D1, sizeof(D1) - 1) ||
210 !strncmp(buf, D2, sizeof(D2) - 1))
211 return;
212 if (!print)
213 continue;
214 if (*buf == '\n')
215 ++lcnt;
216 else {
217 for(; lcnt; --lcnt)
218 (void)putchar('\n');
219 for (p = buf; isspace(*p); ++p);
220 (void)fputs(p, stdout);
221 }
222 }
223 (void)fclose(fp);
224}
8f946e8d 225/*
c56621e7
KB
226 * cat --
227 * cat out the file
8f946e8d 228 */
c56621e7
KB
229cat(fname)
230 char *fname;
c2c2eae0 231{
c56621e7
KB
232 register int fd, n;
233 char buf[BUFSIZ];
c2c2eae0 234
92b48820 235 if ((fd = open(fname, O_RDONLY, 0)) < 0) {
0076013a 236 (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno));
c56621e7 237 exit(1);
c2c2eae0 238 }
c56621e7
KB
239 while ((n = read(fd, buf, sizeof(buf))) > 0)
240 if (write(1, buf, n) != n) {
0076013a
KB
241 (void)fprintf(stderr,
242 "man: write: %s\n", strerror(errno));
c56621e7
KB
243 exit(1);
244 }
245 if (n == -1) {
0076013a 246 (void)fprintf(stderr, "man: read: %s\n", strerror(errno));
c56621e7
KB
247 exit(1);
248 }
249 (void)close(fd);
c2c2eae0
KB
250}
251
8f946e8d 252/*
c56621e7
KB
253 * add --
254 * add a file name to the list for future paging
8f946e8d 255 */
c56621e7 256add(fname)
bb1b89c7 257 char *fname;
c2c2eae0 258{
c56621e7
KB
259 static u_int buflen;
260 static int len;
261 static char *cp;
262 int flen;
c2c2eae0 263
c56621e7 264 if (!command) {
0076013a
KB
265 if (!(command = malloc(buflen = 1024)))
266 enomem();
c56621e7
KB
267 len = strlen(strcpy(command, pager));
268 cp = command + len;
269 }
270 flen = strlen(fname);
271 if (len + flen + 2 > buflen) { /* +2 == space, EOS */
0076013a
KB
272 if (!(command = realloc(command, buflen += 1024)))
273 enomem();
c56621e7 274 cp = command + len;
c2c2eae0 275 }
c56621e7
KB
276 *cp++ = ' ';
277 len += flen + 1; /* +1 = space */
278 (void)strcpy(cp, fname);
279 cp += flen;
c2c2eae0
KB
280}
281
0076013a
KB
282/*
283 * check_pager --
284 * check the user supplied page information
285 */
286char *
287check_pager(name)
288 char *name;
289{
290 register char *p;
011519cd 291 char *save;
0076013a
KB
292
293 /*
294 * if the user uses "more", we make it "more -s"; watch out for
295 * PAGER = "mypager /usr/ucb/more"
296 */
297 for (p = name; *p && !isspace(*p); ++p);
298 for (; p > name && *p != '/'; --p);
299 if (p != name)
300 ++p;
301
302 /* make sure it's "more", not "morex" */
303 if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){
304 save = name;
305 /* allocate space to add the "-s" */
306 if (!(name =
307 malloc((u_int)(strlen(save) + sizeof("-s") + 1))))
308 enomem();
309 (void)sprintf(name, "%s %s", save, "-s");
bb1b89c7 310 }
0076013a 311 return(name);
c2c2eae0 312}
07b262aa
KB
313
314/*
315 * jump --
316 * strip out flag argument and jump
317 */
07b262aa
KB
318jump(argv, flag, name)
319 char **argv, *name;
320 register char *flag;
321{
322 register char **arg;
323
324 argv[0] = name;
325 for (arg = argv + 1; *arg; ++arg)
326 if (!strcmp(*arg, flag))
327 break;
328 for (; *arg; ++arg)
329 arg[0] = arg[1];
330 execvp(name, argv);
011519cd 331 (void)fprintf(stderr, "%s: Command not found.\n", name);
07b262aa
KB
332 exit(1);
333}
334
335/*
336 * usage --
0076013a 337 * print usage message and die
07b262aa 338 */
07b262aa
KB
339usage()
340{
0076013a
KB
341 (void)fprintf(stderr,
342 "usage: man [-ac] [-M path] [-m path] [section] title ...\n");
07b262aa
KB
343 exit(1);
344}