#include #include #include #include #include #include #include #include #include #include char *defmanpath = "/usr/local/share/man:/usr/share/man:/usr/man"; char *defsections = "1:n:l:8:3:2:3posix:3pm:3perl:5:4:9:6:7"; void die(char *str) { perror(str); exit(1); } /* ** Render the specified man page and invoke a pager on it. ** Will only return if there's no such page. */ int display(char *path, char *sec, char *name) { char buf[BUFSIZ]; struct stat sb; char *catprog; int pd1[2], pd2[2], pd3[2]; pid_t pid; snprintf(buf, sizeof buf, "%s/man%s/%s.%s", path, sec, name, sec); if (stat(buf, &sb) != -1) { catprog = "cat"; goto displ; } snprintf(buf, sizeof buf, "%s/man%s/%s.%s.gz", path, sec, name, sec); if (stat(buf, &sb) != -1) { catprog = "zcat"; goto displ; } return 0; displ: /* Have zombies burried automatically */ signal(SIGCHLD, SIG_IGN); if (pipe(pd1) == -1) { die("pipe"); } if ((pid = fork()) == -1) { die("fork"); } else if (!pid) { /* child */ close(1); dup(pd1[1]); close(pd1[1]); close(pd1[0]); execlp(catprog, catprog, buf, NULL); die("exec"); } /* parent */ close(pd1[1]); if (pipe(pd2) == -1) { die("pipe"); } if ((pid = fork()) == -1) { die("fork"); } else if (!pid) { /* child */ close(0); dup(pd1[0]); close(pd1[0]); close(1); dup(pd2[1]); close(pd2[1]); close(pd2[0]); execlp("nroff", "nroff", "-Tlp", "-man", NULL); die("exec"); } /* parent */ close(pd2[1]); if (pipe(pd3) == -1) { die("pipe"); } if ((pid = fork()) == -1) { die("fork"); } else if (!pid) { /* child */ close(0); dup(pd2[0]); close(pd2[0]); close(1); dup(pd3[1]); close(pd3[1]); close(pd3[0]); execlp("col", "col", "-x", NULL); die("exec"); } /* parent */ close(pd3[1]); /* parent */ close(0); dup(pd3[0]); close(pd3[0]); execlp("less", "less", "-is", NULL); die("exec"); return 0; } /* ** Search `manpath' for man page `name' in section `sec'. */ int process(char *name, char *sec, char *manpath) { pid_t pid; char *str, *tok; int status; if (!(manpath = strdup(manpath))) { die("strdup"); } if ((pid = fork()) == -1) { perror("fork"); exit(1); } else if (pid == 0) { /* child to try to display the man page */ for (str=manpath; ; str=NULL) { if (!(tok = strtok(str, ":"))) { break; } display(tok, sec, name); /* returns only on failure */ } /* not found */ exit(1); } free(manpath); wait(&status); return (WIFEXITED(status) && WEXITSTATUS(status)==0); } int main(int argc, char *argv[]) { char *sec = NULL; char *manpath, *str, *tok, *sections; int first = 1; if (!(manpath = getenv("MANPATH"))) { manpath = defmanpath; } if (!(sections = getenv("MANSECTIONS"))) { sections = defsections; } if (argc < 2) { fprintf(stderr, "Usage: %s [SECTION] NAME...\n", argv[0]); exit(1); } argv++; argc--; /* check if first arg is a section number */ if (isdigit(*argv[0])) { sec = argv[0]; argv++; argc--; } for (; *argv; argv++) { int success = 0; if (!first) { fprintf(stderr, "\nNEXT man page `%s' -- \\n to display, " "^D to skip, ^C to quit\n", *argv); if (getchar() == EOF) { argv++; } } first = 0; if (sec) { success = process(*argv, sec, manpath); } else { char *cp; if (!(cp = strdup(sections))) { die("strdup"); } for (str=cp; ; str=NULL) { if (!(tok = strtok(str, ":"))) { break; } if (process(*argv, tok, manpath)) { success = 1; break; } } free(cp); } if (!success) { fprintf(stderr, "No man page for `%s' found.\n", *argv); } } return 1; }