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 | |
9c51a900 | 15 | static 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 | 26 | extern int errno; |
07b262aa | 27 | |
92b48820 | 28 | int f_all, f_cat, f_how, 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 | 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 | 142 | manual(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 | */ | |
187 | how(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 |
229 | cat(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 | 256 | add(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 | */ | |
286 | char * | |
287 | check_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 |
318 | jump(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 |
339 | usage() |
340 | { | |
0076013a KB |
341 | (void)fprintf(stderr, |
342 | "usage: man [-ac] [-M path] [-m path] [section] title ...\n"); | |
07b262aa KB |
343 | exit(1); |
344 | } |