diff --git a/usr.bin/man/README b/usr.bin/man/README index 7fce5c8..be167ef 100644 --- a/usr.bin/man/README +++ b/usr.bin/man/README @@ -1,71 +1,209 @@ -------------------------------------------- -Name: makewhatis -Version: 1.1 -Author: Devin Reade +Name: manpack +Version: 3.0 +Author: Devin Reade Computer: Apple IIgs -Requires: Gno v2.x +Requires: GNO v2.x -------------------------------------------- =========== Description: =========== -Generates the whatis database for apropos(1) and whatis(1). See the man -page for a detailed description. +Various programs for working with manual pages. This archive includes: + + apropos v3.0 locate commands by keyword + catman v1.0 format cat pages from man pages + makewhatis v1.2 create the whatis database + man v3.0 display reference manual pages + whatis v3.0 locate commands by name ============ Installation: ============ -Copy makewhatis to /usr/sbin and makewhatis.1 to $(USRMAN)/man1. -Alternately, you can type "dmake install" from this directory. +Type at the command line `dmake install`. You may wish to first +verify the destination directories in "Makefile.mk". By default +these are: -============ -Distribution: -============ + BINDIR = /usr/bin (apropos, catman, man, and whatis) + SBINDIR = /usr/sbin (makewhatis) + MANDIR = /usr/man (all manual pages) -Makewhatis is freeware. You may distribute this anywhere provided -that the archive remains intact. +Ensure that all older versions of these programs are deleted. +They may or may not be in the above directories. + +========== +Legalities: +========== + +These utilities are copyright 1995 by Devin Reade . + +They are provided as freeware, and may be distributed by Internet +archive sites, online services such as GEnie, or BBSes provided that +the archive remains intact. Permission is granted for distribution +with GNO/ME and Orca provided credit for this work is given along +with any other attributions. + +Inclusion of these utilities in collections on disk, CD-ROM, or +other portable media is permitted provided that only a nominal +fee (not much more than the media cost) is charged. Contact the +author regarding other commercial distributions. + +Updates to these utilities may be distributed provided that the source +and this README file are included. Please follow the coding style +already in use and document your changes in this file. ======= -Changes: +CHANGES: ======= -v1.1: (29 May 94) - Makewhatis will now ignore any man page starting with ".so", in - order to eliminate multiple files. The resultant blank lines in - the whatis database have therefore been eliminated. +apropos, whatis - Changed -v flag to {-v1|-v2} for differing stages of verbosity. - Only error output will be logged with the -l flag. + v3.0 (24 Jul 95) + Complete rewrite from scratch by Devin Reade. - Manual page was updated, to include a correction to the -o flag usage - and the modification to the -v flag. Descriptions of bugs unlikely - to be fixed were added. Date and version were changed. + This version makes use of MANPATH in the same way + as man(1) v3.0. Similarily, it will also search + the 17/syscmnd Orca database. - Fixed bug where input buffer wasn't properly terminated, and added - checks for buffer overflows. + In the previous version, the behavior of apropos was + identical to that of whatis. This version has been + fixed so that whatis is case sensitive and searches + only the manual page names. The apropos search is + case insensitive and searches the entire database + entry. - Makewhatis will now display all commands about which the manual page - is written. For example, if foo.1 described both foo(1) and bar(1), - and bar.1 was an .so (or .l) link to foo.1, then the database entry - will have changed from - foo (1) - extract and add thingys from the bork stream - to - foo, bar (1) - extract and add thingys from the bork stream + v2.1 (1 Jul 92 ?) + This version is by Mike Horwath and shipped with GNO v1.1. + Although no version flags or resource forks where provided + with this release, this release is designated as v2.1 + because it shipped with man(1) v2.1. + +catman - Makewhatis used to pick up the first NAME string in the file as a reference - point. Now, any NAME is ignored in any line starting with .\" or .TH + v1.0 (24 Jul 95) + Initial release. Written from scratch by Devin Reade. - Filename chapter numbers will now be correctly extracted regardless of the - existence of .Z, .z, .F, or .f suffixes, or of the existence of '.' within - the base file name. +makewhatis - Makewhatis is now linked with Soenke's gnulib for the getopt() function, - rather than using the libc version. + v1.2 (24 Jul 95) + Fixed bug where pages in "manl" ending in ".l" (that's + "ell" in both cases) would be ignored. - Stack usage was reduced to 1k. Be aware, though, that a fair amount - of global storage is used, including three 1k buffers. + Added recognition of files compressed with gzip. -v1.0: (15 May 94) - Initial release. + File compression suffixes are now case sensitive. + + If none of MANPATH, USRMAN, or MANDIR are defined, + "/usr/man" will now be used. + + Fixed a bug where the word SYNOPSIS appearing in the + description would mangle the database entry. + + Added a verbose-level-three flag (-v3), which is basically + the old -v2 flag. The new -v2 is somewhat less verbose + than it was. + + v1.1 (29 May 94) + Makewhatis will now ignore any man page starting with + ".so", in order to eliminate multiple files. The resultant + blank lines in the whatis database have therefore been + eliminated. + + Changed -v flag to {-v1|-v2} for differing stages of verbosity. + Only error output will be logged with the -l flag. + + Manual page was updated, to include a correction to the -o + flag usage and the modification to the -v flag. Descriptions + of bugs unlikely to be fixed were added. Date and version + were changed. + + Fixed bug where input buffer wasn't properly terminated, and + added checks for buffer overflows. + + Makewhatis will now display all commands about which the + manual page is written. For example, if foo.1 described + both foo(1) and bar(1), and bar.1 was an .so (or .l) link + to foo.1, then the database entry will have changed from + + foo (1) - extract and add thingys + foo, bar (1) - extract and add thingys + + Makewhatis used to pick up the first NAME string in the file + as a reference point. Now, any NAME is ignored in any line + starting with .\" or .TH + + Filename chapter numbers will now be correctly extracted + regardless of the existence of .Z, .z, .F, or .f suffixes, + or of the existence of '.' within the base file name. + + Makewhatis is now linked with Soenke's gnulib for the + getopt() function, rather than using the libc version. + + Stack usage was reduced to 1k. Be aware, though, that a + fair amount of global storage is used, including three 1k + buffers. + + v1.0 (15 May 94) + Initial release. Written from scratch by Devin Reade. + +man + v3.0 (24 Jul 95) + Complete rewrite from scratch by Devin Reade. + + The -k, -t, -, -f, -M, and -T flags were added. + + Man now supports the MANPATH environment variable which + can be a list of paths delimited by either colons or + spaces. + + Added sections 3f, l, n, o, and p to searched subdirectories. + + Added gzip(1) to compress(1) and freeze(1) as allowable + source compressors. + + Fixed bug with the .so source command; .so references + should now (properly) appear as ".so man
/" + instead of using the full pathname. + + Updates to apropos v3.0 apply to man when invoked with + the -k flag. + + Preprocessing by eqn(1), refer(1), tbl(1), and vgrind(1) + is not yet supported. + + v2.1 (1 Jul 92 ?) + Recognised environment variable USRMAN as well as MANDIR. + + This version was also by Mike Horwath. + + v2.0 (Date Unknown) + This version is by Mike Horwath and shipped with GNO v1.1. + + It made use of the environment variable MANDIR which had + to be a single directory. + + +===== +TO DO: +===== + +Makewhatis is not very well integrated with the rest of the package; +there is still duplication of definitions and functions in some files. + +Man, catman, and makewhatis need to support preformatting for eqn(1), +vgrind(1), et al. + +Makewhatis' "verbose" output could be cleaner. + +Performance analysis has not been done. No doubt some things could +improve, including some string matching in util.c + +If the stock getenv(3) function is used (as is done here), then the +return value should be duplicated (via strdup) rather than just used. +If the getenv function from the lenviron library is used, this is not +a concern. + +Perhaps an "X" version should be done for the Second Sight card. This +will have to wait a while. diff --git a/usr.bin/man/apropos.1 b/usr.bin/man/apropos.1 new file mode 100644 index 0000000..c50da82 --- /dev/null +++ b/usr.bin/man/apropos.1 @@ -0,0 +1 @@ +.so man1/whatis.1 diff --git a/usr.bin/man/apropos.c b/usr.bin/man/apropos.c new file mode 100644 index 0000000..c49e9f2 --- /dev/null +++ b/usr.bin/man/apropos.c @@ -0,0 +1,110 @@ +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +segment "apropos___"; + +#include +#include +#include +#include +#include "util.h" +#include "man.h" + +extern int optind; +extern char *optarg; + +static char *versionstr = "3.0"; +static char *nothing = "nothing appropriate"; + +extern void begin_stack_check(void); +extern int end_stack_check(void); + +int main (int argc, char **argv) { + char *path; + int i, matches1, matches2, matches3; + short V_flag, M_flag, m_flag, n_flag, err_flag; + + /* make sure Gno is running */ + if (needsgno()==0) { + fprintf(stderr,"Requires Gno/ME\n"); + return 1; + } + +#ifdef STACK_CHECK + begin_stack_check(); +#endif + + /* initialization */ + V_flag = M_flag = m_flag = n_flag = err_flag = 0; + matches1 = matches2 = matches3 = 0; + + /* parse command line and check usage */ + while((i = getopt(argc,argv,"M:m:nV")) != EOF) { + switch(i) { + case 'M': + if (m_flag) err_flag++; + M_flag++; + path = optarg; + break; + case 'm': + if (M_flag) err_flag++; + m_flag++; + path = optarg; + break; + case 'n': + n_flag++; + break; + case 'V': + V_flag++; + break; + default: + err_flag++; + } + } + if (argc-optind < 1) err_flag++; + if (err_flag || V_flag) { + fprintf(stderr,"%s version %s by Devin Reade\n", + basename(argv[0]),versionstr); + } + if (err_flag) { + fprintf(stderr, + "Usage: %s [[-M path] | [-m path]] [-nV] keyword [keyword ...]\n", + basename(argv[0])); + return 1; + } + + /* do the search */ + if (M_flag) { + manpath = path; + } else { + manpath = getManpath(); + } + matches1 = apropos(argc-optind, &argv[optind], MAN_K_MODE); + if (!M_flag) free(manpath); + if (m_flag) { + manpath = path; + matches2 = apropos(argc-optind, &argv[optind], MAN_K_MODE); + } + if (!n_flag) { + matches3 = apropos(argc-optind, &argv[optind], ORCA_K_MODE); + } + + i = 0; + if (matches1>0) i+= matches1; + if ( m_flag && matches2>0) i+=matches2; + if (!n_flag && matches3>0) i+=matches3; + + if (i==0) { + fprintf(stderr,"%s: %s\n",basename(argv[0]),nothing); + } + +#ifdef STACK_CHECK + fprintf(stderr,"stack usage: %d bytes\n",end_stack_check()); +#endif + + if ((matches1>=0) && (matches2>=0) && (matches3>=0) && i>0) return 0; + return 1; +} diff --git a/usr.bin/man/apropos2.c b/usr.bin/man/apropos2.c new file mode 100644 index 0000000..f0bc098 --- /dev/null +++ b/usr.bin/man/apropos2.c @@ -0,0 +1,284 @@ +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +segment "apropos2__"; + +#include +#include +#include +#include +#include +#include +#include +#include "util.h" +#include "man.h" + +/* + * orcapadding -- return a suitable number of padding tabs based on the + * length of the command + */ + +static char *orcapadding (char *command) { + int i; + static char *two ="\t\t"; + static char *one ="\t"; + static char *zero =" "; + + i = strlen(command); + if (i<8) return two; + if (i<16) return one; + return zero; +} + +/* + * orcacomment -- return the start of the comment field in a line of + * the Orca SYSCMND file. This _must_ be called before + * orcacommand() is called on the same buffer, because + * orcacommand() modifies the buffer. + */ + +static char *orcacomment (char *buffer) { + char *p; + static char *bad_line="malformed SYSCMND line\n"; + + p = buffer; + + /* get past the command name */ + while ((*p != ' ') && (*p != '\t') && *p) p++; + if (!*p) return bad_line; + + /* get past space */ + while ((*p == ' ') || (*p == '\t') && *p) p++; + if (!*p) return bad_line; + + if (*p == '*') p++; + switch (*p) { + case 'U': /*FALLTHROUGH*/ + case 'u': + p++; + break; + case 'C': /*FALLTHROUGH*/ + case 'L': /*FALLTHROUGH*/ + case 'c': /*FALLTHROUGH*/ + case 'l': + p++; + + /* get past space */ + while ((*p == ' ') || (*p == '\t') && *p) p++; + if (!*p) return bad_line; + + /* get past command or language number */ + while (isdigit(*p)) p++; + + break; + default: + return bad_line; + break; + } + + /* get past any remaining space */ + while ((*p == ' ') || (*p == '\t')) p++; + if (!*p) return bad_line; + return p; +} + +/* + * orcacommand -- returns the command name that starts the buffer. + * This _must_ be called after orcacomment because it + * modifies the buffer. + */ + +static char *orcacommand(char *buffer) { + char *p; + + p = buffer; + while (*p && !isspace(*p)) p++; + *p = '\0'; + return buffer; +} + +/* + * apropos -- print matching lines from WHATIS database. Returns the + * number of matching lines, or -1 on error. + * + * Argv is an array of argc strings, each of which is a keyword. + * Apropos will print out any line that matches any of the + * keywords in argv. The match algorithm depends on the value + * of apropos_mode, which may be one of the following. For the + * first three modes, global variable must be set. + * + * MAN_K_MODE -- this is the one used by apropos(1). A + * match is considered to be made if the keyword + * appears anywhere in the WHATIS database line. + * The match is case insensitive. + * + * MAN_F_MODE -- Any leading path component is stripped from + * the keywords, and then a match is attempted + * for any part of the WHATIS database line. The + * match is case insensitive. + * + * WHATIS_MODE -- The WHATIS database line is parsed up to the + * first occurance of a '(' character. If any + * of the keywords are found, then the line is + * printed. The search is case sensitive. + * + * ORCA_K_MODE -- Like MAN_K_MODE but instead of checking + * the various WHATIS databases, it checks + * 15/syscmnd. + * + * ORCA_W_MODE -- Like WHATIS_MODE but instead of checking + * the various WHATIS databases, it checks + * 15/syscmnd. + * + * WARNING: Use of the MAN_F_MODE may alter the contents of argv[]. + */ + +int apropos(int argc, char **argv, int apropos_mode) { + char **manpath_array; + char *current_path, *p, *q, *r, *keyword; + FILE *fp; + char dirbrk; + int i, j, matches; + +#ifdef DEBUG + assert ((apropos_mode == WHATIS_MODE) || + (apropos_mode == MAN_K_MODE) || + (apropos_mode == MAN_F_MODE) || + (apropos_mode == ORCA_K_MODE) || + (apropos_mode == ORCA_F_MODE) || + (apropos_mode == ORCA_W_MODE)); +#endif + + matches = 0; + + /* + * if we're doing 'man -f', get the basename for all keywords + */ + if ((apropos_mode == MAN_F_MODE) || (apropos_mode == ORCA_F_MODE)) { + for (i=0; i. All rights reserved. +.\" +.TH CATMAN 8 "System Administration" "24 July 95" "Version 1.0" +.SH NAME +catman \- format cat pages from man pages +.SH SYNOPSIS +.BR catman +[ +.B -pvV +] [[ +.BI -M path +] | [ +.BI -m path +]] [ +.IR section " ..." +] +.SH DESCRIPTION +.BR catman +creates formatted versions of the on-line manual pages from their +.BR nroff (1) +or +.BR aroff (1) +source. +Manual pages whose formatted versions are missing or out of date are +regenerated. +.LP +If +.IR section +is specified, then +.BR catman +will only created formatted manual pages for the specified +.IR section (s). +.LP +Manual pages that are +.BR nroff (1) +source and are compressed with either +.BR compress (1), +.BR freeze (1), +or +.BR gzip (1) +are recognised provided that they have the suffixes +.BR ".Z" , +.BR ".F" , +and +.BR ".gz" , +respectively. Manual page names, including suffixes, are case sensitive. +.LP +Preformatted manual pages will be created in +.BI cat ? +only if that subdirectory exists. +.SH OPTIONS +.IP \fB-p\fP +Display the commands that would have been executed, but do not actually +execute them. +.IP "\fB-M\fR \fIpath\fR" +Set +.I path +to be the list of paths for which manual pages will be updated. +If not set, the value of +.BR MANPATH , +.BR USRMAN , +or +.BR MANDIR +will be used instead. Multiple directories may be specified by +separating them either by colons or by spaces. In the latter case, +be sure to quote +.I path +from the shell. +.IP "\fB-m\fR \fIpath\fR" +Append +.I path +on to the list of paths for which manual pages will be updated. +.IP \fB-V\fR +Display version information and exit. +.IP \fB-v\fR +Verbose. Show processing information. +.SH BUGS +Please report any bugs to Devin Reade, . +.SH SEE ALSO +.BR apropos (1), +.BR man (1), +.BR whatis (1), +.BR gzip (1), +.BR compress (1), +.BR freeze (1), +.BR makewhatis (8). +.SH WARNING +.BR catman +will unlink any out-of-date files in the +.BI cat ? +subdirectories. The files that would be unlinked are listed when +.BR catman +is invoked with the +.BR -p +option. diff --git a/usr.bin/man/catman.c b/usr.bin/man/catman.c new file mode 100644 index 0000000..921bc0a --- /dev/null +++ b/usr.bin/man/catman.c @@ -0,0 +1,356 @@ +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +segment "catman____"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" +#include "man.h" + +#define OVERFLOW_ABORT(line,file) { \ + fprintf(stderr,overflowMsg,line,file); \ + exit(1); \ +} + +short v_flag, V_flag, M_flag, m_flag, p_flag, err_flag; + +extern int optind; +extern char *optarg; + +static char *versionstr = "1.0"; + +/* This is of the form "man
" */ +char mandir[FILENAME_MAX]; + +/* + * These are of the form + * "(man|cat)
/.
[.]" + */ +char manfile[FILENAME_MAX]; +char catfile[FILENAME_MAX]; +char catfile2[FILENAME_MAX]; + +char base[FILENAME_MAX]; + +static char *overflowMsg = "internal buffer overflow at line %d of %s\n"; + +extern void begin_stack_check(void); +extern int end_stack_check(void); + +/* + * catman + * + * Pre: argv is an array of section numbers (character strings), possibly + * empty. + * argc is the number of entries in argv. + * global variable is a space- or colon-delimited list + * of pathnames. + * + * Post: for each pathname in , catman will preformat the manpages + * within the man* subdirectories and place the result in the + * corresponding cat* subdirectory. If section numbers are specified, + * only those sections will be done. + * + * Returns 0 on success, 1 on failure. + */ + +int catman(int argc, char **argv) { + + char **manpath_array; /* MANPATH components in array form */ + char *current_path; /* the current MANPATH component */ + int i; /* an index */ + int pathIndex; /* offset into manpath_array[] */ + int sectionIndex; /* offset into sections[] */ + DIR *manp, *catp; /* directory pointers */ + struct dirent *entp; /* current file entry in manp */ + char *sec; /* the current section "number" */ + int catfile_found; /* have we found a preformatted version */ + /* that's newer than the unformatted version? */ + fileType *ftype; /* the file type of the man page */ + struct stat statbuf1, statbuf2; + char dirbrk; + + /* create array of paths to search */ + if ((manpath_array = makePathArray(manpath)) == NULL) return 1; + + /* loop over paths in MANPATH */ + pathIndex=0; + current_path = manpath_array[pathIndex]; + while(current_path) { + + dirbrk = (strchr(current_path,':')==NULL) ? '/' : ':'; + + /* go to the current path in MANPATH */ + if (v_flag) printf("cd %s\n",current_path); + if (chdir(current_path) == -1) { + pathIndex++; + current_path = manpath_array[pathIndex]; + continue; + } + + + /* loop over sections */ + for (sectionIndex=0; sections[sectionIndex].name!=NULL; sectionIndex++){ + + /* + * if section number was specified and this isn't it, do + * the next loop + */ + if (argc > 0) { + sec = NULL; + for (i=0; i= FILENAME_MAX) { + OVERFLOW_ABORT(__LINE__,__FILE__); + } + sprintf(mandir,"man%s",sec); + if ((manp = opendir(mandir)) == NULL) continue; + + /* make sure the cat? directory exists, but leave it closed */ + sprintf(catfile,"cat%s",sec); + if ((catp = opendir(catfile)) == NULL) { + closedir(manp); + continue; + } else { + closedir(catp); + } + + /* loop over files in this section */ + while ((entp = readdir(manp)) != NULL) { + + /* skip standard file entries */ + if (!strcmp(entp->d_name,".") || !strcmp(entp->d_name,"..")) { + continue; + } + + /* + * make the base the name of the man? entry excluding + * any compression suffix + */ + strcpy(base,entp->d_name); + for (i=0; compressArray[i].suffix != NULL; i++) { + size_t len1, len2; + + len1 = strlen(compressArray[i].suffix); + len2 = strlen(base); + if (!strcmp(compressArray[i].suffix, + (char *)(base + len2 - len1))) { + *(base + len2 - len1) = '\0'; + break; + } + } + + /* + * set manfile and catfile properly + */ + + sprintf(manfile,"man%s%c%s",sec,dirbrk,entp->d_name); + sprintf(catfile,"cat%s%c%s",sec,dirbrk,base); + + if (stat(manfile,&statbuf1) != 0) { + fprintf(stderr,"stat on %s failed: %s: file skipped\n", + manfile, strerror(errno)); + continue; + } + + /* + * search for an uncompressed file in the cat? directory, + * unlinking any older files. + */ + catfile_found=0; + if (stat(catfile,&statbuf2) == 0) { + if (statbuf1.st_mtime <= statbuf2.st_mtime) { + catfile_found++; + } else { + if (v_flag) printf("rm %s%c%s\n",current_path,dirbrk,catfile); + if (!p_flag) unlink(catfile); + } + } + + /* + * search for any compressed files in the cat? directory, + * unlinking any older files. + */ + for(i=0;compressArray[i].suffix != NULL; i++) { + sprintf(catfile2,"cat%s%c%s%s",sec,dirbrk,base, + compressArray[i].suffix); + if (stat(catfile2,&statbuf2) == 0) { + if ((!catfile_found) && + (statbuf1.st_mtime <= statbuf2.st_mtime)) { + strcpy(catfile,catfile2); + catfile_found++; + } else { + if (v_flag) + printf("rm %s%c%s\n",current_path,dirbrk,catfile2); + if (!p_flag) unlink(catfile2); + } + } + } + if (catfile_found) continue; + + /* + * If we got to this point, then we will be preformatting + * the manual page. There is also no version of the man + * page left in cat?. + */ + + sprintf(catfile,"cat%s%c%s",sec,dirbrk,base); + i = getSuffixIndex(manfile); + if (i >= 0) { + if (strlen(compressArray[i].extractor) + strlen(manfile) + + strlen(NROFF) + strlen(catfile) + 14 >= BUFFERSIZE) { + OVERFLOW_ABORT(__LINE__,__FILE__); + } + sprintf(linebuf,"%s %s | %s -man - > %s", + compressArray[i].extractor,manfile,NROFF,catfile); + } else { + + /* determine which roffer to use based on the file type */ + if ((ftype = getFileType(manfile)) == NULL) { + fprintf(stderr,"getFileType failed for %s: %s\n", + manfile,strerror(errno)); + continue; + } + if ((ftype->type == 0x50) && (ftype->auxtype == 0x8010)) { + if (strlen(AROFF) + strlen(manfile) + strlen(catfile) + >= BUFFERSIZE) { + OVERFLOW_ABORT(__LINE__,__FILE__); + } + sprintf(linebuf,"%s %s > %s",AROFF,manfile,catfile); + } else if ((ftype->type == TXT) || (ftype->type == BIN) || + (ftype->type == SRC) || (ftype->type == NON)) { + if (strlen(NROFF) + strlen(manfile) + strlen(catfile) + >= BUFFERSIZE) { + OVERFLOW_ABORT(__LINE__,__FILE__); + } + sprintf(linebuf,"%s -man %s > %s",NROFF,manfile,catfile); + } else { + fprintf(stderr,"illegal file type for %s: file skipped\n", + manfile); + continue; + } + } + if (v_flag) printf("%s\n",linebuf); + if (!p_flag) system(linebuf); + } /* done looping over files */ + closedir(manp); + } /* done looping over sections */ + + /* set up for the next component of MANPATH */ + pathIndex++; + current_path = manpath_array[pathIndex]; + } +} + + +int main (int argc, char **argv) { + char *path; + int i, result1, result2; + + /* make sure Gno is running */ + if (needsgno()==0) { + fprintf(stderr,"Requires Gno/ME\n"); + return 1; + } + +#ifdef STACK_CHECK + begin_stack_check(); +#endif + + /* initialization */ + v_flag = V_flag = M_flag = m_flag = p_flag = err_flag = 0; + result1 = result2 = 0; + + /* parse command line and check usage */ + while((i = getopt(argc,argv,"M:m:pVv")) != EOF) { + switch(i) { + case 'M': + if (m_flag) err_flag++; + M_flag++; + path = optarg; + break; + case 'm': + if (M_flag) err_flag++; + m_flag++; + path = optarg; + break; + case 'p': + p_flag++; + v_flag++; + break; + case 'V': + V_flag++; + break; + case 'v': + v_flag++; + break; + default: + err_flag++; + } + } + if (err_flag || V_flag) { + fprintf(stderr,"%s version %s by Devin Reade\n", + basename(argv[0]),versionstr); + } + if (err_flag) { + fprintf(stderr,"Usage: %s [-pVv] [-M path] [-m path] [section ...]\n", + basename(argv[0])); + } + if (err_flag || V_flag) return 1; + + /* translate selected "sections" into something more understandable */ + for (i=optind; i. For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +segment "common____"; + +#include +#include +#include "man.h" + +/* + * getSuffixIndex + * + * return the index into compressArray of the appropriate + * suffix/decompresser. If there is no match, return -1. + */ + +int getSuffixIndex(char *name) { + char *p; + int i; + + for (i=0; compressArray[i].suffix != NULL; i++) { + p = strstr(name,compressArray[i].suffix); + if (p && !*(p + strlen(compressArray[i].suffix))) return i; + } + return -1; +} diff --git a/usr.bin/man/describe.man b/usr.bin/man/describe.man new file mode 100644 index 0000000..4954e80 --- /dev/null +++ b/usr.bin/man/describe.man @@ -0,0 +1,50 @@ +Name: apropos +Version: 3.0 (24 Jul 95) +Author: Devin Reade. +Contact: gdr@myrias.com +Where: /usr/bin +FTP: ftp.cco.caltech.edu, grind.isca.uiowa.edu + + Locate commands by keyword. Bundled with catman, makewhatis, +man, and whatis in the manpack30.shk archive. + +Name: catman +Version: 1.0 (24 Jul 95) +Author: Devin Reade. +Contact: gdr@myrias.com +Where: /usr/sbin +FTP: ftp.cco.caltech.edu, grind.isca.uiowa.edu + + Preformat manual reference pages. Bundled with apropos, makewhatis, +man, and whatis in the manpack30.shk archive. + +Name: makewhatis +Version: 1.2 (24 Jul 95) +Author: Devin Reade. +Contact: gdr@myrias.com +Where: /usr/sbin +FTP: ftp.cco.caltech.edu, grind.isca.uiowa.edu + + Create the whatis database used by man(1), apropos(1), and whatis(1). +Bundled with apropos, catman, man, and whatis in the manpack30.shk archive. + +Name: man +Version: 3.0 (24 Jul 95) +Author: Devin Reade. +Contact: gdr@myrias.com +Where: /usr/bin +FTP: ftp.cco.caltech.edu, grind.isca.uiowa.edu + + Display manual reference pages. Bundled with apropos, catman, +makewhatis, and whatis in the manpack30.shk archive. + +Name: whatis +Version: 3.0 (24 Jul 95) +Author: Devin Reade. +Contact: gdr@myrias.com +Where: /usr/bin +FTP: ftp.cco.caltech.edu, grind.isca.uiowa.edu + + Locate commands by name. Bundled with apropos, catman, +makewhatis, and man in the manpack30.shk archive. + diff --git a/usr.bin/man/fillbuffer.c b/usr.bin/man/fillbuffer.c index 72392ce..3cd4b38 100644 --- a/usr.bin/man/fillbuffer.c +++ b/usr.bin/man/fillbuffer.c @@ -1,6 +1,10 @@ -#ifdef __CCFRONT__ -#include <14:pragma.h> -#endif +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +segment "makewhatis"; #include #include @@ -17,17 +21,17 @@ #define DESCRIPTION2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN" #define DESCRIPTION3 "D\bD\bD\bDE\bE\bE\bES\bS\bS\bSC\bC\bC\bCR\bR\bR\bRI\bI\bI\bIP\bP\bP\bPT\bT\bT\bTI\bI\bI\bIO\bO\bO\bON\bN\bN\bN" - char buffer[BUFFERSIZE]; /* contains the command description */ + char buffer[BUFFERSIZE]; /* contains the command description */ char titlebuf[BUFFERSIZE]; /* contains the command name */ -static char buffer2[BUFFERSIZE]; /* used for chars read from man page */ +static char buffer2[BUFFERSIZE]; /* used for chars read from man page */ #ifdef TEST_FILLBUFFER - short v_flag=2; -# define output_fp stdout -# define error_fp stderr + short v_flag=2; +# define output_fp stdout +# define error_fp stderr #else - extern FILE *output_fp; /* output file descriptor -- may be stdout */ - extern FILE *error_fp; /* error file descriptor -- may be stderr */ + extern FILE *output_fp; /* output file descriptor -- may be stdout */ + extern FILE *error_fp; /* error file descriptor -- may be stderr */ #endif /* void fillbuffer (char *filename); @@ -55,13 +59,14 @@ static char buffer2[BUFFERSIZE]; /* used for chars read from man page */ */ void fillbuffer (char *filename) { - FILE *fp; /* FILE pointer for filename */ - int count; /* how many chars were read into buffer2 */ - char *p1; /* points to current char in buffer2 */ + FILE *fp; /* FILE pointer for filename */ + int count; /* how many chars were read into buffer2 */ + char *p1; /* points to current char in buffer2 */ char *p2; /* points to last char (of interest) in buffer2 */ - char *p3; /* points to current char in buffer */ - short found; /* some flags */ - short in_comment; + char *p3; /* points to current char in buffer */ + char *p6; /* scratch */ + short found; /* some flags */ + short in_comment; short in_format_BR; short in_format_f; short foo; @@ -77,12 +82,12 @@ void fillbuffer (char *filename) { char *p4 = buffer + BUFFERSIZE; char *p5 = titlebuf + BUFFERSIZE; - /* + /* * open the file */ if ((fp = fopen(filename,"rb")) == NULL) { - buffer[0] = '\0'; + buffer[0] = '\0'; if (v_flag) fprintf (error_fp,"Open failed for file \"%s\"\n",filename); return; } @@ -91,7 +96,7 @@ void fillbuffer (char *filename) { * see if it includes another man page */ if ((fgets(buffer2,4,fp) == NULL) || (strncmp(buffer2,".so",3)==0)) { - buffer[0] = '\0'; + buffer[0] = '\0'; titlebuf[0] = '\0'; fclose(fp); return; @@ -106,12 +111,12 @@ void fillbuffer (char *filename) { for(;;) { - /* + /* * read in buffer2 in a line-oriented fashion at first so that we * can more easily ignore .\" and .TH lines */ - if (fgets(buffer2,BUFFERSIZE,fp)==NULL) { + if (fgets(buffer2,BUFFERSIZE,fp)==NULL) { /* * eof or error, and we haven't found "NAME" yet ... return * an empty string @@ -120,13 +125,13 @@ void fillbuffer (char *filename) { titlebuf[0] = '\0'; fclose(fp); if (v_flag) fprintf (error_fp, - "EOF or error on %s, NAME not found.\n",filename); + "EOF or error on %s, NAME not found.\n",filename); return; } /* ignore comment lines and any .TH line(s) */ if ((strncmp(buffer2,".\\\"",3)==0) || (strncmp(buffer2,".TH",3)==0)) - continue; + continue; /* check the various versions of "NAME" */ if (strstr(buffer2,NAME1) != NULL) break; @@ -148,33 +153,33 @@ void fillbuffer (char *filename) { */ p3 = titlebuf; - found = 0; /* set this when we find '-' */ - in_format_BR = 0; /* in the middle of a .BR format */ - in_format_f = 0; /* in the middle of a \fI format */ - in_comment = 0; /* in the middle of a .\" comment */ - foo = 0; /* haven't found the printable character after NAME */ + found = 0; /* set this when we find '-' */ + in_format_BR = 0; /* in the middle of a .BR format */ + in_format_f = 0; /* in the middle of a \fI format */ + in_comment = 0; /* in the middle of a .\" comment */ + foo = 0; /* haven't found the printable character after NAME */ for(;;) { - /* read another block into buffer2. */ + /* read another block into buffer2. */ - count = fread(buffer2,sizeof(char),BUFFERSIZE-1,fp); + count = fread(buffer2,sizeof(char),BUFFERSIZE-1,fp); if (count == 0) { - /* eof or error; empty buffer and titlebuf then return */ + /* eof or error; empty buffer and titlebuf then return */ buffer[0] = '\0'; titlebuf[0] = '\0'; fclose(fp); if (v_flag) fprintf (error_fp, - "EOF or error on %s, command name not found.\n",filename); + "EOF or error on %s, command name not found.\n",filename); return; } - buffer2[count] = '\0'; - p1 = buffer2; + buffer2[count] = '\0'; + p1 = buffer2; /* mark the "end" of buffer2 with p2 */ if ((p2 = strchr(p1,'-')) != NULL) { - found = 1; + found = 1; } else { - p2 = buffer + count; + p2 = buffer + count; } /* @@ -183,17 +188,17 @@ void fillbuffer (char *filename) { */ if (in_comment) { - while((p1titlebuf) && (*p1 == ' ') && (*(p3-1) == ' ')) && - !((p3==titlebuf) && (*p3 == ' ')) + if ( !((p3>titlebuf) && (*p1 == ' ') && (*(p3-1) == ' ')) && + !((p3==titlebuf) && (*p3 == ' ')) ) { /* don't let a space precede a comma */ if ((*p1==',') && (*(p3-1)==' ')) { - *(p3-1) = ','; + *(p3-1) = ','; continue; } else *p3++ = *p1; - if (p3>=p5) { /* titlebuf overflow? */ - if (v_flag) - fprintf(error_fp,"command name buffer overflow on %s\n", - filename); - buffer[0] = '\0'; - titlebuf[0] = '\0'; - fclose(fp); - return; - } - } + if (p3>=p5) { /* titlebuf overflow? */ + if (v_flag) + fprintf(error_fp,"command name buffer overflow on %s\n", + filename); + buffer[0] = '\0'; + titlebuf[0] = '\0'; + fclose(fp); + return; + } + } } } - - if (found) { /* we've got all of the key words */ - p3--; /* p3 now points to last char, not terminator */ - if (*p3=='\\') p3--; + + if (found) { /* we've got all of the key words */ + p3--; /* p3 now points to last char, not terminator */ + if (*p3=='\\') p3--; while(isspace(*p3)) p3--; - *(p3+1) = '\0'; - break; + *(p3+1) = '\0'; + break; } - } + } p1 = p2 + 1; #ifdef ISGRAPH_FIX while ( (p1 < buffer2 + BUFFERSIZE) &&!(isgraph(*p1) && (*p1 != ' '))) p1++; @@ -315,24 +320,35 @@ void fillbuffer (char *filename) { */ p3 = buffer; - found = 0; /* set this when we find one of the above strings */ - in_format_BR = 0; /* in the middle of a .BR format */ - in_format_f = 0; /* in the middle of a \fI format */ - in_comment = 0; /* in the middle of a .\" comment */ + found = 0; /* set this when we find one of the above strings */ + in_format_BR = 0; /* in the middle of a .BR format */ + in_format_f = 0; /* in the middle of a \fI format */ + in_comment = 0; /* in the middle of a .\" comment */ for(;;) { /* mark the "end" of buffer2 with p2 */ if ( ((p2 = strstr(p1,".SH")) != NULL) || - ((p2 = strstr(p1,SYNOPSIS1)) != NULL) || - ((p2 = strstr(p1,SYNOPSIS2)) != NULL) || - ((p2 = strstr(p1,SYNOPSIS3)) != NULL) || + ((p2 = strstr(p1,SYNOPSIS1)) != NULL) || + ((p2 = strstr(p1,SYNOPSIS2)) != NULL) || + ((p2 = strstr(p1,SYNOPSIS3)) != NULL) || ((p2 = strstr(p1,DESCRIPTION1)) != NULL) || ((p2 = strstr(p1,DESCRIPTION2)) != NULL) || ((p2 = strstr(p1,DESCRIPTION3)) != NULL) ) { - found = 1; + *p2 = '\0'; + /* + * this conditional is to cover the wierd case of having the word + * "SYNOPSIS" appearing in the description (or elsewhere), as + * it does for the GNO Intro(1) man page. Blech. Only in + * aroff source or a preformatted page would this matter. + */ + if (((p6 = strstr(p1,SYNOPSIS1)) != NULL) || + ((p6 = strstr(p1,DESCRIPTION1)) != NULL)) { + p2 = p6; + } + found = 1; } else { - p2 = buffer + count; + p2 = buffer + count; } /* @@ -341,17 +357,17 @@ void fillbuffer (char *filename) { */ if (in_comment) { - while((p1buffer) && (*p1 == ' ') && (*(p3-1) == ' ')) && - !((p3==buffer) && (*p3 == ' ')) + if ( !((p3>buffer) && (*p1 == ' ') && (*(p3-1) == ' ')) && + !((p3==buffer) && (*p3 == ' ')) ) { - *p3++ = *p1; - if (p3>=p4) { /* buffer overflow? */ - if (v_flag) - fprintf(error_fp,"command description buffer overflow on %s\n", - filename); - buffer[0] = '\0'; - titlebuf[0] = '\0'; - fclose(fp); - return; - } - } + *p3++ = *p1; + if (p3>=p4) { /* buffer overflow? */ + if (v_flag) + fprintf(error_fp,"command description buffer overflow on %s\n", + filename); + buffer[0] = '\0'; + titlebuf[0] = '\0'; + fclose(fp); + return; + } + } } } - - if (found) { /* we've got the entire description */ - *p3 = '\0'; - break; + + if (found) { /* we've got the entire description */ + *p3 = '\0'; + break; } /* * We're part way through the description; read another block * into buffer2. - */ + */ - count = fread(buffer2,sizeof(char),BUFFERSIZE-1,fp); + count = fread(buffer2,sizeof(char),BUFFERSIZE-1,fp); if (count == 0) { /* eof or error; terminate buffer and return */ *p3 = '\0'; fclose(fp); if (v_flag) fprintf (error_fp, - "EOF or error on %s, description not found.\n",filename); + "EOF or error on %s, description not found.\n",filename); return; } - buffer2[count] = '\0'; - p1 = buffer2; - - } + buffer2[count] = '\0'; + p1 = buffer2; + + } /* * close the file @@ -452,36 +468,3 @@ void fillbuffer (char *filename) { return; } - - -#ifdef TEST_FILLBUFFER - -int main(int argc, char **argv) { - - if (argc != 2) { - fprintf(stderr,"Usage: %s \n\n",argv[0]); - return -1; - } - - fillbuffer(argv[1]); - - - - if (strlen(titlebuf) == 0) { - printf("title buffer empty\n"); - } else { - printf("main: title buffer is %lu chars long\n%s\n", - strlen(titlebuf),titlebuf); - } - - if (strlen(buffer) == 0) { - printf("buffer empty\n"); - } else { - printf("main: buffer is %lu chars long\n%s\n",strlen(buffer),buffer); - } - - - return 0; -} - -#endif diff --git a/usr.bin/man/globals.c b/usr.bin/man/globals.c new file mode 100644 index 0000000..1891cb6 --- /dev/null +++ b/usr.bin/man/globals.c @@ -0,0 +1,42 @@ +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +#include +#include "man.h" + +/* + * The compression suffixes and how to uncompress the files. + * If you use ".l" (that's "ell") as a suffix, you will break the + * algorithm for dereferencing aroff "links". + */ + +compressionType compressArray[] = { + { ".Z", "compress -cd" }, + { ".F", "freeze -cd" }, + { ".gz", "gzip -cd" }, + { NULL, NULL } +}; + +char linebuf[BUFFERSIZE]; +char linebuf2[BUFFERSIZE]; +char *manpath; + +Section sections[] = { + { "1", "1" }, + { "2", "2" }, + { "3", "3" }, + { "3f", "3f" }, + { "4", "4" }, + { "5", "5" }, + { "6", "6" }, + { "7", "7" }, + { "8", "8" }, + { "new", "n" }, /* the words "new", "local", "public", */ + { "local", "l" }, /* and "old" can be abbreviated on the */ + { "public", "p" }, /* command line with "n", "l", "p", and */ + { "old", "o" }, /* "o", respectively */ + { NULL, NULL } /* MUST be NULL-terminated! */ +}; diff --git a/usr.bin/man/makefile.mk b/usr.bin/man/makefile.mk index 223e857..0f00321 100644 --- a/usr.bin/man/makefile.mk +++ b/usr.bin/man/makefile.mk @@ -1,54 +1,70 @@ # -# Makefile for dmake(1) +# Makefile for the man package, for use with dmake(1). # -# Location for executable. It should be /usr/sbin +# Location for executables. They should normally be /usr/sbin and /usr/bin. -BINDIR = /usr/sbin +SBINDIR = /usr/sbin +BINDIR = /usr/bin -# Location for man pages. +# Location for man pages. Usually /usr/man. -MANDIR = /usr/man +MANDIR = /usr/man # -# Nothing past this point should have to be changed +# You should not have to change anything below this line # -# -DISGRAPH_FIX should come out when Orca/C's isgraph() function is fixed. +# Define: -DDEBUG to produce more debugging info and checks # -# -DTEST_PROCESS is for debugging process(). Use "dmake process". -# -DDEBUG will give stack usage. +# -DSTACK_CHECK to show stack usage. If you use this +# one, ensure you add -l/usr/lib/stack to your LDLIBS. # -CFLAGS = -w -O -v -DISGRAPH_FIX -s1024 +STACK = -s1270 +DEFINES = +CFLAGS = $(DEFINES) $(STACK) -w -v -O -I/usr/include +LDFLAGS = -v +LDLIBS = -l/usr/lib/gnulib -l/usr/lib/stack +CP = /bin/cp -f -OBJS = makewhatis.o fillbuffer.o process.o -LDLIBS = -l/usr/lib/gnulib -l/usr/lib/stack - -makewhatis: $(OBJS) - $(CC) $(OBJS) $(LDLIBS) -o makewhatis +build: apropos catman makewhatis man whatis -makewhatis.o: makewhatis.c makewhatis.h - $(CC) -c $(CFLAGS) makewhatis.c +apropos: apropos.o apropos2.o util.o utilgs.o globals.o + $(CC) $(LDFLAGS) $< $(LDLIBS) -o $@ -fillbuffer.o: fillbuffer.c makewhatis.h - $(CC) -c $(CFLAGS) fillbuffer.c +catman: catman.o util.o utilgs.o globals.o common.o + $(CC) $(LDFLAGS) $< $(LDLIBS) -o $@ -process.o: process.c makewhatis.h - $(CC) -c $(CFLAGS) process.c +makewhatis: makewhatis.o fillbuffer.o process.o + $(CC) $(LDFLAGS) $< $(LDLIBS) -o $@ + +man: man.o man2.o apropos2.o util.o utilgs.o globals.o common.o + $(CC) $(LDFLAGS) $< $(LDLIBS) -o $@ + +whatis: whatis.o apropos2.o util.o utilgs.o globals.o + $(CC) $(LDFLAGS) $< $(LDLIBS) -o $@ + +clobber: + $(RM) *.o *.root install: - /bin/cp makewhatis $(BINDIR) - /bin/cp makewhatis.1 $(MANDIR)/man1 + $(CP) apropos man whatis $(BINDIR) + $(CP) catman makewhatis $(SBINDIR) + $(CP) apropos.1 man.1 whatis.1 $(MANDIR)/man1 + $(CP) catman.8 makewhatis.8 $(MANDIR)/man8 -clean: - /bin/cp -p rm $(OBJS) +# additional dependancies -# -# These are just for debugging purposes -# - -fillbuffer: fillbuffer.c makewhatis.h - $(CC) $(CFLAGS) -DTEST_FILLBUFFER -o fillbuffer fillbuffer.c - -process: process.o fillbuffer.o - $(CC) $(CFLAGS) process.o fillbuffer.o -o process +apropos.o:: man.h util.h +apropos2.o:: man.h util.h +catman.o:: man.h util.h +common.o:: man.h util.h +fillbuffer.o:: makewhatis.h +globals.o:: man.h +makewhatis.o:: makewhatis.h +man.o:: man.h util.h +man2.o:: man.h util.h +process.o:: makewhatis.h +util.o:: util.h +utilgs.o:: util.h +whatis.o:: man.h util.h diff --git a/usr.bin/man/makewhatis.8 b/usr.bin/man/makewhatis.8 index 50d34e3..5200fd2 100644 --- a/usr.bin/man/makewhatis.8 +++ b/usr.bin/man/makewhatis.8 @@ -1,166 +1,254 @@ -.TH MAKEWHATIS 1 "Commands and Applications" "29 May 1994" "Version 1.1" +.TH MAKEWHATIS 8 "System Administration" "24 July 1995" "Version 1.2" .SH NAME .B makewhatis \- generate the whatis database file .SH SYNOPSIS .B makewhatis [ -.I -c +.B -c | -.I -C +.B -C ] [ -.I "-f outfile" +.BI -f " outfile" ] [ -.I "-l logfile" +.BI -l " logfile" ] [ -.I "-o dbfile" +.BI -o " dbfile" ] [ -.I "-p path" +.BI -p " path" ] [ -.I "-v n" +.BI -v " n" ] [ -.I "-V" +.B -V ] .SH DESCRIPTION .B makewhatis generates the whatis database for -.BR whatis "(1) and " apropos "(1)." +.BR apropos (1), +.BR man (1), +and +.BR whatis (1). This database is a text file containing line oriented records. Each record contains a man page name, the section number, and the brief description. .LP -By default, -.B makewhatis -makes use of one of the environment variables \fIMANPATH\fR, \fIUSRMAN\fR, -or \fIMANDIR\fR, in the listed order of preference. It will use this +.B Makewhatis +makes use of one of the environment variables +.BR MANPATH , +.BR USRMAN , +or +.BR MANDIR , +in the listed order of preference. It will use this environment variable to determine for which manual pages the whatis database should be built. If the environment variable contains more than -one path (delimited by spaces), then whatis databases will be generated -in all of the specified paths. -.LP -The routines used are compatible with man pages in -.BR nroff , -.BR aroff , -.BR compress ", or" -.BR freeze -format, as well as text versions of manual pages in the man/catX hierarchy. -.B Makewhatis -assumes that the suffixes \fI.Z\fR and \fI.F\fR are are appended to the -chapter number on file names when those files are in -.BR compress " or " freeze -format, respectively. (For example, a compressed file would be expected -to have a file name similar to -.I foo.3.Z -or \fIbar.3v.Z\fR.) -Any files using the -.I ".l" -(ell) suffix are ignored. All suffix tests are case insensitive. +one path (delimited by either colons or spaces), +then whatis databases will be generated +in all of the specified paths. This may be overridden by the +.BR -p +flag. .LP By default, -.B makewhatis -will only use files in the man/manX hierarchy in the creation of the -database. However, since many Gno programmers are providing only text -versions of their man pages, invoking -.B makewhatis -with the +.BR makewhatis +will generate its database from manual pages existing in the +.IB manpath_component /man X +subdirectories (where +.I X +is the section number) +that are either +.BR aroff +or +.BR nroff +source files. +However, since many GNO programmers are providing only preformatted +text versions of their man pages, using the .I -c -flag will add descriptions for all files in the man/catX hierarchy that -don't have a counterpart in the man/manX hierarchy. This conditional -eliminates the parsing of files in man/catX generated by -.BR catman (1). +flag will cause +.B makewhatis +to also use manual pages in the +.IB manpath_component /cat X +subdirectories when building the database. +If there is a corresponding manual page in both the +.BI man X +and +.BI cat X +subdirectory, then only the page in the +.BI man X +subdirectory will be used. +.LP +Manual pages which are +.BR nroff +source files in the +.BI man X +subdirectory, or are preformatted text in the +.BI cat X +subdirectory may be compressed by either +.BR compress (1), +.BR freeze (1), +or +.BR gzip (1), +provided that the suffixes on the compressed file are +.BR ".Z" , +.BR ".F" , +and +.BR ".gz" , +respectively. The case of the suffix is significant. +.BR Aroff +source files +.I "must not" +be compressed by any method. +.LP +All +.BR aroff +link files are ignored. A file is assumed to be an +.BR aroff +link file if it ends in +.B ".l" +(dot lower-case ell) and is not within a +.BR manl +(man-ell) or a +.BR catl +(cat-ell) subdirectory. .LP Note that the lines in the whatis database file are created in the order -that the man pages are found. It is suggested that the database be sorted -after +that the man pages are found. It is suggested that the database files +be sorted after .B makewhatis is finished. See -.BR sort (1). +.BR sort (1) +or +.BR msort (1) . .SH OPTIONS -.I -c -will check man/catX sub-directories as well as man/manX -.LP -.I -C +.IP "\fB\-c\fP" +will check +.BI cat X +subdirectories as well as +.BI man X +subdirectories. +.IP \fB\-C\fP will check -.BR only -man/catX sub-directories, not man/manX sub-directories. -.LP -.I "-f outfile" +.I only +.BI cat X +subdirectories, +.I not +.BI man X +subdirectories. +.IP "\fB-f\fR \fIoutfile\fR" causes the .B makewhatis -status output to be placed in \fIoutfile\fR. Invoking -.I "-f" +status output to be placed in +.IR outfile . +Invoking +.B -f without -.I "-v2" +.B -v2 produces no output. -.LP -.I "-l logfile" -will cause any error messages to be printed to \fIlogfile\fR. Invoking -.I "-l" +.IP "\fB-l\fR \fIlogfile\fR" +will cause any error messages to be printed to +.IR logfile . +Invoking +.B -l without either -.I "-v1" +.B -v1 or -.I "-v2" +.B -v2 produces no output. -.LP -.I "-o dbfile" +.IP "\fB-o\fR \fIdbfile\fR" will make .B makewhatis use .I dbfile as the name for the generated whatis databases. While it is possible to use a full pathname for -.I dbfile -, this will result in that file being overwritten for each space-delimited -entry in \fIMANPATH\fR. -.LP -.I "-p path" +.IR dbfile , +this will result in that file being overwritten for each colon- or +space-delimited entry in +.BR MANPATH . +.IP "\fB-p\fR \fIpath\fR" overrides the environment variables -.I MANPATH +.B MANPATH et al for determining for which manual page hierarchies the databases must be generated. -.LP -.I "-v n" -creates verbose status messages during execution. For n=1 only error -messages are printed out. For n=2, both error and status messages are -printed. -.LP -.I -V +.IP "\fB-v\fR \fIn\fR" +creates verbose status messages during execution. For +.IR n =1 +only major error messages are printed out. For +.IR n =2, +the names of processed files are also printed. For +.IR n =3, +the output becomes very verbose with excessive status information, including +listing any missing subdirectores. +.IP \fB-V\fR will show version and usage information, then exit. .SH ENVIRONMENT -\fIMANPATH\fR, \fIUSRMAN\fR, \fIMANDIR\fR: +.BR MANPATH .br +.BR USRMAN +.br +.BR MANDIR +.RS Unless the -.I -p +.B -p flag is used, .B makewhatis will use the first that it finds of these environment variables for -determining where database files should be generated. While +determining where database files should be generated. The search +is done in the order shown. While .B makewhatis will correctly handle -.I ~ +.RB ` ~ ' and -.I . -being part of these paths, it will not correctly handle \fI..\fR. +.RB ` . ' +being part of these paths, it will not correctly handle +.RB ` .. '. +.sp 1 +Either colons or spaces can be used to delimit the individual paths. +If the value of the selected environment variable contains no spaces +nor +.B / +characters (such as +.BR :usr:local:man ), +it is assumed to be a single path, not a list of paths. +.sp 1 +Although +.B makewhatis +allows +.BR USRMAN +and +.BR MANDIR +to be each a colon- or space-separated list of pathnames, +it is recommended that for compatibility with +.BR man +(version 2.1 and earlier) these variables, if used, should be +a single pathname. +.RE .SH CAVEATS .B Makewhatis assumes that the programs .BR aroff , -.BR compress ", and" -.BR freeze -are available to the executing shell via the \fIsystem\fR(2) call. -Nroff is not used and need not be available. +.BR compress , +.BR freeze , +and +.BR gzip +are available to the executing shell via the +.BR system (2) +call. +.BR Nroff +is not used and need not be available. .LP Because .B makewhatis looks for the string -.I NAME -and one of \fI.SH\fR, \fISYNOPSIS\fR, or -.I DESCRIPTION +.B NAME +and one of +.BR .SH , +.BR SYNOPSIS , +or +.B DESCRIPTION when processing files, it can be confused by missing fields or -some methods of formatting. For example, if in a man/catX page -.I NAME +some methods of formatting. For example, if in a preformatted manual page +.B NAME is underlined by repeated backspace-_ sequences, then the generated description for that particular man page is unpredictable, -though usually blank. When parsing man pages, +though usually blank. When parsing preformatted manual pages, .B makewhatis will understand the common double- and quadruple-boldfaced subheadings, provided @@ -169,18 +257,15 @@ that the backspace character (control-H) is used to achieve this effect. Similarily, .B makewhatis expects the subheading -.I NAME +.B NAME to be in the format: .nf NAME - - + \fIcommand_name\fR [...] - \fIbrief description\fR .fi If this is not so (ignoring whitespace), then the output is unpredictable. .LP -Man pages must be CR-deliminated. -.LP -If aroff source is compressed or frozen, the database entry for that -page is unpredictable. +Man pages must be CR-delimited (ASCII 015, or control\-M). .LP Where unpredictable output has been mentioned above, this means that the description in the database file will either be blank or random @@ -190,20 +275,21 @@ mean that system integrity or that the remainder of the database file has been affected. .LP Any text appearing after -.I NAME +.B NAME on the NAME header line will be ignored. .SH BUGS .B Makewhatis reads files in blocks of 1024 characters. If formatting information is split by the end of the input buffer, you may see formatting infomation such as -.I .BR +.B .BR in the output. This was not fixed due to the overhead of having to check for such a condition. +.LP +Please report any additional bugs to Devin Reade, . .SH FILES .nf -/usr/sbin/makewhatis -- whatis database generator -man/whatis -- the whatis database +/usr/[share/]man/whatis -- the whatis database .fi .SH SEE ALSO .BR apropos (1), @@ -211,8 +297,7 @@ man/whatis -- the whatis database .BR catman (1), .BR compress (1), .BR freeze (1), +.BR gzip (1), .BR man (1), .BR nroff (1), .BR whatis (1) -.SH AUTHOR -Written by Devin Reade for the Apple IIgs and Gno. diff --git a/usr.bin/man/makewhatis.c b/usr.bin/man/makewhatis.c index 4033d86..3d35b79 100644 --- a/usr.bin/man/makewhatis.c +++ b/usr.bin/man/makewhatis.c @@ -1,6 +1,10 @@ -#ifdef __CCFRONT__ -#include <14:pragma.h> -#endif +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +segment "makewhatis"; #include #include @@ -14,29 +18,30 @@ #include "makewhatis.h" -#ifdef DEBUG - extern void begin_stack_check(void); +#ifdef STACK_CHECK + extern void begin_stack_check(void); extern int end_stack_check(void); #endif /* * Options: * - * -c check cat* subdirectories as well - * -C check _only_ cat* subdirectories, not man* subdirectories. - * -f outfile force whatis status output to - * -l logfile log errors to - * -o dbfile force whatis database output to - * -p path use the rather than $MANPATH, $USRMAN, or $MANDIR - * -s sort the whatis database by manual page name - * -v{1|2} verbose - * -V show version and usage info and exit + * -c check cat* subdirectories as well + * -C check _only_ cat* subdirectories, not man* subdirectories. + * -f outfile force whatis status output to + * -l logfile log errors to + * -o dbfile force whatis database output to + * -p path use the rather than $MANPATH, $USRMAN, or $MANDIR + * -s sort the whatis database by manual page name + * -v{1|2|3} verbose + * -V show version and usage info and exit */ char *man_subdir[] = { - "man1", + "man1", "man2", "man3", + "man3f", "man4", "man5", "man6", @@ -44,7 +49,9 @@ char *man_subdir[] = { "man8", "mann", "manl", - NULL + "manp", + "mano", + NULL }; /* @@ -55,7 +62,7 @@ char *man_subdir[] = { char *cat_subdir[] = { "cat1", "cat2", - "cat3", + "cat3f", "cat4", "cat5", "cat6", @@ -63,7 +70,9 @@ char *cat_subdir[] = { "cat8", "catn", "catl", - NULL /* _must_ be NULL terminated! */ + "catp", + "cato", + NULL /* _must_ be NULL terminated! */ }; /* For the various command line flags */ @@ -73,10 +82,10 @@ short C_flag = 0; short o_flag = 0; short p_flag = 0; short v_flag = 0; -short errflag = 0; /* This is set if there is a usage error or -V flag */ +short errflag = 0; /* This is set if there is a usage error or -V flag */ -static char filebuffer[FILENAME_MAX]; /* used when traversing cat* pages */ -static char progdir[FILENAME_MAX]; /* the directory where makewhatis started */ +static char filebuffer[FILENAME_MAX]; /* used when traversing cat* pages */ +static char progdir[FILENAME_MAX]; /* the directory where makewhatis started */ FILE *output_fp; FILE *error_fp; @@ -84,15 +93,15 @@ FILE *error_fp; int main (int argc, char **argv) { - char *manpath; /* the location of the man pages */ - char *path; /* the current path; taken from manpath */ - char *p=NULL; /* a temporary pointer */ - struct dirent *file; /* the current file we have open */ - char tmp_file[L_tmpnam]; /* a scratch file */ - FILE *tmp_fp; /* pointer to tmp_file */ - FILE *whatis_fp; /* pointer to the current whatis database */ - DIR *subdir; /* the current man subdirectory -- eg: /usr/man/man3 */ - char *dbfile; /* non-default name of the whatis database */ + char *manpath; /* the location of the man pages */ + char *path; /* the current path; taken from manpath */ + char *p=NULL; /* a temporary pointer */ + struct dirent *file; /* the current file we have open */ + char tmp_file[L_tmpnam]; /* a scratch file */ + FILE *tmp_fp; /* pointer to tmp_file */ + FILE *whatis_fp; /* pointer to the current whatis database */ + DIR *subdir; /* the current man subdirectory -- eg: /usr/man/man3 */ + char *dbfile; /* non-default name of the whatis database */ char *dirsep; /* the directory separator, either "/" or ":" */ int i; extern int optind; @@ -100,12 +109,12 @@ int main (int argc, char **argv) { /* make sure Gno is running */ if (needsgno()==0) { - fprintf(stderr,"Requires Gno/ME\n"); + fprintf(stderr,"Requires Gno/ME\n"); return 1; } -#ifdef DEBUG - begin_stack_check(); +#ifdef STACK_CHECK + begin_stack_check(); #endif /* @@ -114,8 +123,8 @@ int main (int argc, char **argv) { output_fp = stdout; error_fp = stderr; - if (getwd(progdir) == NULL) { - perror("getwd() failed"); + if (getwd(progdir) == NULL) { + perror("getwd() failed"); exit(1); } @@ -123,56 +132,56 @@ int main (int argc, char **argv) { * parse the command line */ - while((i = getopt(argc,argv,"cCf:l:o:p:v:V")) != EOF) - switch(i) { + while((i = getopt(argc,argv,"cCf:l:o:p:v:V")) != EOF) + switch(i) { case 'c': - if (C_flag) errflag++; + if (C_flag) errflag++; else c_flag++; break; case 'C': - if (c_flag) errflag++; - else C_flag++; + if (c_flag) errflag++; + else C_flag++; break; case 'f': - output_fp = fopen (optarg,"w"); + output_fp = fopen (optarg,"w"); if (output_fp == NULL) { - fprintf(stderr,"Could not open output file %s; using stdout.\n", - optarg); + fprintf(stderr,"Could not open output file %s; using stdout.\n", + optarg); output_fp = stdout; } - break; + break; case 'l': - error_fp = fopen (optarg,"w"); + error_fp = fopen (optarg,"w"); if (error_fp == NULL) { - fprintf(stderr,"Could not open log file %s; using stderr.\n", - optarg); + fprintf(stderr,"Could not open log file %s; using stderr.\n", + optarg); error_fp = stderr; } break; case 'o': - o_flag++; + o_flag++; dbfile = optarg; break; case 'p': - p_flag++; + p_flag++; p = optarg; break; case 'v': - v_flag = (short) atoi(optarg); - if ((v_flag!=1) && (v_flag!=2)) errflag++; + v_flag = (short) atoi(optarg); + if ((v_flag<1) && (v_flag>3)) errflag++; break; case 'V': - fprintf(stderr, - "%s --\n\tCreate the %s database.\n\tVersion %s by Devin Reade\n\n", + fprintf(stderr, + "%s --\n\tCreate the %s database.\n\tVersion %s by Devin Reade\n\n", argv[0],WHATIS,VERSIONSTRING); errflag++; break; default: - errflag++; + errflag++; break; } - if (errflag) { - fprintf(error_fp, + if (errflag) { + fprintf(error_fp, "Usage:\n%s\t[-c|-C] [-f outfile] [-l logfile] [-o dbfile] [-p path]\n\ \t\t[-v 1|2] [-V]\n\n\ -c\t\tCheck catX subdirectories as well\n\ @@ -181,32 +190,29 @@ int main (int argc, char **argv) { -l logfile\tLog errors to .\n\ -o dbfile\tforce whatis database output to .\n\ -p path\t\tUse the rather than $MANPATH, $USRMAN, or $MANDIR.\n\ --v n\t\t=1: Verbose, only displaying major errors.\n\ -\t\t=2: Very verbose, displaying processing information.\n\ +-v n\t\t=1: Slightly verbose, only displaying major errors.\n\ +\t\t=2: Verbose, displaying processed file names.\n\ +\t\t=3: Very verbose, displaying more processing info.\n\ -V\t\tShow version and usage information, then exit.\n",argv[0]); - return -1; + return -1; } /* * get the location of the man pages; p is already set if -p flag used */ - if (p == NULL) p = getenv("MANPATH"); - if (p == NULL) p = getenv("USRMAN"); - if (p == NULL) p = getenv("MANDIR"); - if (p == NULL) { - fprintf(error_fp,"Location of man pages unknown. You must either define \ -environment variables\n$MANPATH, $USRMAN, or $MANDIR, or use the -p flag.\n\n"); - return -1; - } + if (p == NULL) p = getenv("MANPATH"); + if (p == NULL) p = getenv("USRMAN"); + if (p == NULL) p = getenv("MANDIR"); + if (p == NULL) p = DEFAULT_MANPATH; /* define the directory separator */ dirsep = (strchr(p,':')==NULL) ? "/" : ":"; /* make a copy of the location */ if ((manpath = malloc (strlen(p) + 1)) == NULL) { - if (v_flag) fprintf(error_fp, - "malloc failed while making copy of \"%s\"\nAborted.\n",p); + if (v_flag) fprintf(error_fp, + "malloc failed while making copy of \"%s\"\nAborted.\n",p); return -1; } strcpy(manpath,p); @@ -222,105 +228,106 @@ environment variables\n$MANPATH, $USRMAN, or $MANDIR, or use the -p flag.\n\n"); path = strtok (manpath," "); while (path != NULL) { - if (access(path,F_OK)==0) { + if (access(path,F_OK)==0) { - if (strcmp(path,".") == 0) { - chdir(progdir); + if (strcmp(path,".") == 0) { + chdir(progdir); } else { - chdir(path); + chdir(path); } - /* open the whatis database file */ - if (!o_flag) dbfile = WHATIS; - whatis_fp = fopen(dbfile,"w"); + /* open the whatis database file */ + if (!o_flag) dbfile = WHATIS; + whatis_fp = fopen(dbfile,"w"); if (whatis_fp == NULL) { - fprintf (error_fp, - "Could not create whatis database file %s in directory %s.\n\ + fprintf (error_fp, + "Could not create whatis database file %s in directory %s.\n\ Aborted.\n", - dbfile,path); - exit(-1); - } + dbfile,path); + exit(-1); + } - /* + /* * loop over the expected man* subdirectories within path */ - if (!C_flag) for (i=0; man_subdir[i] != NULL; i++) { - subdir = opendir(man_subdir[i]); - if (subdir != NULL) { + if (!C_flag) for (i=0; man_subdir[i] != NULL; i++) { + subdir = opendir(man_subdir[i]); + if (subdir != NULL) { - /* print status */ - if (v_flag>=2) fprintf(output_fp, - "Now working on directory %s\t%s ...\n",path,man_subdir[i]); + /* print status */ + if (v_flag>=3) fprintf(output_fp, + "Now working on directory %s\t%s ...\n",path,man_subdir[i]); /* no need to error check because of opendir() */ - chdir(man_subdir[i]); + chdir(man_subdir[i]); - /* loop over files within subdirectory */ - while ((file = readdir(subdir)) != NULL) { - process (file->d_name,tmp_file,whatis_fp); - } - closedir(subdir); - } else { - if (v_flag>=2) fprintf(output_fp, - "Could not access files in %s\t%s ...\n",path,man_subdir[i]); - } - chdir(path); - } + /* loop over files within subdirectory */ + while ((file = readdir(subdir)) != NULL) { + process (file->d_name,tmp_file,whatis_fp,&man_subdir[i][3]); + } + closedir(subdir); + } else { + if (v_flag>=3) fprintf(output_fp, + "Could not access files in %s\t%s ...\n",path,man_subdir[i]); + } + chdir(path); + } - /* + /* * loop over the expected cat* subdirectories within path, * adding only those files without man* versions. */ - if (c_flag||C_flag) for (i=0; cat_subdir[i] != NULL; i++) { - subdir = opendir(cat_subdir[i]); - if (subdir != NULL) { + if (c_flag||C_flag) for (i=0; cat_subdir[i] != NULL; i++) { + subdir = opendir(cat_subdir[i]); + if (subdir != NULL) { - /* print status */ - if (v_flag>=2) fprintf(output_fp, - "Now working on directory %s\t%s ...\n",path,cat_subdir[i]); + /* print status */ + if (v_flag>=3) fprintf(output_fp, + "Now working on directory %s\t%s ...\n",path,cat_subdir[i]); /* no need to error check because of opendir() */ - chdir(cat_subdir[i]); + chdir(cat_subdir[i]); - /* make filebuffer contain path to matching man* subdirectory */ + /* make filebuffer contain path to matching man* subdirectory */ strcpy(filebuffer,path); strcat(filebuffer,dirsep); strcat(filebuffer,man_subdir[i]); strcat(filebuffer,dirsep); p = filebuffer + strlen(filebuffer); /* p points to '\0' */ - /* loop over files that don't have a man* counterpart */ - while ((file = readdir(subdir)) != NULL) { - strcpy(p,file->d_name); + /* loop over files that don't have a man* counterpart */ + while ((file = readdir(subdir)) != NULL) { + strcpy(p,file->d_name); if (access(filebuffer,F_OK)!=0) - process (file->d_name,tmp_file,whatis_fp); - } - closedir(subdir); - } else { - if (v_flag>=2) fprintf(output_fp, - "Could not access files in %s\t%s ...\n",path,cat_subdir[i]); - } - chdir(path); - } + process (file->d_name,tmp_file,whatis_fp, + &man_subdir[i][3]); + } + closedir(subdir); + } else { + if (v_flag>=3) fprintf(output_fp, + "Could not access files in %s\t%s ...\n",path,cat_subdir[i]); + } + chdir(path); + } - /* close the database */ - fclose(whatis_fp); + /* close the database */ + fclose(whatis_fp); } - /* get the next path in manpath */ - path = strtok (NULL," "); + /* get the next path in manpath */ + path = strtok (NULL," "); } /* clean up and exit */ - unlink(tmp_file); + unlink(tmp_file); if (output_fp != stdout) fclose(output_fp); if (error_fp != stderr) fclose(error_fp); -#ifdef DEBUG - fprintf(stderr,"Makewhatis stack usage: %d bytes\n",end_stack_check()); +#ifdef STACK_CHECK + fprintf(stderr,"Makewhatis stack usage: %d bytes\n",end_stack_check()); #endif return 0; diff --git a/usr.bin/man/makewhatis.h b/usr.bin/man/makewhatis.h index e44c7e5..9bf75b1 100644 --- a/usr.bin/man/makewhatis.h +++ b/usr.bin/man/makewhatis.h @@ -1,18 +1,27 @@ -#define VERSIONSTRING "1.1, 29 May 1994" +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +#define VERSIONSTRING "1.2" +#define ISGRAPH_FIX 1 /* The size of the IO buffers */ -#define BUFFERSIZE 1024 +#define BUFFERSIZE 1024 /* The default name for the whatis database */ -#define WHATIS "whatis" +#define WHATIS "whatis" /* The number of characters per tab in the whatis database */ -#define TABLENGTH 8 +#define TABLENGTH 8 -extern int chdir (const char *); -extern int system (const char *); +#define DEFAULT_MANPATH "/usr/man" -void fillbuffer (char *filename); -void process (char *filename, char *tmp_file, FILE *whatis_fp); +extern int chdir (const char *); +extern int system (const char *); + +void fillbuffer (char *filename); +void process (char *filename, char *tmp_file, FILE *whatis_fp, char *sec); extern short v_flag; diff --git a/usr.bin/man/man.1 b/usr.bin/man/man.1 new file mode 100644 index 0000000..317f2bf --- /dev/null +++ b/usr.bin/man/man.1 @@ -0,0 +1,519 @@ +.\" This man page copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" While this manual page is based on one from UCB, the included +.\" C source, makefile, and executables are copyright (c) 1995 +.\" by Devin Reade . All rights reserved. +.\" +.TH MAN 1 "Commands and Applications" "24 July 95" "Version 3.0" +.SH NAME +man \- display reference manual pages; find reference pages by keyword +.SH SYNOPSIS +.B man +.RB "[\|" \- "\|]" +.RB "[\|" \-t "\|]" +.RB "[\|" \-M +.IR path "\|]" +.RB "[\|" \-T +.IR macro-package "\|]" +.RI "[\|" section "\|] " title " +.br +.B man +.RB "[\|" \-M +.IR path "\|]" +.B \-k +.I keyword +\&.\|.\|. +.br +.B man +.RB "[\|" \-M +.IR path "\|]" +.B \-f +.I filename +\&.\|.\|. +.SH DESCRIPTION +.B man +displays information from the reference manuals. +It can display complete manual pages that you select by +.IR title , +or one-line summaries selected either by +.I keyword +.RB ( \-k ), +or by the name of an associated file +.RB ( \-f ). +.LP +A +.IR section , +when given, applies to the +.I title +that follows it on the command line. +.B man +looks in the indicated section of the manual for that +.IR title . +.I section +is either a digit (perhaps followed by a single letter indicating +the type of manual page), or one of the words +.BR new , +.BR local , +.BR old , +or +.BR public . +The +abbreviations +.BR n , +.BR l , +.B o +and +.B p +are also allowed. +If +.I section +is omitted, +.B man +searches all reference sections +(giving preference to commands over functions). +If more than one manual page exists for the specified +.IR title , +each page is displayed in the order in which it is found. The +user is given the option of exiting after each page is displayed. +If no manual page is located, +.B man +prints an error message. +.LP +The reference page sources are typically located in the +.BR /usr/man/man? +directories. +If there are preformatted, up-to-date versions in +corresponding +.B cat? +or +.B fmt? +directories, +.B man +simply displays or prints those versions. +If the preformatted +version of interest is out of date or missing, +.B man +reformats it prior to display. +If directories for the +preformatted versions are not provided, +.B man +reformats a page whenever it is requested. +.LP +If the standard output is not a terminal, or if the +.RB ` \- ' +flag is given, +.B man +pipes its output through +.BR cat (1V). +Otherwise, +.B man +pipes its output through +.BR more (1) +to handle paging and underlining on the screen. +.SH OPTIONS +.IP \fB\-t\fP +.B man +arranges for the specified manual pages to be +.BR troff ed +to a suitable raster output device (see +.BR troff (1) +or +.BR vtroff (1)). +If both the +.B \- +and +.B \-t +flags are given, +.B man +updates the +.BR troff ed +versions of each named +.I title +(if necessary), but does not display them. +.IP "\fB\-M\fP \fIpath\fP" +Change the search path for manual pages. +.I path +is a colon- or space-separated list of directories that contain manual page +directory subtrees. +For example, +.B /usr/man/u_man:/usr/man/a_man +makes +.B man +search in the standard System V locations. +The space delimiter is provided for compatibility with GS/OS's +use of the colon as a pathname component delimiter. If the search +path contains no spaces nor +.B / +characters (such as +.BR :usr:local:man ), +it is assumed to be a single path, not a list of paths. +If spaces are used as delimiters, remember to quote +.I path +from the shell. +Each directory in the +.I path +is assumed to contain subdirectories of the form +.BR man[1-8l-p] . +.IP "\fB\-T\fP \fImacro-package\fP" +.B man +uses +.I macro-package +rather than the standard +.B \-man +macros defined in +.B /usr/lib/tmac/tmac.an +for formatting manual pages. +.IP "\fB\-k\fP \fIkeyword .\|.\|.\fP" +.B man +prints out one-line summaries from the +.B whatis +database (table of contents) that contain any of the given +.IR keyword s. +The +.B whatis +database is created using the +.BR makewhatis (8) +command. +.IP "\fB\-f\fP \fIfilename .\|.\|.\fP" +.B man +attempts to locate manual pages related to any of the given +.IR filename s. +It strips the leading pathname components from each +.IR filename , +and then prints one-line summaries containing the resulting +basename or names. +This option also uses the +.B whatis +database. +.br +.ne 7 +.SH "MANUAL PAGES" +.LP +Manual pages are either +.BR nroff (1)/ troff (1) +source files prepared with the +.B \-man +macro package, or +.BR aroff (1) +source files prepared with +.B "Appleworks GS" +(tm) or a compatible word processor. +.SS "Referring to Other Manual Pages" +Other manual pages can be referenced in one of two ways, depending on +whether the target manual page is an +.BR aroff +or +.BR nroff +source file. +.LP +For +.BR aroff +source files, a "link" may be made by creating a file ending in +.BR ".l" +(that's a dot-ell). The file must contain a single line consisting +of the pathname of the target +.BR aroff +source file. +An intentional design limitation was made that disallows this form +of "link" in the +.BR manl +(that's man-ell) subdirectory. +.LP +For +.BR nroff +source files, a "link" may be made by creating a file containing +the +.BR nroff +source (\fB\.so\fP) command. This file should have the same suffix +as the target +.BR nroff +source file. +.B man +does not itself do any processing of the source command. +.LP +With both types of "links" the pathname may be either a full- or +partial-pathname. In the latter case, the pathname must be relative +to the root of the manual page directory subtree. +.LP +.B man +processes the indicated file in place of the current one. +The reference must be expressed as +a pathname relative to the root of +the manual page directory subtree. +.SS "Preprocessing Manual Pages" +If the first line is a string of the form: +.nf + + \fB'\|\e"\0 \fR\fIX\fR + +.fi +where +.I X +is separated from the +`\fB"\fP' +by a single +.SM SPACE +and consists of any combination of characters in the following list, +.B man +pipes its input to +.BR troff (1) +or +.BR nroff (1) +through the corresponding preprocessors. +.nf + + \fBe\fP \fBeqn\fP(1), or \fBneqn\fP for \fBnroff\fP + \fBr\fP \fBrefer\fP(1) + \fBt\fP \fBtbl\fP(1) + \fBv\fP \fBvgrind\fP(1) + +.fi +.LP +If +.B eqn +or +.B neqn +is invoked, +it will automatically read the file +.B /usr/pub/eqnchar +(see +.BR eqnchar (7)). +If +.BR nroff (1) +is invoked, +.BR col (1V) +is automatically used. +.SH "COMPRESSED MANUAL PAGES" +.B man +allows its manual pages to be compressed by either +.BR compress , +.BR freeze , +or +.BR gzip , +in which case the manual page must have the suffix +.BR .Z , +.BR .F , +or +.BR .gz , +respectively. Note that the test for these suffixes is case sensitive +and if the incorrect case is used then the compressed file will be passed +to +.B nroff +with unpredictable results. +.LP +Compression may be used on files in either (or both) of the +.BR man? " and " cat? +subdirectories. Do not compress +.BR aroff (1) +source files since compressed files in the +.BR man? +subdirectory are always assumed to be +.BR nroff (1) +source. +.SH ENVIRONMENT +.IP \fBMANPATH\fP +If set, +its value overrides +.B /usr/man +as the default search path. +(The +.B \-M +flag, in turn, overrides this value.) +See the description of the +.B \-M +flag for syntax details. +.IP \fBUSRMAN\fP +If +.B MANPATH +is not set, then the value of +.B USRMAN +(if set) overrides +.B /usr/man +as the default search path. +(The +.B \-M +flag, in turn, overrides this value.) +See the description of the +.B \-M +flag for syntax details. +.IP \fBMANDIR\fP +If neither +.B MANPATH +nor +.B USRMAN +is set, then the value of +.B MANDIR +(if set) overrides +.B /usr/man +as the default search path. +(The +.B \-M +flag, in turn, overrides this value.) +See the description of the +.B \-M +flag for syntax details. +.IP \fBPAGER\fP +A program to use for interactively delivering +.BR man 's +output to the screen. +If not set, +.RB ` "/bin/more" ' +(see +.BR more (1)) +is used. +.IP \fBTCAT\fP +The name of the program to use to display +.BR troff ed +manual pages. +If not set, +.RB ` "lpr \-t" ' +(see +.BR lpr (1)) +is used. +.IP \fBTROFF\fP +The name of the formatter to use when the +.B \-t +flag is given. +If not set, +.RB ` "troff \-t" ' +is used. +.SH FILES +.B /usr/[share]/man +.RS +root of the standard manual page directory subtree +.RE +.sp +.B /usr/[share]/man/man?/* +.RS +unformatted manual entries +.RE +.sp +.B /usr/[share]/man/cat?/* +.RS +.BR nroff ed +manual entries +.RE +.sp +.B /usr/[share]/man/fmt?/* +.RS +.BR troff ed +manual entries +.RE +.sp +.B /usr/[share]/man/whatis +.RS +table of contents and keyword database +.RE +.sp +.B /usr/[share]/lib/tmac/tmac.an +.RS +standard +.B \-man +macro package +.RE +.sp +.B /usr/pub/eqnchar +.SH "SEE ALSO" +.BR apropos (1), +.BR aroff (1), +.BR cat (1V), +.BR col (1V), +.BR compress (1), +.BR eqn (1), +.BR freeze (1), +.BR gzip (1), +.BR less (1), +.BR lpr (1), +.BR more (1), +.BR nroff (1), +.BR refer (1), +.BR tbl (1), +.BR troff (1), +.BR vgrind (1), +.BR vtroff (1), +.BR whatis (1), +.BR whereis (1), +.BR eqnchar (7), +.BR man (7), +.BR catman (8) +.br +.ne 5 +.SH NOTES +.LP +Because +.B troff +is not 8-bit clean, +.B man +has not been made 8-bit clean. +.LP +The +.B \-f +and +.B \-k +options use the +.B whatis +database, which is created by +.BR makewhatis (8). +.br +.ne 4 +.LP +Although this version of +.B man +allows +.BR USRMAN " and " MANDIR +to be each a colon- or space-separated list of pathnames, other versions +of +.B man +treat the values of these environment variables as a single pathname. +For compatibility reasons, the use of these two environment variables +is discouraged; use +.B MANPATH +instead. +.SH BUGS +.LP +The manual is supposed to be reproducible +either on a phototypesetter or on an +.SM ASCII +terminal. +However, +on a terminal some information +(indicated by font changes, for instance) +is necessarily lost. +.LP +Some dumb terminals cannot process the vertical motions produced +by the +.B e +.RB ( eqn (1)) +preprocessing flag. +To prevent garbled output on these terminals, +when you use +.B e +also use +.BR t , +to invoke +.BR col (1V) +implicitly. +This workaround has the disadvantage of eliminating superscripts and +subscripts \(em even on those terminals that can display them. +.SM CTRL-Q +will clear a terminal that gets confused by +.BR eqn (1) +output. +.LP +The code which calls the +.BR eqn (1), +.BR refer (1), +.BR tbl (1), +and +.BR vgrind (1) +preprocessors is not yet implemented. Since these preprocessors do +not as yet exist for GNO, this is not too much of a problem. +.LP +Please report any other bugs to Devin Reade, . +.SH HISTORY +The GNO version of +.BR man +first appeared in GNO version 1.0 and was written by Mike Horwath. +This version was rewritten from scratch by Devin Reade. diff --git a/usr.bin/man/man.c b/usr.bin/man/man.c new file mode 100644 index 0000000..9bce7bc --- /dev/null +++ b/usr.bin/man/man.c @@ -0,0 +1,154 @@ +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +segment "man_______"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" +#include "man.h" + +#ifdef DEBUG + extern void begin_stack_check(void); + extern int end_stack_check(void); +#endif + +char *macroPackage = "an"; /* default /usr/lib/tmac/tmac.an */ +char *versionStr = "Version 3.0 by Devin Reade"; +char *pager; +char *troff; +char *tcat; + +static char *nothing = "nothing appropriate"; + +short f_flag, k_flag, M_flag, n_flag, t_flag, T_flag, V_flag; +short hyphen_flag, err_flag; + +static void usage(char *progname) { + if (err_flag || V_flag) fprintf(stderr,"%s %s\n",progname,versionStr); + if (err_flag) { + fprintf(stderr,"Usage:\n\ +\t%s [-] [-nt] [-M path] [-T macro-package] [section] title ...\n\ +\t%s [-n] [-M path] -f filename ...\n\ +\t%s [-n] [-M path] -k keyword ...\n\n",progname,progname,progname); + exit(1); + } + return; +} + +int main (int argc, char **argv) { + int i, result; + char *p; + + extern int optind; + extern char *optarg; + + /* make sure Gno is running */ + if (needsgno()==0) { + fprintf(stderr,"Requires Gno/ME\n"); + return 1; + } + +#ifdef STACK_CHECK + begin_stack_check(); +#endif + + /* + * initialization + */ + + f_flag = k_flag = M_flag = t_flag = T_flag = V_flag = 0; + n_flag = hyphen_flag = err_flag = 0; + + /* + * parse the command line + */ + + while((i = getopt(argc,argv,"fkM:ntT:V-")) != EOF) { + switch(i) { + case 'f': + f_flag++; + if (k_flag || t_flag || T_flag || hyphen_flag) err_flag++; + break; + case 'k': + k_flag++; + if (f_flag || t_flag || T_flag || hyphen_flag) err_flag++; + break; + case 'M': + M_flag++; + manpath = Xstrdup(optarg,__LINE__,__FILE__); + break; + case 'n': + n_flag++; + break; + case 't': + t_flag++; + if (k_flag || f_flag) err_flag++; + break; + case 'T': + T_flag++; + macroPackage = optarg; + if (k_flag || f_flag) err_flag++; + break; + case 'V': + V_flag++; + break; + default: + err_flag++; + } + } + /* take care of the '-' option, since getopt isn't smart enough */ + for (i=optind; i 3))) { + err_flag++; + } + + usage(argv[0]); + + /* if not already done, set the manpath */ + if (!M_flag) manpath = getManpath(); + + i = 0; + if (k_flag || f_flag) { + result = apropos(argc-optind, &argv[optind], + ((k_flag) ? MAN_K_MODE : MAN_F_MODE)); + if (!n_flag) { + i = apropos(argc-optind, &argv[optind], + ((k_flag) ? ORCA_K_MODE : ORCA_F_MODE)); + } + if (result<=0 && i<=0) { + fprintf(stderr,"%s: %s\n",basename(argv[0]),nothing); + } + } else { + if (!isatty(STDOUT_FILENO)) hyphen_flag++; + result = man(argc-optind, &argv[optind]); + } + free(manpath); + result = ((result == 0) && (i == 0)) ? 0 : 1; + +#ifdef STACK_CHECK + fprintf(stderr,"stack usage: %d bytes\n",end_stack_check()); +#endif + + return result; +} diff --git a/usr.bin/man/man.h b/usr.bin/man/man.h new file mode 100644 index 0000000..251f90a --- /dev/null +++ b/usr.bin/man/man.h @@ -0,0 +1,95 @@ +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +/* + * Configuration info + */ + +#define WHATIS "whatis" +#define PAGER "/bin/more" +#define SYSCMND "15/syscmnd" + +#define AROFF "aroff" +#define NROFF "nroff" +#define TROFF "troff -t" +#define TCAT "lpr -t" +#define CAT "cat" +#define EQN "eqn" +#define REFER "refer" +#define TBL "tbl" +#define VGRIND "vgrind" + +#define NON 0x00 +#define TXT 0x04 +#define BIN 0x06 +#define SRC 0xB0 + +#define MAN_F_MODE 1 +#define MAN_K_MODE 2 +#define WHATIS_MODE 3 +#define ORCA_F_MODE 4 +#define ORCA_K_MODE 5 +#define ORCA_W_MODE 6 + +#define BUFFERSIZE 2048 + +typedef struct Section_tag { + char *name; /* section name */ + char *suffix; /* directory suffix */ +} Section; + +typedef struct { + char *suffix; + char *extractor; +} compressionType; + +/* + * from globals.c + */ + +extern compressionType compressArray[]; +extern char linebuf[BUFFERSIZE]; +extern char linebuf2[BUFFERSIZE]; + +/* + * from man.c + */ + +extern Section sections[]; + +extern char *manpath; +extern char *pager; +extern char *tcat; +extern char *troff; +extern char *macroPackage; + +extern short hyphen_flag; +extern short n_flag; +extern short t_flag; + +/* + * from apropos2.c + */ + +int apropos(int argc, char **argv, int whole_line); + +/* + * from whatis2.c + */ + +int whatis(int argc, char **argv); + +/* + * from man2.c + */ +int man (int argc, char *argv[]); + + +/* + * from common.c + */ + +int getSuffixIndex(char *name); diff --git a/usr.bin/man/man2.c b/usr.bin/man/man2.c new file mode 100644 index 0000000..6e08cda --- /dev/null +++ b/usr.bin/man/man2.c @@ -0,0 +1,611 @@ +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +segment "man2______"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" +#include "man.h" + +#define MAX(a,b) ((a) > (b)) ? (a) : (b) + +static char **buildManList(char *suffix, char *name); +static void display(char *list); +static char *getBaseName (char *out, char *in); +static void cleanManList(char **list); + +/* + * Pre: argc is the number of strings in argv. It should either be 1 or 2. + * If DEBUG is defined, then any other value of argc will result in + * a failed assert. + * + * argv is an array of strings. If argc==1, then argv[0] is presumed + * to be the name of the man page. If argc==2, then argv[0] is + * presumed to be a section number and argv[1] is the name of the + * man page. + * + * globals: + * manpath must be a malloc'd string. Either ':' or ' ' may + * may be used as a directory delimiter. + * macroPackage must be set to a static string. + * t_flag must be in a defined state (either set or unset) + * hyphen_flag must be in a defined state (either set or unset) + * + * Post: print the man page in whatever form it takes, acting as necessary + * on the -, -M, and -T flags and section number. + */ + +int man(int argc, char *argv[]) { + char **manpath_array, **manpagelist; + char *sec, *name, *current_path; + Section *section; + int i, j, k, abort; + short section_found, page_found; + char dirbrk; /* path component separator. either ':' or '/' */ + char c, *p; + struct sgttyb termMode; + short oldMode; + + /* initialization */ + abort = 0; + section_found = 0; + page_found = 0; + if (t_flag) { + if ((tcat = getenv("TCAT")) == NULL) { + tcat = TCAT; + } else tcat = Xstrdup(tcat,__LINE__,__FILE__); + if ((troff = getenv("TROFF")) == NULL) { + troff = TROFF; + } else troff = Xstrdup(troff,__LINE__,__FILE__); + } + if (hyphen_flag) { + pager = CAT; + } else if ((pager = getenv("PAGER")) == NULL) { + pager = PAGER; + } + + /* determine name and, if appropriate, sec */ + switch (argc) { + case 1: + sec = NULL; + name = argv[0]; + break; + case 2: + sec = argv[0]; + /* special case some section abbreviations */ + if (!strcmp(sec,"l")) { + sec = "local"; + } else if (!strcmp(sec,"n")) { + sec = "new"; + } else if (!strcmp(sec,"o")) { + sec = "old"; + } else if (!strcmp(sec,"p")) { + sec = "public"; + } + name = argv[1]; + break; + default: + fprintf(stderr,"internal error at line %d in file %s\n",__LINE__, + __FILE__); + exit(1); + } + + /* create array of paths to search */ + if ((manpath_array = makePathArray(manpath)) == NULL) return 1; + + /* + * loop over all the paths in MANPATH + */ + i=0; + current_path = manpath_array[i]; + while (!abort && current_path) { + + dirbrk = (strchr(current_path,':')!=NULL) ? ':' : '/'; + + /* go to the current path in MANPATH */ + if (chdir(current_path) == -1) { + i++; + current_path = manpath_array[i]; + continue; + } + + /* loop over sections */ + for (j=0; !abort && sections[j].name != NULL; j++) { + + /* + * if section number was specified and this isn't it, do + * the next loop + */ + if (sec && (strcmp(sec,sections[j].name) || + (!isdigit(*sec) && + strncmp(sec,sections[j].name,strlen(sec))))) continue; + section_found++; + + /* + * we're going to check this section. Get the pathnames + * (relative to this directory) of the two files. + */ + + manpagelist = buildManList(sections[j].suffix,name); + if (!manpagelist) continue; + page_found++; + + for (k=0; !abort && manpagelist[k]; k++) { + display(manpagelist[k]); + if (!hyphen_flag && !t_flag) { + fprintf(stderr, + "type q to quit, or any other key for next man page: "); + c = getcharraw(); + if (c == '\0') { + fprintf(stderr,"getcharraw failed line %d of %s: %s\n", + __LINE__,__FILE__,strerror(errno)); + exit(1); + } + fputc('\n',stderr); + /* evaluate result */ + if ((c == 'q') || (c == 'Q')) abort++; + } + } + + cleanManList(manpagelist); + + } /* done looping over sections */ + i++; + current_path = manpath_array[i]; + + } /* done looping over paths */ + + i = 0; /* used here for the return code */ + if (sec) { + if (!section_found) { + fprintf(stderr,"there is no section %s in the manual\n",sec); + i++; + } else if (!page_found) { + fprintf(stderr,"there is no %s in section %s\n",name,sec); + i++; + } + } else if (!page_found) { + fprintf(stderr,"there is no %s in the manual\n",name); + i++; + } + return i; +} + + +#define DIRBUF_LEN 10 +static const char *manstr="man"; +static const char *catstr="cat"; + +static char **buildManList(char *suffix, char *name) { + static char buffer1[FILENAME_MAX]; + static char buffer2[FILENAME_MAX]; + DIR *directory; + struct dirent *entry; + char **list1, **list2, **list3; + size_t len; + int total1, total2, i, j, k; + char *p, *fn; + + /* initialization */ + list1 = list2 = list3 = NULL; + total1 = total2 = 0; + +#ifdef DEBUG + /* sanity check on arguments */ + if(MAX(strlen(manstr),strlen(catstr)) + strlen(suffix) >= FILENAME_MAX) { + fprintf(stderr,"internal error: buffer overflow at line %d of %s\n", + __LINE__,__FILE__); + } +#endif + + /* + * look in man subdirectory + */ + strcpy(buffer1,manstr); + strcat(buffer1,suffix); + if ((directory = opendir(buffer1)) != NULL) { + while ((entry = readdir(directory)) != (struct dirent *) NULL) { + + /* skip if no match */ + len = strlen(name); + if (strncmp(entry->d_name,name,len) || + (entry->d_name[len] != '.')) continue; + + if (strlen(manstr) + strlen(suffix) + strlen(entry->d_name) + + strlen(suffix) + 1 >= FILENAME_MAX) { + fprintf(stderr,"internal error: buffer overflow at line %d of %s\n", + __LINE__,__FILE__); + } + sprintf(buffer1,"%s%s:%s",manstr,suffix,entry->d_name); + + /* look for "links" to aroff files. (what a kludge) */ + if ((buffer1[3] != 'l') && + (strcmp(".l",&buffer1[strlen(buffer1)-2])==0)) { + FILE *linkptr; + char *tp; + + /* dereference the "link" */ + if ((linkptr = fopen(buffer1,"r")) == NULL) { + fprintf(stderr,"couldn't open %s\n",buffer1); + } else if (fgets(buffer2,FILENAME_MAX,linkptr)==NULL) { + fprintf(stderr,"couldn't read %s\n",buffer1); + } else { + + /* drop trailing space and newline */ + tp = buffer2 + strlen(buffer2) -1; + while ((tp>=buffer2) && (isspace(*tp) || *tp == '\n')) { + *tp = '\0'; + tp--; + } + fclose(linkptr); + + if (access(buffer2,R_OK) == 0) { + list1 = addToStringArray(list1, buffer2); + total1++; + } + } + } else { + /* not a .l "link"; a normal file */ + list1 = addToStringArray(list1, buffer1); + total1++; + } + } + closedir(directory); + } + + if (!t_flag) { + /* + * look in cat subdirectory + */ + strcpy(buffer1,catstr); + strcat(buffer1,suffix); + if ((directory = opendir(buffer1)) != NULL) { + while ((entry = readdir(directory)) != (struct dirent *) NULL) { + + /* skip if no match */ + len = strlen(name); + if (strncmp(entry->d_name,name,len) || + (entry->d_name[len] != '.')) continue; + + if (strlen(catstr) + strlen(suffix) + strlen(entry->d_name) + + strlen(suffix) + 1 >= FILENAME_MAX) { + fprintf(stderr,"internal error: buffer overflow at line %d of %s\n", + __LINE__,__FILE__); + } + sprintf(buffer1,"%s%s:%s",catstr,suffix,entry->d_name); + list2 = addToStringArray(list2, buffer1); + total2++; + } + closedir(directory); + } + } + + /* + * eliminate files common to both lists + */ + len = strlen(suffix); + for(i=0; i= 0) { + compressor = compressArray[icompress].extractor; + if (isubdir == MANSUBDIR) { + + /* + * compressed nroff source + */ + + if (t_flag && hyphen_flag) { + if (strlen(compressor) + 2*strlen(file) + strlen(troff) + + strlen(macroPackage) + strlen(tcat) + 12 > BUFFERSIZE) { + fprintf(stderr,"%s\n",OVERFLOW); + exit(1); + } + sprintf(linebuf,"%s %s | %s -m%s - > fmt%s", + compressor, file, troff, macroPackage, &file[3]); + } else if (t_flag) { + if (strlen(compressor) + strlen(file) + strlen(troff) + + strlen(macroPackage) + strlen(tcat) + 12 > BUFFERSIZE) { + fprintf(stderr,"%s\n",OVERFLOW); + exit(1); + } + sprintf(linebuf,"%s %s | %s -m%s - | %s", + compressor, file, troff, macroPackage, tcat); + } else { + /* not troff, jes' plain old nroff */ + if (strlen(compressor) + strlen(file) + strlen(NROFF) + + strlen(macroPackage) + strlen(pager) + 12 > BUFFERSIZE) { + fprintf(stderr,"%s\n",OVERFLOW); + exit(1); + } + if (!hyphen_flag) printf("%s\n",DECFOR); + sprintf(linebuf,"%s %s | %s -m%s - | %s", + compressor, file, NROFF, macroPackage, pager); + } + } else { + + /* + * compressed straight text + */ + + if (strlen(compressor)+strlen(file)+strlen(pager)+5 > BUFFERSIZE) { + fprintf(stderr,"%s\n",OVERFLOW); + exit(1); + } + if (!hyphen_flag) printf("%s\n",DECOMP); + sprintf(linebuf,"%s %s | %s", compressor, file, pager); + } + } else { + if (isubdir == MANSUBDIR) { + + /* + * Can be either aroff or nroff source. If it's nroff source, + * it must either be a TXT, SRC, or BIN file + */ + + if (!hyphen_flag && !t_flag) printf("%s\n",FORMAT); + if ((ft = getFileType(file)) == NULL) { + perror(file); + exit(1); + } + if ((ft->type == 0x50) || (ft->auxtype == 0x8010)) { + + /* + * AppleworksGS Word Processor format; use 'aroff' + */ + + if (t_flag) { + fprintf(stderr,"cannot use troff on aroff source files\n"); + return; + } + if (strlen(AROFF)+strlen(file)+strlen(pager)+5 > BUFFERSIZE) { + fprintf(stderr,"%s\n",OVERFLOW); + exit(1); + } + sprintf(linebuf,"%s %s | %s", AROFF, file, pager); + + } else if ((ft->type == TXT) || (ft->type == BIN) || + (ft->type == SRC) || (ft->type == NON)) { + + /* + * TeXT, BINary, or SouRCe file; assume nroff source + */ + if (t_flag && hyphen_flag) { + if (strlen(troff) + strlen(macroPackage) + + 2 * strlen(file) + 7 >= BUFFERSIZE) { + fprintf(stderr,"%s\n",OVERFLOW); + exit(1); + } + sprintf(linebuf,"%s -m%s %s > fmt%s", + troff, macroPackage, file, &file[3]); + } else if (t_flag) { + if (strlen(troff) + strlen(macroPackage) + strlen(file) + + strlen(tcat) + 7 >= BUFFERSIZE) { + fprintf(stderr,"%s\n",OVERFLOW); + exit(1); + } + sprintf(linebuf,"%s -m%s %s | %s",troff,macroPackage,file,tcat); + } else { + /* not troff, jes' plain old nroff */ + if (strlen(NROFF) + strlen(macroPackage) + + strlen(file) + strlen(pager) + 8 >= BUFFERSIZE) { + fprintf(stderr,"%s\n",OVERFLOW); + exit(1); + } + sprintf(linebuf,"%s -m%s %s | %s",NROFF,macroPackage,file,pager); + } + + } else { + fprintf(stderr, + "bad file type for %s\n\ttype = %x\n\taux = %lx\n", + file,ft->type,ft->auxtype); + return; + } + } else { + /* assume straight text */ + if (strlen(CAT) + strlen(file) + strlen(pager) + 4 >= BUFFERSIZE){ + fprintf(stderr,"%s\n",OVERFLOW); + exit(1); + } + sprintf(linebuf,"%s %s | %s", CAT, file, pager); + } + } + +#if 0 + fprintf(stderr,"DEBUG: BUFFER: %s\n",linebuf); +#endif + system(linebuf); + return; +} + + +/* + * getBaseName -- copy the filename pointed to by into the buffer + * pointed to by , dropping any compression suffix + * that may be on the base name. The set of compression + * suffixes is defined by the NULL-terminated compressArray[]. + * + * It is the user's responsibility to ensure that the + * buffer *out has been allocated with sufficient space + * for the result. + * + * Returns a pointer to . + */ + +static char *getBaseName (char *out, char *in) { + char *p; + int i; + + strcpy(out,in); + if ((p = strrchr(out,'.')) != NULL) { + for (i=0; compressArray[i].suffix; i++) { + if (strcmp(p,compressArray[i].suffix)==0) { + *p = '\0'; + break; + } + } + } + return out; +} diff --git a/usr.bin/man/process.c b/usr.bin/man/process.c index 151e9e6..b94d6ea 100644 --- a/usr.bin/man/process.c +++ b/usr.bin/man/process.c @@ -1,6 +1,10 @@ -#ifdef __CCFRONT__ -#include <14:pragma.h> -#endif +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +segment "makewhatis"; #include #include @@ -16,51 +20,55 @@ #define NO_COMPRESS 0 #define Z_COMPRESS 1 #define F_COMPRESS 2 +#define G_COMPRESS 3 #ifdef TEST_PROCESS - short v_flag = 1; - FILE *output_fp; - FILE *error_fp; + short v_flag = 1; + FILE *output_fp; + FILE *error_fp; #else - extern FILE *output_fp; - extern FILE *error_fp; + extern FILE *output_fp; + extern FILE *error_fp; #endif -extern GSString255Ptr __C2GSMALLOC (char *s); +extern GSString255Ptr __C2GSMALLOC (char *s); extern char buffer[]; extern char titlebuf[]; /* * void process (char *filename, char *tmp_file, FILE *whatis_fp); * - * Pre: is the name of the file to add to the database. - * is the name for the temporary file. It has not been opened. - * is a file pointer to the open whatis database file. + * Pre: is the name of the file to add to the database. + * is the name for the temporary file. It has not been opened. + * is a file pointer to the open whatis database file. + * (sec> is the section "number". We really only care if it is + * either "l" or "local" (because of aroff "links"), otherwise + * it is ignored. * * Post: The name, section number, and description from the man page is - * appended to . + * appended to . */ -void process (char *filename, char *tmp_file, FILE *whatis_fp) { +void process (char *filename, char *tmp_file, FILE *whatis_fp, char *sec) { - FileInfoRecGS info_record; /* used to get the file type */ + FileInfoRecGS info_record; /* used to get the file type */ char *suffix; /* points to the start of the file suffix */ - static char command_buf[255]; /* used to call system(2) */ - char *p1; /* a scratch pointer */ - int namelength; /* length of 'name (section)' */ - char *name; /* points to the file basename */ - short compression; /* the compression type (if nec) */ + static char command_buf[255]; /* used to call system(2) */ + char *p1; /* a scratch pointer */ + int namelength; /* length of 'name (section)' */ + char *name; /* points to the file basename */ + short compression; /* the compression type (if nec) */ - if (v_flag>=2) fprintf(output_fp,"Working on file %s ...\n",filename); + if (v_flag>=2) fprintf(output_fp,"Working on file %s/%s ...\n",sec,filename); - /* + /* * get the file basename */ if ((name = malloc (strlen(filename)+1)) == NULL) { - if (v_flag) - fprintf(error_fp,"malloc failed when processing %s -- file skipped\n", - filename); + if (v_flag) + fprintf(error_fp,"malloc failed when processing %s -- file skipped\n", + filename); return; } strcpy(name,filename); @@ -69,18 +77,20 @@ void process (char *filename, char *tmp_file, FILE *whatis_fp) { * check for a compression suffix like ".Z" or ".F" */ - p1 = name + strlen(name) -1; /* p1 points to last char of name */ - while ((p1>=name) && (*p1!='.')) --p1; + p1 = name + strlen(name) -1; /* p1 points to last char of name */ + while ((p1>=name) && (*p1!='.')) p1--; if (p1<=name) { /* <= because we don't want a name beginning with '.' */ - if (v_flag) - fprintf(error_fp,"%s has no suffix -- file skipped\n", - filename); + if (v_flag) + fprintf(error_fp,"%s has no suffix -- file skipped\n", + filename); return; } - if ((strcmp(p1,".Z")==0) || (strcmp(p1,".z")==0)) { - compression = Z_COMPRESS; - } else if ((strcmp(p1,".F")==0) || (strcmp(p1,".f")==0)) { - compression = F_COMPRESS; + if (strcmp(p1,".Z")==0) { + compression = Z_COMPRESS; + } else if (strcmp(p1,".F")==0) { + compression = F_COMPRESS; + } else if (strcmp(p1,".gz")==0) { + compression = G_COMPRESS; } else compression = NO_COMPRESS; *p1 = '\0'; @@ -89,15 +99,15 @@ void process (char *filename, char *tmp_file, FILE *whatis_fp) { */ if (compression == NO_COMPRESS) { - suffix = p1 + 1; + suffix = p1 + 1; } else { - while ((p1>=name) && (*p1!='.')) --p1; - if (p1<=name) { /* <= because we don't want a name beginning with '.' */ - if (v_flag) - fprintf(error_fp,"%s has deformed file name -- file skipped\n", - filename); - return; - } + while ((p1>=name) && (*p1!='.')) --p1; + if (p1<=name) { /* <= because we don't want a name beginning with '.' */ + if (v_flag) + fprintf(error_fp,"%s has deformed file name -- file skipped\n", + filename); + return; + } *p1 = '\0'; suffix = p1 + 1; } @@ -107,55 +117,68 @@ void process (char *filename, char *tmp_file, FILE *whatis_fp) { */ if (compression == NO_COMPRESS) { - info_record.pCount = 5; - info_record.pathname = __C2GSMALLOC(filename); - GetFileInfoGS(&info_record); - if (toolerror()) { - if (v_flag) - fprintf(error_fp, - "malloc failed when processing %s -- file skipped\n", filename); - return; - } + info_record.pCount = 5; + info_record.pathname = __C2GSMALLOC(filename); + GetFileInfoGS(&info_record); + if (toolerror()) { + if (v_flag) + fprintf(error_fp, + "malloc failed when processing %s -- file skipped\n", filename); + return; + } } - /* + /* * Process the file according to type: nroff, aroff, freeze, and compress. * The digested result is placed in buffer. */ if ((compression == NO_COMPRESS) && - (info_record.fileType == 0x50u) && + (info_record.fileType == 0x50u) && (info_record.auxType == 0x8010u) ) { - + /* is it an Appleworks GS word processor document? Use aroff */ - sprintf(command_buf,"aroff -b %s >%s",filename,tmp_file); + sprintf(command_buf,"aroff -b %s > %s",filename,tmp_file); + if (v_flag>=3) fprintf(stderr,"%s\n",command_buf); system(command_buf); - fillbuffer(tmp_file); + fillbuffer(tmp_file); } else if (compression == Z_COMPRESS) { - + /* Compressed man page; uncompress it */ - sprintf(command_buf,"compress -dc %s >%s",filename,tmp_file); - system(command_buf); - fillbuffer(tmp_file); + sprintf(command_buf,"compress -cd %s > %s",filename,tmp_file); + if (v_flag>=3) fprintf(stderr,"%s\n",command_buf); + system(command_buf); + fillbuffer(tmp_file); } else if (compression == F_COMPRESS) { - + /* Frozen man page; melt it */ - sprintf(command_buf,"freeze -dc %s >%s",filename,tmp_file); - system(command_buf); - fillbuffer(tmp_file); + sprintf(command_buf,"freeze -cd %s > %s",filename,tmp_file); + if (v_flag>=3) fprintf(stderr,"%s\n",command_buf); + system(command_buf); + fillbuffer(tmp_file); - } else if ((toupper(*suffix)=='L') && (*(suffix+1)=='\0')) { - - /* It's a link to another man page; do nothing. */ - return; + } else if (compression == G_COMPRESS) { + + /* gzipped man page; zcat it */ + sprintf(command_buf,"gzip -cd %s > %s",filename,tmp_file); + if (v_flag>=3) fprintf(stderr,"%s\n",command_buf); + system(command_buf); + fillbuffer(tmp_file); + + } else if ((*suffix=='l') && (*(suffix+1)=='\0') && + strcmp("l",sec) && strcmp("local",sec)) { + + /* It's a link to another man page; do nothing. */ + return; } else { - /* Assume that it's a text file */ - fillbuffer(filename); + /* Assume that it's a text file */ + if (v_flag>=3) fprintf(stderr,"assuming text file\n"); + fillbuffer(filename); } /* @@ -163,7 +186,9 @@ void process (char *filename, char *tmp_file, FILE *whatis_fp) { * page, then return without writing anything to the database */ - if ((buffer[0] == '\0') || (titlebuf[0] == '\0')) return; + if ((buffer[0] == '\0') || (titlebuf[0] == '\0')) { + return; + } /* * At this point, buffer contains the line that we need to print to @@ -171,37 +196,37 @@ void process (char *filename, char *tmp_file, FILE *whatis_fp) { * formatting. */ - p1 = buffer; + p1 = buffer; while (isspace(*p1)) p1++; - namelength = strlen(titlebuf) + strlen(suffix) + 4; + namelength = strlen(titlebuf) + strlen(suffix) + 4; - if (namelength > (TABLENGTH * 3)) { - fprintf(whatis_fp,"%s (%s) - %s\n", titlebuf, suffix, p1); + if (namelength > (TABLENGTH * 3)) { + fprintf(whatis_fp,"%s (%s) - %s\n", titlebuf, suffix, p1); } else if (namelength > (TABLENGTH * 2)) { - fprintf(whatis_fp,"%s (%s)\t- %s\n", titlebuf, suffix, p1); + fprintf(whatis_fp,"%s (%s)\t- %s\n", titlebuf, suffix, p1); } else if (namelength > TABLENGTH ) { fprintf(whatis_fp,"%s (%s)\t\t- %s\n", titlebuf, suffix, p1); } else { fprintf(whatis_fp,"%s (%s)\t\t\t- %s\n", titlebuf, suffix, p1); } - return; + return; } #ifdef TEST_PROCESS int main (int argc, char **argv) { - + output_fp = stdout; - error_fp = stderr; + error_fp = stderr; - if (argc != 2) { - fprintf(stderr,"Usage: %s \n",argv[0]); + if (argc != 2) { + fprintf(stderr,"Usage: %s \n",argv[0]); return -1; } - process (argv[1], ":tmp:garbage", stdout); + process (argv[1], ":tmp:garbage", stdout, "2"); return 0; } diff --git a/usr.bin/man/util.c b/usr.bin/man/util.c new file mode 100644 index 0000000..f455dcb --- /dev/null +++ b/usr.bin/man/util.c @@ -0,0 +1,386 @@ +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +segment "util______"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" + +/* + * getManpath -- return a malloc'd copy of the MANPATH. If MANPATH + * isn't defined in the environment, then use USRMAN, then + * MANDIR, then if all else fails, use the macro DEFAULT_MANPATH. + * If an error occurs, print the cause via perror and exit. + */ + +char *getManpath(void) { + char *manpath; + + manpath = getenv("MANPATH"); + if (manpath == NULL) manpath = getenv("USRMAN"); + if (manpath == NULL) manpath = getenv("MANDIR"); + if (manpath == NULL) manpath = DEFAULT_MANPATH; + + return Xstrdup(manpath,__LINE__,__FILE__); +} + +/* + * Xstrdup - a safe strdup; it will handle error conditions and exit + * one occurs + * + * line and file are arbitrary, but are expected to be the + * values of __LINE__ and __FILE__ respectively. + */ + +char *Xstrdup(char *oldstr, int line, char *file) { + char *newstr; + + if ((newstr = malloc(strlen(oldstr)+1)) == NULL) { + fprintf(stderr,"Xstrdup failed at line %d in file %s: %s\n",line, + file,strerror(errno)); + exit(1); + } + strcpy(newstr,oldstr); + return newstr; +} + +/* + * Xmalloc - a safe malloc; it will handle error conditions and exit + * if one occurs. + * + * line and file are arbitrary, but are expected to be the + * values of __LINE__ and __FILE__ respectively. + */ + +void *Xmalloc(size_t size, int line, char *file) { + char *p; + + if ((p = malloc(size)) == NULL) { + fprintf(stderr,"Xmalloc failed at line %d in file %s: %s\n",line, + file,strerror(errno)); + exit(1); + } + return ((void *) p); +} + + +/* + * Xrealloc - a safe realloc; it will handle error conditions and exit + * if one occurs. + * + * line and file are arbitrary, but are expected to be the + * values of __LINE__ and __FILE__ respectively. + */ + +void *Xrealloc(void *oldptr, size_t size, int line, char *file) { + char *p; + + if ((p = realloc(oldptr, size)) == NULL) { + fprintf(stderr,"Xrealloc failed at line %d in file %s: %s\n",line, + file,strerror(errno)); + exit(1); + } + return ((void *) p); +} + + +/* + * addToStringArray -- add a string to a NULL-terminated array of strings. + * If oldArray is NULL, then a new array is created, + * otherwise oldArray is expanded. + * + * WARNING: | Because of the allocation scheme used, any oldArray + * | passed to this routine _must_ be the return value + * | of a previous call to this routine. This does not + * | imply that only one array can be expanded by this + * | routine (any number may be expanded). + * + * The value of macro SLOTS_QUANTUM defined below is + * the number of array slots allocated at one time. The + * size of the string array is always a multiple of this + * value. + * + * Returns a pointer to an array that contains the old + * strings with the new one appended. The array is + * NULL-terminated. + */ + +#define SLOTS_QUANTUM 10 + +char **addToStringArray(char **oldArray, char *string) { + + char **result; + int slotsAlloced, slotsUsed; + + if (oldArray == NULL) { + + /* + * This is a new array; do the brute force approach + */ + + result = Xmalloc(SLOTS_QUANTUM * sizeof(char *), __LINE__, __FILE__); + result[0] = Xstrdup(string,__LINE__,__FILE__); + result[1] = NULL; + + } else { + + /* + * adding to and, if necessary, expanding an old array + */ + + /* determine slotsUsed and slotsAlloced */ + for (slotsUsed=0; oldArray[slotsUsed]; slotsUsed++); + + if (slotsUsed % SLOTS_QUANTUM == SLOTS_QUANTUM-1) { /* space for NULL */ + slotsAlloced = slotsUsed+1; + } else { + slotsAlloced = ((slotsUsed / SLOTS_QUANTUM) + 1) * SLOTS_QUANTUM; + } + +#ifdef DEBUG + assert(slotsUsed < slotsAlloced); +#endif + + /* expand number of slots if necessary */ + if (slotsUsed+1 < slotsAlloced) { + /* there are enough slots; add it to this array */ + result = oldArray; + } else { + /* we need more slots; expand the array */ + slotsAlloced += SLOTS_QUANTUM; + result = Xrealloc(oldArray, slotsAlloced * sizeof(char *), + __LINE__, __FILE__); + } + + /* add the string to the array */ + result[slotsUsed++] = Xstrdup(string, __LINE__, __FILE__); + result[slotsUsed] = NULL; + } + return result; +} + +/* + * makePathArray -- parse a path list and break it into a NULL-terminated + * array of paths. The original path is left unchanged. + * + * The delimiter between paths may either be a ' ' or a ':'. + * The delimiter is assumed to be a ':' if contains + * both '/' and ':' characters but no ' ' character, + * otherwise the delimiter is assumed to be a ' '. + */ + +char **makePathArray(char *path) { + + char *delim, *p, *q, **result; + + /* set the delimiter */ + if ( strchr(path,' ')==NULL && + strchr(path,':') && + strchr(path,'/')) { + delim = ":"; + } else { + delim = " "; + } + + /* build the array */ + p = Xstrdup(path, __LINE__, __FILE__); + q = strtok(p,delim); + result = NULL; + while (q) { + result = addToStringArray(result, q); + q = strtok(NULL,delim); + } + + free(p); + return result; +} + + +/* + * ncstrcmp -- A case insensitive ("no-case") strcmp + */ + +int ncstrcmp(char *a, char *b) { + + while (*a && *b) { + if (*a == *b) { + a++; b++; + continue; + } + return ((int) *b - *a); + } + if (!*a && !*b) return 0; + return ((int) *b - *a); +} + +/* + * ncstrncmp -- A case insensitive ("no-case") strncmp + */ + +int ncstrncmp (char *a, char *b, unsigned int count) { + unsigned int i=0; + + for (i=0; i 5, + * and using a straight-forward search for strlen(substr) <= 5. + */ + +char *ncstrstr(char *str, char *substr) { + + char *strCopy, *substrCopy, *p; + + strCopy = Xstrdup(str,__LINE__,__FILE__); + substrCopy = Xstrdup(substr,__LINE__,__FILE__); + + /* convert the strings */ + p = strCopy; + while (*p) { + *p = tolower(*p); + p++; + } + p = substrCopy; + while (*p) { + *p = tolower(*p); + p++; + } + + p = strstr(strCopy,substrCopy); + free(strCopy); + free(substrCopy); + return p; +} + +/* + * newerFile -- Compares the "last modified" time of two paths. + * Returns: + * the name of the newer file if both files exist + * the second file if both exist and have the same mod time + * the name of the existing file if one file doesn't exist + * NULL and sets errno if neither file exists or if there + * is an error. + */ + +char *newerFile(char *path1, char *path2) { + static struct stat record1, record2; + int i,j; + + /* + * see if both, only one, or neither files exist + */ + + i = access(path1, F_OK); + j = access(path2, F_OK); + if (i==-1 && j==-1) { + errno = ENOENT; + return NULL; + } else if (i==-1) { + return path2; + } else if (j==-1) { + return path1; + } + + /* + * both files exist; stat them + */ + + if (stat(path1,&record1) != 0) return NULL; + if (stat(path2,&record2) != 0) return NULL; + + return (record1.st_mtime > record2.st_mtime) ? path1 : path2; +} + + +/* + * getcharraw() - return the next character from stdin without waiting + * for a CR to be hit. Returns '\0' and sets errno + * on an error. + */ + +#define FAILED_CHAR '\0'; + +char getcharraw(void) { + short oldmode; + struct sgttyb s; + int count; + char c; + + /* obtain old terminal mode */ + if (gtty(STDIN_FILENO,&s) == -1) return FAILED_CHAR; + oldmode = s.sg_flags; + + /* set terminal to CBREAK and obtain keystroke */ + s.sg_flags |= CBREAK; + if (stty(STDIN_FILENO,&s) == -1) return FAILED_CHAR; + count = read (STDIN_FILENO, &c, 1); + + /* reset old terminal mode */ + s.sg_flags = oldmode; + if ((stty(STDIN_FILENO,&s) == -1) || (count == -1)) return FAILED_CHAR; + return c; +} + +/* + * basename -- return a pointer to the base filename (all leading + * pathname components removed) of . _must_ + * point to a NULL-terminated string. + */ + +char *basename (char *path) { + char *p, dirsep; + + dirsep = (strchr(path,':')) ? ':' : '/'; + if ((p = strrchr(path,dirsep)) != NULL) { + return p+1; + } else { + return path; + } +} + +/* + * dirname -- return a pointer to a string consisting of the directory + * component of . This returns a pointer to an internal + * buffer, so the next call to dirname() will overwrite this + * buffer. must be a NULL-terminated string. + */ + +char *dirname (const char *path) { + static char buffer[FILENAME_MAX]; + char *p, dirsep; + + strcpy(buffer,path); + + dirsep = (strchr(buffer,':')) ? ':' : '/'; + if ((p = strrchr(buffer,dirsep)) != NULL) { + *p = '\0'; + } + return buffer; +} + diff --git a/usr.bin/man/util.h b/usr.bin/man/util.h new file mode 100644 index 0000000..0efb0b8 --- /dev/null +++ b/usr.bin/man/util.h @@ -0,0 +1,37 @@ +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +/* + * from util.c + */ + +#define DEFAULT_MANPATH "/usr/man" + +char *getManpath(void); +char *Xstrdup(char *oldstr, int line, char *file); +void *Xmalloc(size_t size, int line, char *file); +void *Xrealloc(void *oldptr, size_t size, int line, char *file); +char **addToStringArray(char **oldArray, char *string); +char **makePathArray(char *path); +int ncstrcmp(char *a, char *b); +int ncstrncmp (char *a, char *b, unsigned int count); +char *ncstrstr(char *str, char *substr); +char *newerFile(char *path1, char *path2); +char getcharraw(void); +char *basename (char *path); +char *dirname (const char *path); + + +/* + * from utilgs.c + */ + +typedef struct { + unsigned int type; + unsigned long int auxtype; +} fileType, fileTypePtr; + +fileType *getFileType (char *file); diff --git a/usr.bin/man/utilgs.c b/usr.bin/man/utilgs.c new file mode 100644 index 0000000..8d6a069 --- /dev/null +++ b/usr.bin/man/utilgs.c @@ -0,0 +1,179 @@ +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +segment "utilgs____"; + +#include +#include +#include +#include +#include +#include +#include "util.h" + +extern GSString255Ptr __C2GSMALLOC(char *); +extern int _mapErr(int); + +/* + * access -- a replacement for the standard Gno one; this one will actually + * return 0 when testing X_OK on a directory. + * + * This one still has a bug in it: If the file is a shell command or sys + * file, then X_OK will return zero, but not if it is a shell script (as + * with 'chtyp -lexec filename'). + */ + +int access(char *name, int mode) { + struct stat statbuf; + int realmode=0; + + if (stat(name,&statbuf) == -1) return -1; + + /* check read permission */ + if ((mode & R_OK) && !(statbuf.st_mode & S_IREAD)) return -1; + + /* check write permission */ + if ((mode & W_OK) && !(statbuf.st_mode & S_IWRITE)) return -1; + + /* + * Check execute mode. Assume directories have execute permission + * for GS/OS. + */ + if (mode & X_OK) { + if (statbuf.st_mode & (S_IFDIR | S_IEXEC)) return 0; + else return -1; + } + + return 0; /* file merely exists */ +} + + +/* + * chdir -- Replacement for the one normally shipping with Gno. + * Returns -1 and sets errno on failure, instead of always + * returning zero. + */ + +int chdir (const char *pathname) { + + PrefixRecGS record; + struct stat statbuf; + int result; + + errno = 0; + if (stat(pathname,&statbuf) == -1) return -1; + + /* verify that it's a directory */ + if (!(statbuf.st_mode & S_IFDIR)) { + errno = ENOTDIR; + return -1; + } + + /* change directory */ + record.pCount = 2; + record.prefixNum = 0; /* prefix 0 is the current directory */ + record.buffer.setPrefix = __C2GSMALLOC(pathname); + if (record.buffer.setPrefix == (GSString255Ptr) NULL) { + errno = ENOMEM; + return -1; + } + SetPrefixGS(&record); + + /* verify success, clean up, and return */ + result = toolerror(); + free(record.buffer.setPrefix); + if (result) { + errno = EINVAL; + return -1; + } + return 0; +} + + +/* + * getFileType -- Get the file type and auxillary file type of a file. + * On success it returns a pointer to an internal buffer + * containing the file type and aux type. On failure + * it returns NULL and sets errno. + */ + +fileType *getFileType (char *file) { + + static FileInfoRecGS record; + static fileType result; + int i; + + /* set the parameters */ + record.pCount = 4; + if ((record.pathname = __C2GSMALLOC(file)) == NULL) { + errno = ENOMEM; + return NULL; + } + + /* get the info */ + GetFileInfoGS(&record); + + /* check for errors */ + i = toolerror(); + free(record.pathname); + if (i) { + errno = _mapErr(i); + return NULL; + } + + /* set the return value */ + result.type = record.fileType; + result.auxtype = record.auxType; + + return &result; +} + + +#if 0 +#include + +int main(int argc, char **argv) { + char *p; + char buf[1024]; + int i; + fileType *ft; + + if (argc!=2) return -1; + + ft = getFileType(argv[1]); + if (ft == NULL) { + perror(argv[1]); + exit(1); + } else { + printf("type = %x\nauxtype = %lx\n",ft->type,ft->auxtype); + } + return 0; +} + + printf("F_OK: %d\n",access(argv[1],F_OK)); + printf("R_OK: %d\n",access(argv[1],R_OK)); + printf("W_OK: %d\n",access(argv[1],W_OK)); + printf("X_OK: %d\n",access(argv[1],X_OK)); + + if (getwd(buf) == NULL) { + perror("getwd failed"); + exit(-1); + } + printf("old directory: %s\n",buf); + + if ((i = chdir(argv[1])) !=0) perror ("chdir failed"); + printf("chdir returned %d\n",i); + + if (getwd(buf) == NULL) { + perror("getwd failed"); + exit(-1); + } + printf("new directory: %s\n",buf); + + return 0; +} + +#endif /* 0 */ diff --git a/usr.bin/man/whatis.1 b/usr.bin/man/whatis.1 new file mode 100644 index 0000000..fdf00d3 --- /dev/null +++ b/usr.bin/man/whatis.1 @@ -0,0 +1,187 @@ +.\" This man page is based on another man page copyright (c) 1980 +.\" by the Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" While this manual page is based on one from UCB, the included +.\" C source, makefile, and executables are copyright (c) 1995 +.\" by Devin Reade . All rights reserved. +.\" +.TH WHATIS 1 "Commands and Applications" "24 July 95" "Version 3.0" +.SH NAME +whatis, apropos \- locate commands by name or keyword lookup +.SH SYNOPSIS +.BR apropos +[[ +.BI \-M path +] | [ +.BI \-m path +]] [ +.BR -nV +] +.IR keyword " ..." +.br +.BR whatis +[[ +.BI \-M path +] | [ +.BI \-m path +]] [ +.BR -nV +] +.IR keyword ... +.SH DESCRIPTION +.BR whatis +shows the manual page title line for the specified +.IR keyword (s), +while +.BR apropos +shows which manual pages contain instances of any of the given +.IR keyword (s) +in their title line. +Each word is considered separately and, for +.BR apropos , +the case of letters is ignored. +Words which are part of other words are considered; when looking for +.IR compile , +.BR apropos +will also list all instances of +.IR compiler . +.LP +If a line output by either of these commands starts with +.nf + + \fIname\fR (\fIsection\fR) ... + +.fi +you can enter +.BI man " section name" +to get its documentation. +.SH OPTIONS +.IP "\fB\-M\fP \fIpath\fP" +Override the list of standard directories +.BR apropos +or +.BR whatis +search for the +.BR whatis +database. +The supplied +.I path +must be a colon\- or space\-delimited list of directories. +This search path may also be set using the environment variable +.BR MANPATH . +The space delimiter is provided for compatibility with GS/OS's +use of the colon as a pathname component delimiter. If the search +path contains no spaces nor +.B / +characters (such as +.BR :usr:local:man ), +it is assumed to be a single path, not a list of paths. +If spaces are used as delimiters, remember to quote them from the +shell. +.IP "\fB\-m\fP \fIpath\fP" +Augment the list of standard directories +.BR apropos +or +.BR whatis +search for its database. +The supplied +.I path +must be a colon\- or space\-delimited list of directories. +These directories will be searched after the standard directories +or the directories supplied by the +.BR MANPATH +environment variable are searched. +If spaces are used as delimiters, remember to quote them from the +shell. +.IP \fB-n\fP +Normally, in addition to searching the various +.BR whatis +databases, +.BR apropos +and +.BR whatis +will also search the Orca shell +.BR 15/syscmnd +file. Specifying the +.BR -n +flag will keep +.BR apropos +and +.BR whatis +from searching this file. +.IP \fB-V\fP +Show version information. +.SH ENVIRONMENT +.IP \fBMANPATH\fP +If set, +its value overrides +.B /usr/man +as the list of directories where +.BR apropos +and +.BR whatis +search for their databases. +(The +.B \-M +flag, in turn, overrides this value.) +See the description of the +.B \-M +flag for syntax details. +.IP \fBUSRMAN\fP +If +.B MANPATH +is not set, then the value of +.B USRMAN +(if set) overrides +.B /usr/man +as the list of directories where +.BR apropos +and +.BR whatis +search for their databases. +(The +.B \-M +flag, in turn, overrides this value.) +See the description of the +.B \-M +flag for syntax details. +.IP \fBMANDIR\fP +If neither +.B MANPATH +nor +.B USRMAN +is set, then the value of +.B MANDIR +(if set) overrides +.B /usr/man +as the list of directories where +.BR apropos +and +.BR whatis +search for their databases. +(The +.B \-M +flag, in turn, overrides this value.) +See the description of the +.B \-M +flag for syntax details. +.SH FILES +.\" .IP \fB/usr/\fR[\fBshare/\fR]\fBman/whatis\fR +.BR /usr/ [ share/ ] man/whatis " \-" +The +.BR whatis (1) +database. +.SH BUGS +Please report any bugs to Devin Reade, . +.SH SEE ALSO +.BR man (1), +.BR whereis (1), +.BR catman (8), +.BR makewhatis (8) +.SH HISTORY +The GNO version of +.BR apropos +first appeared in GNO version 1.0 and was written by Mike Horwath. +This version was rewritten from scratch by Devin Reade. diff --git a/usr.bin/man/whatis.c b/usr.bin/man/whatis.c new file mode 100644 index 0000000..25ca07a --- /dev/null +++ b/usr.bin/man/whatis.c @@ -0,0 +1,110 @@ +/* + * Copyright 1995 by Devin Reade . For distribution + * information see the README file that is part of the manpack archive, + * or contact the author, above. + */ + +segment "apropos___"; + +#include +#include +#include +#include +#include "util.h" +#include "man.h" + +extern int optind; +extern char *optarg; + +static char *versionstr = "3.0"; +static char *nothing = "nothing appropriate"; + +extern void begin_stack_check(void); +extern int end_stack_check(void); + +int main (int argc, char **argv) { + char *path; + int i, matches1, matches2, matches3; + short V_flag, M_flag, m_flag, n_flag, err_flag; + + /* make sure Gno is running */ + if (needsgno()==0) { + fprintf(stderr,"Requires Gno/ME\n"); + return 1; + } + +#ifdef STACK_CHECK + begin_stack_check(); +#endif + + /* initialization */ + V_flag = M_flag = m_flag = n_flag = err_flag = 0; + matches1 = matches2 = matches3 = 0; + + /* parse command line and check usage */ + while((i = getopt(argc,argv,"M:m:nV")) != EOF) { + switch(i) { + case 'M': + if (m_flag) err_flag++; + M_flag++; + path = optarg; + break; + case 'm': + if (M_flag) err_flag++; + m_flag++; + path = optarg; + break; + case 'n': + n_flag++; + break; + case 'V': + V_flag++; + break; + default: + err_flag++; + } + } + if (argc-optind < 1) err_flag++; + if (err_flag || V_flag) { + fprintf(stderr,"%s version %s by Devin Reade\n", + basename(argv[0]),versionstr); + } + if (err_flag) { + fprintf(stderr, + "Usage: %s [[-M path] | [-m path]] [-nV] keyword [keyword ...]\n", + basename(argv[0])); + return 1; + } + + /* do the search */ + if (M_flag) { + manpath = path; + } else { + manpath = getManpath(); + } + matches1 = apropos(argc-optind, &argv[optind], WHATIS_MODE); + if (!M_flag) free(manpath); + if (m_flag) { + manpath = path; + matches2 = apropos(argc-optind, &argv[optind], WHATIS_MODE); + } + if (!n_flag) { + matches3 = apropos(argc-optind, &argv[optind], ORCA_W_MODE); + } + + i = 0; + if (matches1>0) i+= matches1; + if ( m_flag && matches2>0) i+=matches2; + if (!n_flag && matches3>0) i+=matches3; + + if (i==0) { + fprintf(stderr,"%s: %s\n",basename(argv[0]),nothing); + } + +#ifdef STACK_CHECK + fprintf(stderr,"stack usage: %d bytes\n",end_stack_check()); +#endif + + if ((matches1>=0) && (matches2>=0) && (matches3>=0) && i>0) return 0; + return 1; +}