|
|
1.1 root 1: /*
2: * Copyright (c) 1987 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that the above copyright notice and this paragraph are
7: * duplicated in all such forms and that any documentation,
8: * advertising materials, and other materials related to such
9: * distribution and use acknowledge that the software was developed
10: * by the University of California, Berkeley. The name of the
11: * University may not be used to endorse or promote products derived
12: * from this software without specific prior written permission.
13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16: */
17:
18: #ifndef lint
19: char copyright[] =
20: "@(#) Copyright (c) 1987 Regents of the University of California.\n\
21: All rights reserved.\n";
22: #endif /* not lint */
23:
24: #ifndef lint
25: static char sccsid[] = "@(#)man.c 5.17 (Berkeley) 6/29/88";
26: #endif /* not lint */
27:
28: #include <sys/param.h>
29: #include <sys/file.h>
30: #include <stdio.h>
31: #include <ctype.h>
32:
33: #define DEF_PAGER "/usr/ucb/more -s"
34: #define DEF_PATH "/usr/man:/usr/new/man:/usr/local/man"
35: #define LOCAL_PATH "/usr/local/man"
36: #define NEW_PATH "/usr/new/man"
37:
38: #define NO 0
39: #define YES 1
40:
41: static char *command, /* command buffer */
42: *defpath, /* default search path */
43: *locpath, /* local search path */
44: *machine, /* machine type */
45: *manpath, /* current search path */
46: *newpath, /* new search path */
47: *pager, /* requested pager */
48: how; /* how to display */
49:
50: #define ALL 0x1 /* show all man pages */
51: #define CAT 0x2 /* copy file to stdout */
52: #define WHERE 0x4 /* just tell me where */
53:
54: main(argc, argv)
55: int argc;
56: register char **argv;
57: {
58: extern char *optarg;
59: extern int optind;
60: int ch;
61: char *getenv(), *malloc();
62:
63: while ((ch = getopt(argc, argv, "-M:P:afkw")) != EOF)
64: switch((char)ch) {
65: case '-':
66: how |= CAT;
67: break;
68: case 'M':
69: case 'P': /* backward compatibility */
70: defpath = optarg;
71: break;
72: case 'a':
73: how |= ALL;
74: break;
75: /*
76: * "man -f" and "man -k" are backward contemptible,
77: * undocumented ways of calling whatis(1) and apropos(1).
78: */
79: case 'f':
80: jump(argv, "-f", "whatis");
81: /*NOTREACHED*/
82: case 'k':
83: jump(argv, "-k", "apropos");
84: /*NOTREACHED*/
85: /*
86: * Deliberately undocumented; really only useful when
87: * you're moving man pages around. Not worth adding.
88: */
89: case 'w':
90: how |= WHERE | ALL;
91: break;
92: case '?':
93: default:
94: usage();
95: }
96: argv += optind;
97:
98: if (!*argv)
99: usage();
100:
101: if (!(how & CAT))
102: if (!isatty(1))
103: how |= CAT;
104: else if (pager = getenv("PAGER")) {
105: register char *p;
106:
107: /*
108: * if the user uses "more", we make it "more -s"
109: * watch out for PAGER = "mypager /usr/ucb/more"
110: */
111: for (p = pager; *p && !isspace(*p); ++p);
112: for (; p > pager && *p != '/'; --p);
113: if (p != pager)
114: ++p;
115: /* make sure it's "more", not "morex" */
116: if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){
117: char *opager = pager;
118: /*
119: * allocate space to add the "-s"
120: */
121: if (!(pager = malloc((u_int)(strlen(opager)
122: + sizeof("-s") + 1)))) {
123: fputs("man: out of space.\n", stderr);
124: exit(1);
125: }
126: (void)sprintf(pager, "%s %s", opager, "-s");
127: }
128: }
129: else
130: pager = DEF_PAGER;
131: if (!(machine = getenv("MACHINE")))
132: machine = MACHINE;
133: if (!defpath && !(defpath = getenv("MANPATH")))
134: defpath = DEF_PATH;
135: locpath = LOCAL_PATH;
136: newpath = NEW_PATH;
137: man(argv);
138: /* use system(3) in case someone's pager is "pager arg1 arg2" */
139: if (command)
140: (void)system(command);
141: exit(0);
142: }
143:
144: typedef struct {
145: char *name, *msg;
146: } DIR;
147: static DIR list1[] = { /* section one list */
148: "cat1", "1st", "cat8", "8th", "cat6", "6th",
149: "cat.old", "old", NULL, NULL,
150: }, list2[] = { /* rest of the list */
151: "cat2", "2nd", "cat3", "3rd", "cat4", "4th",
152: "cat5", "5th", "cat7", "7th", "cat3f", "3rd (F)",
153: NULL, NULL,
154: }, list3[2]; /* single section */
155:
156: static
157: man(argv)
158: char **argv;
159: {
160: register char *p;
161: DIR *section, *getsect();
162: int res;
163:
164: for (; *argv; ++argv) {
165: manpath = defpath;
166: section = NULL;
167: switch(**argv) {
168: case 'l': /* local */
169: /* support the "{l,local,n,new}###" syntax */
170: for (p = *argv; isalpha(*p); ++p);
171: if (!strncmp(*argv, "l", p - *argv) ||
172: !strncmp(*argv, "local", p - *argv)) {
173: ++argv;
174: manpath = locpath;
175: section = getsect(p);
176: }
177: break;
178: case 'n': /* new */
179: for (p = *argv; isalpha(*p); ++p);
180: if (!strncmp(*argv, "n", p - *argv) ||
181: !strncmp(*argv, "new", p - *argv)) {
182: ++argv;
183: manpath = newpath;
184: section = getsect(p);
185: }
186: break;
187: /*
188: * old isn't really a separate section of the manual,
189: * and its entries are all in a single directory.
190: */
191: case 'o': /* old */
192: for (p = *argv; isalpha(*p); ++p);
193: if (!strncmp(*argv, "o", p - *argv) ||
194: !strncmp(*argv, "old", p - *argv)) {
195: ++argv;
196: list3[0] = list1[3];
197: section = list3;
198: }
199: break;
200: case '1': case '2': case '3': case '4':
201: case '5': case '6': case '7': case '8':
202: if (section = getsect(*argv))
203: ++argv;
204: }
205:
206: if (*argv) {
207: if (section)
208: res = manual(section, *argv);
209: else {
210: res = manual(list1, *argv);
211: if (!res || (how & ALL))
212: res += manual(list2, *argv);
213: }
214: if (res || how&WHERE)
215: continue;
216: }
217:
218: fputs("man: ", stderr);
219: if (*argv)
220: fprintf(stderr, "no entry for %s in the ", *argv);
221: else
222: fputs("what do you want from the ", stderr);
223: if (section)
224: fprintf(stderr, "%s section of the ", section->msg);
225: if (manpath == locpath)
226: fputs("local ", stderr);
227: else if (manpath == newpath)
228: fputs("new ", stderr);
229: if (*argv)
230: fputs("manual.\n", stderr);
231: else
232: fputs("manual?\n", stderr);
233: exit(1);
234: }
235: }
236:
237: /*
238: * manual --
239: * given a directory list and a file name find a file that
240: * matches; check ${directory}/${dir}/{file name} and
241: * ${directory}/${dir}/${machine}/${file name}.
242: */
243: static
244: manual(section, name)
245: DIR *section;
246: char *name;
247: {
248: register char *beg, *end;
249: register DIR *dp;
250: register int res;
251: char fname[MAXPATHLEN + 1], *index();
252:
253: for (beg = manpath, res = 0;; beg = end + 1) {
254: if (end = index(beg, ':'))
255: *end = '\0';
256: for (dp = section; dp->name; ++dp) {
257: (void)sprintf(fname, "%s/%s/%s.0", beg, dp->name, name);
258: if (access(fname, R_OK)) {
259: (void)sprintf(fname, "%s/%s/%s/%s.0", beg,
260: dp->name, machine, name);
261: if (access(fname, R_OK))
262: continue;
263: }
264: if (how & WHERE)
265: printf("man: found in %s.\n", fname);
266: else if (how & CAT)
267: cat(fname);
268: else
269: add(fname);
270: if (!(how & ALL))
271: return(1);
272: res = 1;
273: }
274: if (!end)
275: return(res);
276: *end = ':';
277: }
278: /*NOTREACHED*/
279: }
280:
281: /*
282: * cat --
283: * cat out the file
284: */
285: static
286: cat(fname)
287: char *fname;
288: {
289: register int fd, n;
290: char buf[BUFSIZ];
291:
292: if (!(fd = open(fname, O_RDONLY, 0))) {
293: perror("man: open");
294: exit(1);
295: }
296: while ((n = read(fd, buf, sizeof(buf))) > 0)
297: if (write(1, buf, n) != n) {
298: perror("man: write");
299: exit(1);
300: }
301: if (n == -1) {
302: perror("man: read");
303: exit(1);
304: }
305: (void)close(fd);
306: }
307:
308: /*
309: * add --
310: * add a file name to the list for future paging
311: */
312: static
313: add(fname)
314: char *fname;
315: {
316: static u_int buflen;
317: static int len;
318: static char *cp;
319: int flen;
320: char *malloc(), *realloc(), *strcpy();
321:
322: if (!command) {
323: if (!(command = malloc(buflen = 1024))) {
324: fputs("man: out of space.\n", stderr);
325: exit(1);
326: }
327: len = strlen(strcpy(command, pager));
328: cp = command + len;
329: }
330: flen = strlen(fname);
331: if (len + flen + 2 > buflen) { /* +2 == space, EOS */
332: if (!(command = realloc(command, buflen += 1024))) {
333: fputs("man: out of space.\n", stderr);
334: exit(1);
335: }
336: cp = command + len;
337: }
338: *cp++ = ' ';
339: len += flen + 1; /* +1 = space */
340: (void)strcpy(cp, fname);
341: cp += flen;
342: }
343:
344: /*
345: * getsect --
346: * return a point to the section structure for a particular suffix
347: */
348: static DIR *
349: getsect(s)
350: char *s;
351: {
352: switch(*s++) {
353: case '1':
354: if (!*s)
355: return(list1);
356: break;
357: case '2':
358: if (!*s) {
359: list3[0] = list2[0];
360: return(list3);
361: }
362: break;
363: /* sect. 3 requests are for either section 3, or section 3[fF]. */
364: case '3':
365: if (!*s) {
366: list3[0] = list2[1];
367: return(list3);
368: }
369: else if ((*s == 'f' || *s == 'F') && !*++s) {
370: list3[0] = list2[5];
371: return(list3);
372: }
373: break;
374: case '4':
375: if (!*s) {
376: list3[0] = list2[2];
377: return(list3);
378: }
379: break;
380: case '5':
381: if (!*s) {
382: list3[0] = list2[3];
383: return(list3);
384: }
385: break;
386: case '6':
387: if (!*s) {
388: list3[0] = list1[2];
389: return(list3);
390: }
391: break;
392: case '7':
393: if (!*s) {
394: list3[0] = list2[4];
395: return(list3);
396: }
397: break;
398: case '8':
399: if (!*s) {
400: list3[0] = list1[1];
401: return(list3);
402: }
403: }
404: return((DIR *)NULL);
405: }
406:
407: /*
408: * jump --
409: * strip out flag argument and jump
410: */
411: static
412: jump(argv, flag, name)
413: char **argv, *name;
414: register char *flag;
415: {
416: register char **arg;
417:
418: argv[0] = name;
419: for (arg = argv + 1; *arg; ++arg)
420: if (!strcmp(*arg, flag))
421: break;
422: for (; *arg; ++arg)
423: arg[0] = arg[1];
424: execvp(name, argv);
425: fprintf(stderr, "%s: Command not found.\n", name);
426: exit(1);
427: }
428:
429: /*
430: * usage --
431: * print usage and die
432: */
433: static
434: usage()
435: {
436: fputs("usage: man [-] [-a] [-M path] [section] title ...\n", stderr);
437: exit(1);
438: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.