Relay-Version: version B 2.10.3 beta 11/15/85; site seismo.CSS.GOV Posting-Version: version B 2.10.2 9/3/84; site panda.UUCP Path: seismo!harvard!talcott!panda!sources-request From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: A compiled 'man' program for System V Message-ID: <1230@panda.UUCP> Date: 26 Dec 85 03:13:48 GMT Sender: jpn@panda.UUCP Lines: 606 Approved: jpn@panda.UUCP Mod.sources: Volume 3, Issue 70 Submitted by: cbosgd!ukma!ukecc!edward (Edward C. Bennett) In System V (at least on our 3B20) the man(1) command is a shell script and, because it calls nroff *every time*, it is painfully slow to use. Even the catman(1) command, which uses preformatted and packed versions of the man pages, takes a noticeably long time to get your data on-screen. Furthermore, catman(1) has no easy way to keep the /usr/catman files up- to-date. Such is the inspiration for this new version of man(1). This version of man(1) eliminates all these problems. It is compiled rather than interpreted to increase speed. [This program compiles on BSD4.2 after changing to and converting calls to strchr() to index() - moderator ] It uses the /usr/catman files to avoid repetative nroff'ing. And checks to see if the formatted version postdates the raw version and if not, a new formatted version is created. This automates the problem of maintaining a current manual. Additionally, the program allows you to select the order that the sections are searched. This way you can put little-used sections like 5 and 8 at the end of the line. The program also looks at the environment variable PAGER for a preferred paging program, finding none it uses a preselected default. An option is provided to look for man pages applicable to a given keyword. #! /bin/sh : This is a shell archive, meaning: : 1. Remove everything above the '#! /bin/sh' line. : 2. Save the resulting text in a file. : 3. Execute the file with /bin/sh '(not csh)' to create the files: : 'README' : 'Makefile' : 'man.1' : 'man.c' : 'mkxref.c' : 'updateall.c' : This archive created: 'Mon Dec 23 16:31:07 1985' : By: 'Edward C. Bennett' export PATH; PATH=/bin:$PATH if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat >'README' <<\SHAR_EOF To set this system up: Check the makefile to be sure all paths are OK. Su to 'root' and do "make convert" Compile the updateall command. This should be run at an off hour as it takes quite awhile. SHAR_EOF fi if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat >'Makefile' <<\SHAR_EOF # makefile of System V man program # # AUTHOR # Edward C. Bennett, edward@ukecc.UUCP # # Copyright 1985 by Edward C. Bennett # # Permission is given to alter this code as needed to adapt it to forign # systems provided that this header is included and that the original # author's name is preserved. USRBIN=/usr/bin MANOWN=bin man: man.c cc -O man.c -o man xref: mkxref mkxref > /usr/man/xref mkxref: mkxref.c cc -O mkxref.c -o mkxref updateall: updateall.c cc -O updateall.c -o updateall install: man /etc/install -f ${USRBIN} man chown ${MANOWN} ${USRBIN}/man chmod 4755 ${USRBIN}/man convert: man mkxref mv ${USRBIN}/man ${USRBIN}/oman mv /usr/man/u_man/man1/man.1 /usr/man/u_man/man1/oman.1 /etc/install -f ${USRBIN} man chown ${MANOWN} ${USRBIN}/man chmod 4755 ${USRBIN}/man mkxref > /usr/man/xref chown ${MANOWN} /usr/bin/xref clean: rm -f man mkxref updateall shar: shar README Makefile man.1 man.c mkxref.c updateall.c > man.shar SHAR_EOF fi if test -f 'man.1' then echo shar: will not over-write existing file "'man.1'" else cat >'man.1' <<\SHAR_EOF .TH MAN 1 "23 December 1985" .SH NAME man \- print manual pages .SH SYNOPSIS .B man [ .B section ] title .PP .B man \-k keyword .SH DESCRIPTION .I Man finds and prints pages from the on-line manual. To speed things up, .I man keeps preformatted and packed versions of the manual pages in the /usr/catman directory. The date of the formatted version is checked against the date of the raw version and if the raw version is newer, a new formatted version is created with .IR nroff (1) and .IR pack (1). .PP The environmental variable PAGER is checked for a preferred paging program. If none is specified, .IR pg (1) is used. .PP If .I man is used with the \-k option, a list of all subject lines is searched for the given keyword. This is useful if you don't know the name of a command, but you know what it does. .SH FILES .TP 38 /usr/man/[apu]_man/man[1-8]/* unformatted pages .TP 38 /usr/catman/[apu]_man/man[1-8]/*.z formatted, packed pages .TP 38 /usr/man/xref collection of title lines .SH AUTHOR Edward C. Bennett .SH DIAGNOSTICS Hopefully self-explanatory. .SH BUGS .I Man only prints the first manual entry with the given title that it finds. To keep things simple, .IR nroff (1) uses no fancy options. The \-k option should search for multiple keywords. SHAR_EOF fi if test -f 'man.c' then echo shar: will not over-write existing file "'man.c'" else cat >'man.c' <<\SHAR_EOF /* * man - view the on-line manual * * man [ section ] title * * man -k keyword * * This manual program is designed primarily for a speed increase * in viewing the manual. Rather than run nroff every time a man page is * requested, pre-formatted packed versions of the pages are kept in the * /usr/catman directory and pcat is used to read them. This agrees with * System V's catman program. This program stats both the unformatted and * formatted versions of the requested page and, if the formatted page is * up-to-date, it is printed, otherwise a new packed page is created with * nroff and pack. This automates the task of keeping up-to-date man pages * on-line. The environmental variable PAGER is checked for a preferred * pager, if none is specified /usr/bin/pg is used. To keep things simple, * nroff uses no fancy options. * With the -k option, the /usr/man/xref database is searched for the * given keyword. * * AUTHOR * Edward C. Bennett, edward@ukecc.UUCP * * Copyright 1985 by Edward C. Bennett * * Permission is given to alter this code as needed to adapt it to forign * systems provided that this header is included and that the original * author's name is preserved. */ #include #include #include #include #include #include #define DEFPAGER "/usr/bin/pg" #define GREP "/bin/grep" #define XREF "/usr/man/xref" /* * These are the directories under /usr/man that are to be searched for the * requested man page. The order in the array is the order of the search * so to minimize searching effort the more frequently used sections should * go at the top. */ char *mandirs[] = { "u_man/man1", "p_man/man2", "p_man/man3", "u_man/man6", "p_man/man4", "p_man/man5", "a_man/man1", "a_man/man7", "a_man/man8", }; #define NUMDIRS sizeof(mandirs)/sizeof(char *) main(argc, argv) int argc; char **argv; { char *manpage, *pager, *section, *title, *Findpage(), *getenv(); char cmd[BUFSIZ], catbuf[BUFSIZ], catbufz[BUFSIZ]; int status; void exit(); struct stat manstat, catstat; if (!strcmp(argv[1], "-k")) { execl(GREP, GREP, argv[2], XREF, 0); } switch (argc) { case 2: title = argv[1]; section = NULL; break; case 3: title = argv[2]; section = argv[1]; break; default: fprintf(stderr, "Usage: %s [ section ] title\n", argv[0]); exit(1); } if ((pager = getenv("PAGER")) == NULL) pager = DEFPAGER; chdir("/usr/man"); if ((manpage = Findpage(title, section)) == NULL) { if (section) printf("No entry for %s in section %s of the manual\n", title, section); else printf("No manual entry for %s\n", title); exit(1); } strcpy(catbuf, "/usr/catman/"); strcat(catbuf, manpage); strcpy(catbufz, catbuf); strcat(catbufz, ".z"); stat(manpage, &manstat); if (stat(catbufz, &catstat) == -1) catstat.st_mtime = -1; if (catstat.st_mtime < manstat.st_mtime) { unlink(catbufz); printf("Reformatting page, wait..."); fflush(stdout); if (fork() == 0) { sprintf(cmd, "nroff -man %s > %s", manpage, catbuf); execl("/bin/sh", "sh", "-c", cmd, 0); } wait(&status); printf("\nCompressing output, wait..."); fflush(stdout); if (fork() == 0) { sprintf(cmd, "pack -f %s", catbuf); execl("/bin/sh", "sh", "-c", cmd, 0); } wait(&status); } /* * Do this in case the user does something like 'man curses > file' */ if (isatty(1)) sprintf(cmd, "pcat %s | %s", catbuf, pager); else sprintf(cmd, "pcat %s", catbuf); execl("/bin/sh", "sh", "-c", cmd, 0); } /* * Findpage - determine the pathname of the requested page * * path = Findpage(title, sect); * path is a pointer to the requested path * title is a pointer to the title of the requested page * sect is a pointer to the section to search, NULL if all sections * * Findpage() returns a pointer to a buffer containing the path name * of the unformatted version of the request man page in the form * [apu]_man/man[1-8]/title.[1-8]. The user can specify a section to search. * This is needed for cases like write(1) and write(2). If 'section' is given * as NULL, all sections are searched. If no match for title.sect can be found, * NULL is returned. */ char * Findpage(title, sect) char *title, *sect; { int fd, i, len, tlen; long lseek(); static char manbuf[BUFSIZ]; struct direct manent; tlen = strlen(title); for (i = 0; i < NUMDIRS; i++) { if (sect && *sect != *(mandirs[i] + 9)) continue; if ((fd = open(mandirs[i], O_RDONLY)) == -1) continue; /* * Skip "." and ".." */ lseek(fd, 2*sizeof(manent), 0); while (read(fd, &manent, sizeof(manent)) == sizeof(manent)) { if (manent.d_ino == 0) continue; len = (int)(strchr(manent.d_name, '.') - manent.d_name); if (!strncmp(manent.d_name, title, (len > tlen ? len : tlen))) { if (sect && strcmp(sect, manent.d_name+len+1)) continue; sprintf(manbuf, "%s/%s", mandirs[i], manent.d_name); return(manbuf); } } } return(NULL); } SHAR_EOF fi if test -f 'mkxref.c' then echo shar: will not over-write existing file "'mkxref.c'" else cat >'mkxref.c' <<\SHAR_EOF /* * mkxref - a program to list the titles from man pages * * All files in /usr/man/?_man/man? are searched for their title lines. * A title line is the first line following the ".SH NAME" line. Nroff * escapes are removed and the lines are written to the standard output. * If no title line is found in a file, the file's name is printed on * the standard error output. * * AUTHOR * Edward C. Bennett, edward@ukecc.UUCP * * Copyright 1985 by Edward C. Bennett * * Permission is given to alter this code as needed to adapt it to forign * systems provided that this header is included and that the original * author's name is preserved. */ #include #include #include #include #include #include char *mandirs[] = { "u_man/man1", "p_man/man2", "p_man/man3", "u_man/man6", "p_man/man4", "p_man/man5", "a_man/man1", "a_man/man7", "a_man/man8", }; #define NUMDIRS sizeof(mandirs)/sizeof(char *) main(argc, argv) int argc; char **argv; { char manbuf[BUFSIZ]; int fd, i, len; long lseek(); struct direct manent; chdir("/usr/man"); for (i = 0; i < NUMDIRS; i++) { if ((fd = open(mandirs[i], O_RDONLY)) == -1) continue; /* * Skip "." and ".." */ lseek(fd, 2*sizeof(manent), 0); while (read(fd, &manent, sizeof(manent)) == sizeof(manent)) { if (manent.d_ino == 0) continue; sprintf(manbuf, "%s/%s", mandirs[i], manent.d_name); Findname(manbuf); } } } Findname(manfile) char *manfile; { char *p, line[BUFSIZ], section[4]; int i, flag = 0; FILE *fp; strcpy(section, strchr(manfile, '.')+1); if ((fp = fopen(manfile, "r")) == NULL) return; while (fgets(line, BUFSIZ, fp) != NULL) { if (!strncmp(line, ".SH NAME", 8)) { flag++; if ((p = fgets(line, BUFSIZ, fp)) != NULL) { i = 0; while (*p) { /* * Remove escapes */ if (*p == '\\') { if (*++p == 's') { if (*++p == '-' || *p == '+') { p++; i--; } p++; i -= 2; } else if (*p == '*') { p += 2; i -= 3; } else if (*p == '&') { p++; i -= 2; } else if (*p == '-') { printf("(%s) ", section, ")"); for (i += (int)(p - line) + strlen(section); i < 25; i++) putchar(' '); putchar(*p++); } else putchar(*p++); } else putchar(*p++); } } break; } } if (!flag) fprintf(stderr, "%s\n", manfile); fclose(fp); return; } SHAR_EOF fi if test -f 'updateall.c' then echo shar: will not over-write existing file "'updateall.c'" else cat >'updateall.c' <<\SHAR_EOF /* * updateall - update the /usr/catman files * * All of the unformatted manual pages are checked against the copies * in the /usr/catman directory. If the unformatted copy is newer, a * new formatted and packed copy is placed in /usr/catman. * * AUTHOR * Edward C. Bennett, edward@ukecc.UUCP * * Copyright 1985 by Edward C. Bennett * * Permission is given to alter this code as needed to adapt it to forign * systems provided that this header is included and that the original * author's name is preserved. */ #include #include #include #include #include #include char *mandirs[] = { "u_man/man1", "p_man/man2", "p_man/man3", "u_man/man6", "p_man/man4", "p_man/man5", "a_man/man1", "a_man/man7", "a_man/man8", }; #define NUMDIRS sizeof(mandirs)/sizeof(char *) main() { char manbuf[BUFSIZ], cmd[BUFSIZ], catbuf[BUFSIZ], catbufz[BUFSIZ]; int status; void exit(); struct stat manstat, catstat; int fd, i; long lseek(); struct direct manent; chdir("/usr/man"); for (i = 0; i < NUMDIRS; i++) { if ((fd = open(mandirs[i], O_RDONLY)) == -1) continue; lseek(fd, 2*sizeof(manent), 0); while (read(fd, &manent, sizeof(manent)) == sizeof(manent)) { if (manent.d_ino == 0) continue; sprintf(manbuf, "%s/%s", mandirs[i], manent.d_name); strcpy(catbuf, "/usr/catman/"); strcat(catbuf, manbuf); strcpy(catbufz, catbuf); strcat(catbufz, ".z"); stat(manbuf, &manstat); if (stat(catbufz, &catstat) == -1) catstat.st_mtime = -1; if (catstat.st_mtime < manstat.st_mtime) { unlink(catbufz); if (fork() == 0) { sprintf(cmd, "nroff -man %s > %s", manbuf, catbuf); execl("/bin/sh", "sh", "-c", cmd, 0); } wait(&status); if (fork() == 0) { sprintf(cmd, "pack -f %s", catbuf); execl("/bin/sh", "sh", "-c", cmd, 0); } wait(&status); } } } } SHAR_EOF fi : End of shell archive exit 0 Edward C. Bennett UUCP: ihnp4!cbosgd!ukma!ukecc!edward /* A charter member of the Scooter bunch */ "Goodnight M.A."