|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)man.c 5.12 (Berkeley) 3/20/86";
15: #endif not lint
16:
17: #include <stdio.h>
18: #include <ctype.h>
19: #include <sgtty.h>
20: #include <sys/param.h>
21: #include <sys/stat.h>
22: #include <signal.h>
23: #include <strings.h>
24:
25: /*
26: * man
27: * link also to apropos and whatis
28: * This version uses more for underlining and paging.
29: */
30: #define NROFFCAT "nroff -h -man" /* for nroffing to cat file */
31: #define NROFF "nroff -man" /* for nroffing to tty */
32: #define MORE "more -s" /* paging filter */
33: #define CAT_ "/bin/cat" /* for when output is not a tty */
34: #define CAT_S "/bin/cat -s" /* for '-' opt (no more) */
35:
36: #define TROFFCMD "vtroff -man %s"
37:
38: #define ALLSECT "1nl6823457po" /* order to look through sections */
39: #define SECT1 "1nlo" /* sections to look at if 1 is specified */
40: #define SUBSEC1 "cg" /* subsections to try in section 1 */
41: #define SUBSEC3 "sxmncf"
42: #define SUBSEC4 "pfn"
43: #define SUBSEC8 "cv"
44:
45: #define WHATIS "whatis"
46:
47: int nomore;
48: char *CAT = CAT_;
49: char *manpath = "/usr/man";
50: char *strcpy();
51: char *strcat();
52: char *getenv();
53: char *calloc();
54: char *trim();
55: int remove();
56: int apropos();
57: int whatis();
58: int section;
59: int subsec;
60: int troffit;
61: int mypid;
62:
63: #define eq(a,b) (strcmp(a,b) == 0)
64:
65: main(argc, argv)
66: int argc;
67: char *argv[];
68: {
69: char *mp;
70:
71: if ((mp = getenv("MANPATH")) != NULL)
72: manpath = mp;
73: umask(0);
74: mypid = getpid();
75: if (strcmp(argv[0], "apropos") == 0) {
76: runpath(argc-1, argv+1, apropos);
77: exit(0);
78: }
79: if (strcmp(argv[0], "whatis") == 0) {
80: runpath(argc-1, argv+1, whatis);
81: exit(0);
82: }
83: if (argc <= 1) {
84: fprintf(stderr, "Usage: man [ section ] name ...\n");
85: exit(1);
86: }
87: argc--, argv++;
88: while (argc > 0 && argv[0][0] == '-') {
89: switch(argv[0][1]) {
90:
91: case 0:
92: nomore++;
93: CAT = CAT_S;
94: break;
95:
96: case 't':
97: troffit++;
98: break;
99:
100: case 'k':
101: apropos(argc-1, argv+1);
102: exit(0);
103:
104: case 'f':
105: whatis(argc-1, argv+1);
106: exit(0);
107:
108: case 'P': /* backwards compatibility */
109: case 'M':
110: if (argc < 2) {
111: fprintf(stderr, "%s: missing path\n", *argv);
112: exit(1);
113: }
114: argc--, argv++;
115: manpath = *argv;
116: break;
117: }
118: argc--, argv++;
119: }
120: if (troffit == 0 && nomore == 0 && !isatty(1))
121: nomore++;
122: section = 0;
123: do {
124: if (eq(argv[0], "local")) {
125: section = 'l';
126: goto sectin;
127: } else if (eq(argv[0], "new")) {
128: section = 'n';
129: goto sectin;
130: } else if (eq(argv[0], "old")) {
131: section = 'o';
132: goto sectin;
133: } else if (eq(argv[0], "public")) {
134: section = 'p';
135: goto sectin;
136: } else if (isdigit(argv[0][0]) &&
137: (argv[0][1] == 0 || argv[0][2] == 0)) {
138: section = argv[0][0];
139: subsec = argv[0][1];
140: sectin:
141: argc--, argv++;
142: if (argc == 0) {
143: fprintf(stderr,
144: "But what do you want from section %s?\n",
145: argv[-1]);
146: exit(1);
147: }
148: continue;
149: }
150: manual(section, argv[0]);
151: argc--, argv++;
152: } while (argc > 0);
153: exit(0);
154: }
155:
156: runpath(ac, av, f)
157: int ac;
158: char *av[];
159: int (*f)();
160: {
161:
162: if (ac > 0 && strcmp(av[0], "-M") == 0 || strcmp(av[0], "-P") == 0) {
163: if (ac < 2) {
164: fprintf(stderr, "%s: missing path\n", av[0]);
165: exit(1);
166: }
167: manpath = av[1];
168: ac -= 2, av += 2;
169: }
170: (*f)(ac, av);
171: exit(0);
172: }
173:
174: manual(sec, name)
175: char sec, *name;
176: {
177: char section = sec;
178: char work[100], work2[100];
179: char path[MAXPATHLEN+1], realname[MAXPATHLEN+1];
180: char cmdbuf[150];
181: int ss = 0;
182: struct stat stbuf, stbuf2;
183: int last;
184: char *sp = ALLSECT;
185: FILE *it;
186: char abuf[BUFSIZ];
187:
188: strcpy(work, "manx/");
189: strcat(work, name);
190: strcat(work, ".x");
191: last = strlen(work) - 1;
192: if (section == '1') {
193: sp = SECT1;
194: section = 0;
195: }
196: if (section == 0) { /* no section or section 1 given */
197: for (section = *sp++; section; section = *sp++) {
198: work[3] = section;
199: work[last] = section;
200: work[last+1] = 0;
201: work[last+2] = 0;
202: if (pathstat(work, path, &stbuf))
203: break;
204: if (work[last] >= '1' && work[last] <= '8') {
205: char *cp;
206: search:
207: switch (work[last]) {
208: case '1': cp = SUBSEC1; break;
209: case '3': cp = SUBSEC3; break;
210: case '4': cp = SUBSEC4; break;
211: case '8': cp = SUBSEC8; break;
212: default: cp = ""; break;
213: }
214: while (*cp) {
215: work[last+1] = *cp++;
216: if (pathstat(work, path, &stbuf)) {
217: ss = work[last+1];
218: goto found;
219: }
220: }
221: if (ss == 0)
222: work[last+1] = 0;
223: }
224: }
225: if (section == 0) {
226: if (sec == 0)
227: printf("No manual entry for %s.\n", name);
228: else
229: printf("No entry for %s in section %c%s.\n",
230: name, sec, " of the manual");
231: return;
232: }
233: } else { /* section given */
234: work[3] = section;
235: work[last] = section;
236: work[last+1] = subsec;
237: work[last+2] = 0;
238: if (!pathstat(work, path, &stbuf)) {
239: if ((section >= '1' && section <= '8') && subsec == 0) {
240: sp = "\0";
241: goto search;
242: }
243: else if (section == 'o') { /* XXX */
244: char *cp;
245: char sec;
246: for (sec = '0'; sec <= '8'; sec++) {
247: work[last] = sec;
248: if (pathstat(work, path, &stbuf))
249: goto found;
250: switch (work[last]) {
251: case '1': cp = SUBSEC1; break;
252: case '3': cp = SUBSEC3; break;
253: case '4': cp = SUBSEC4; break;
254: case '8': cp = SUBSEC8; break;
255: default: cp = ""; break;
256: }
257: while (*cp) {
258: work[last+1] = *cp++;
259: if (pathstat(work, path, &stbuf)) {
260: ss = work[last+1];
261: goto found;
262: }
263: }
264: if (ss == 0)
265: work[last+1] = 0;
266: }
267: }
268: printf("No entry for %s in section %c", name, section);
269: if (subsec)
270: putchar(subsec);
271: printf(" of the manual.\n");
272: return;
273: }
274: }
275: found:
276: sprintf(realname, "%s/%s", path, work);
277: if (troffit) {
278: troff(path, work);
279: return;
280: }
281: if (!nomore) {
282: if ((it = fopen(realname, "r")) == NULL) {
283: goto catit;
284: }
285: if (fgets(abuf, BUFSIZ-1, it) &&
286: strncmp(abuf, ".so ", 4) == 0) {
287: register char *cp = abuf+4;
288: char *dp;
289:
290: while (*cp && *cp != '\n')
291: cp++;
292: *cp = 0;
293: while (cp > abuf && *--cp != '/')
294: ;
295: dp = ".so man";
296: if (cp != abuf+strlen(dp)+1) {
297: tohard:
298: fclose(it);
299: nomore = 1;
300: strcpy(work, abuf+4);
301: goto hardway;
302: }
303: for (cp = abuf; *cp == *dp && *cp; cp++, dp++)
304: ;
305: if (*dp)
306: goto tohard;
307: strcpy(work, cp-3);
308: }
309: fclose(it);
310: }
311: catit:
312: strcpy(work2, "cat");
313: work2[3] = work[3];
314: work2[4] = 0;
315: sprintf(realname, "%s/%s", path, work2);
316: if (stat(realname, &stbuf2) < 0)
317: goto hardway;
318: strcpy(work2+4, work+4);
319: sprintf(realname, "%s/%s", path, work2);
320: if (stat(realname, &stbuf2) < 0 || stbuf2.st_mtime < stbuf.st_mtime) {
321: if (nomore)
322: goto hardway;
323: printf("Reformatting page. Wait...");
324: fflush(stdout);
325: unlink(work2);
326: if (signal(SIGINT, SIG_IGN) == SIG_DFL) {
327: (void) signal(SIGINT, remove);
328: (void) signal(SIGQUIT, remove);
329: (void) signal(SIGTERM, remove);
330: }
331: sprintf(cmdbuf, "%s %s/%s > /tmp/man%d; trap '' 1 15",
332: NROFFCAT, path, work, mypid);
333: if (system(cmdbuf)) {
334: printf(" aborted (sorry)\n");
335: remove();
336: /*NOTREACHED*/
337: }
338: sprintf(cmdbuf, "/bin/mv -f /tmp/man%d %s/%s 2>/dev/null",
339: mypid, path, work2);
340: if (system(cmdbuf)) {
341: sprintf(path, "/");
342: sprintf(work2, "tmp/man%d", mypid);
343: }
344: printf(" done\n");
345: }
346: strcpy(work, work2);
347: hardway:
348: nroff(path, work);
349: if (work2[0] == 't')
350: remove();
351: }
352:
353: /*
354: * Use the manpath to look for
355: * the file name. The result of
356: * stat is returned in stbuf, the
357: * successful path in path.
358: */
359: pathstat(name, path, stbuf)
360: char *name, path[];
361: struct stat *stbuf;
362: {
363: char *cp, *tp, *ep;
364: char **cpp;
365: static char *manpaths[] = {"man", "cat", 0};
366: static char *nopaths[] = {"", 0};
367:
368: if (strncmp(name, "man", 3) == 0)
369: cpp = manpaths;
370: else
371: cpp = nopaths;
372: for ( ; *cpp ; cpp++) {
373: for (cp = manpath; cp && *cp; cp = tp) {
374: tp = index(cp, ':');
375: if (tp) {
376: if (tp == cp) {
377: sprintf(path, "%s%s", *cpp,
378: name+strlen(*cpp));
379: }
380: else {
381: sprintf(path, "%.*s/%s%s", tp-cp, cp,
382: *cpp, name+strlen(*cpp));
383: }
384: ep = path + (tp-cp);
385: tp++;
386: } else {
387: sprintf(path, "%s/%s%s", cp, *cpp,
388: name+strlen(*cpp));
389: ep = path + strlen(cp);
390: }
391: if (stat(path, stbuf) >= 0) {
392: *ep = '\0';
393: return (1);
394: }
395: }
396: }
397: return (0);
398: }
399:
400: nroff(pp, wp)
401: char *pp, *wp;
402: {
403: char cmd[BUFSIZ];
404:
405: chdir(pp);
406: if (wp[0] == 'c' || wp[0] == 't')
407: sprintf(cmd, "%s %s", nomore? CAT : MORE, wp);
408: else
409: sprintf(cmd, nomore? "%s %s" : "%s %s|%s", NROFF, wp, MORE);
410: (void) system(cmd);
411: }
412:
413: troff(pp, wp)
414: char *pp, *wp;
415: {
416: char cmdbuf[BUFSIZ];
417:
418: chdir(pp);
419: sprintf(cmdbuf, TROFFCMD, wp);
420: (void) system(cmdbuf);
421: }
422:
423: any(c, sp)
424: register int c;
425: register char *sp;
426: {
427: register int d;
428:
429: while (d = *sp++)
430: if (c == d)
431: return (1);
432: return (0);
433: }
434:
435: remove()
436: {
437: char name[15];
438:
439: sprintf(name, "/tmp/man%d", mypid);
440: unlink(name);
441: exit(1);
442: }
443:
444: unsigned int
445: blklen(ip)
446: register char **ip;
447: {
448: register unsigned int i = 0;
449:
450: while (*ip++)
451: i++;
452: return (i);
453: }
454:
455: apropos(argc, argv)
456: int argc;
457: char **argv;
458: {
459: char buf[BUFSIZ], file[MAXPATHLEN+1];
460: char *gotit, *cp, *tp;
461: register char **vp;
462:
463: if (argc == 0) {
464: fprintf(stderr, "apropos what?\n");
465: exit(1);
466: }
467: gotit = calloc(1, blklen(argv));
468: for (cp = manpath; cp; cp = tp) {
469: tp = index(cp, ':');
470: if (tp) {
471: if (tp == cp)
472: strcpy(file, WHATIS);
473: else
474: sprintf(file, "%.*s/%s", tp-cp, cp, WHATIS);
475: tp++;
476: } else
477: sprintf(file, "%s/%s", cp, WHATIS);
478: if (freopen(file, "r", stdin) == NULL)
479: continue;
480: while (fgets(buf, sizeof buf, stdin) != NULL)
481: for (vp = argv; *vp; vp++)
482: if (match(buf, *vp)) {
483: printf("%s", buf);
484: gotit[vp - argv] = 1;
485: for (vp++; *vp; vp++)
486: if (match(buf, *vp))
487: gotit[vp - argv] = 1;
488: break;
489: }
490: }
491: for (vp = argv; *vp; vp++)
492: if (gotit[vp - argv] == 0)
493: printf("%s: nothing appropriate\n", *vp);
494: }
495:
496: match(bp, str)
497: register char *bp;
498: char *str;
499: {
500:
501: for (;;) {
502: if (*bp == 0)
503: return (0);
504: if (amatch(bp, str))
505: return (1);
506: bp++;
507: }
508: }
509:
510: amatch(cp, dp)
511: register char *cp, *dp;
512: {
513:
514: while (*cp && *dp && lmatch(*cp, *dp))
515: cp++, dp++;
516: if (*dp == 0)
517: return (1);
518: return (0);
519: }
520:
521: lmatch(c, d)
522: register int c, d;
523: {
524:
525: if (c == d)
526: return (1);
527: if (!isalpha(c) || !isalpha(d))
528: return (0);
529: if (islower(c))
530: c = toupper(c);
531: if (islower(d))
532: d = toupper(d);
533: return (c == d);
534: }
535:
536: whatis(argc, argv)
537: int argc;
538: char **argv;
539: {
540: register char *gotit, **vp;
541: char buf[BUFSIZ], file[MAXPATHLEN+1], *cp, *tp;
542:
543: if (argc == 0) {
544: fprintf(stderr, "whatis what?\n");
545: exit(1);
546: }
547: for (vp = argv; *vp; vp++)
548: *vp = trim(*vp);
549: gotit = calloc(1, blklen(argv));
550: for (cp = manpath; cp; cp = tp) {
551: tp = index(cp, ':');
552: if (tp) {
553: if (tp == cp)
554: strcpy(file, WHATIS);
555: else
556: sprintf(file, "%.*s/%s", tp-cp, cp, WHATIS);
557: tp++;
558: } else
559: sprintf(file, "%s/%s", cp, WHATIS);
560: if (freopen(file, "r", stdin) == NULL)
561: continue;
562: while (fgets(buf, sizeof buf, stdin) != NULL)
563: for (vp = argv; *vp; vp++)
564: if (wmatch(buf, *vp)) {
565: printf("%s", buf);
566: gotit[vp - argv] = 1;
567: for (vp++; *vp; vp++)
568: if (wmatch(buf, *vp))
569: gotit[vp - argv] = 1;
570: break;
571: }
572: }
573: for (vp = argv; *vp; vp++)
574: if (gotit[vp - argv] == 0)
575: printf("%s: not found\n", *vp);
576: }
577:
578: wmatch(buf, str)
579: char *buf, *str;
580: {
581: register char *bp, *cp;
582:
583: bp = buf;
584: again:
585: cp = str;
586: while (*bp && *cp && lmatch(*bp, *cp))
587: bp++, cp++;
588: if (*cp == 0 && (*bp == '(' || *bp == ',' || *bp == '\t' || *bp == ' '))
589: return (1);
590: while (isalpha(*bp) || isdigit(*bp))
591: bp++;
592: if (*bp != ',')
593: return (0);
594: bp++;
595: while (isspace(*bp))
596: bp++;
597: goto again;
598: }
599:
600: char *
601: trim(cp)
602: register char *cp;
603: {
604: register char *dp;
605:
606: for (dp = cp; *dp; dp++)
607: if (*dp == '/')
608: cp = dp + 1;
609: if (cp[0] != '.') {
610: if (cp + 3 <= dp && dp[-2] == '.' &&
611: any(dp[-1], "cosa12345678npP"))
612: dp[-2] = 0;
613: if (cp + 4 <= dp && dp[-3] == '.' &&
614: any(dp[-2], "13") && isalpha(dp[-1]))
615: dp[-3] = 0;
616: }
617: return (cp);
618: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.