Commit | Line | Data |
---|---|---|
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 | |
9 | char 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 | |
5db167c0 | 15 | static char sccsid[] = "@(#)man.c 5.23 (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 | 26 | extern int errno; |
07b262aa | 27 | |
0076013a | 28 | int f_all, f_cat, f_where; |
011519cd | 29 | char *command, *machine, *p_augment, *p_path, *pager, *progname; |
5db167c0 | 30 | extern char **arorder, *pathbuf; |
c2c2eae0 KB |
31 | |
32 | main(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 | 141 | manual(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 |
183 | cat(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 | 210 | add(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 | */ | |
240 | char * | |
241 | check_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 |
272 | jump(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 |
293 | usage() |
294 | { | |
0076013a KB |
295 | (void)fprintf(stderr, |
296 | "usage: man [-ac] [-M path] [-m path] [section] title ...\n"); | |
07b262aa KB |
297 | exit(1); |
298 | } |