Version 3.0 of the manpack archive. This moved on top of the

original makewhatis repository.  Earlier versions of man, apropos,
and whatis were by other authors (these are written from scratch).
Catman is new.
This commit is contained in:
gdr 1996-01-28 00:41:22 +00:00
parent 8ae768d073
commit 73ce022151
24 changed files with 4071 additions and 563 deletions

View File

@ -1,71 +1,209 @@
--------------------------------------------
Name: makewhatis
Version: 1.1
Author: Devin Reade <glyn@cs.ualberta.ca>
Name: manpack
Version: 3.0
Author: Devin Reade <gdr@myrias.com>
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 <gdr@myrias.com>.
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<section>/<filename>"
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.

1
usr.bin/man/apropos.1 Normal file
View File

@ -0,0 +1 @@
.so man1/whatis.1

110
usr.bin/man/apropos.c Normal file
View File

@ -0,0 +1,110 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "apropos___";
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <libc.h>
#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;
}

284
usr.bin/man/apropos2.c Normal file
View File

@ -0,0 +1,284 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "apropos2__";
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#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 <manpath> 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<argc; i++) {
dirbrk = (strchr(argv[i],':')!=NULL) ? ':' : '/';
if ((q = strrchr(argv[i],dirbrk)) != NULL) {
q++;
p = argv[i];
do {
*p = *q;
p++; q++;
} while (*q);
*p = '\0';
}
}
}
if ((apropos_mode == ORCA_K_MODE) ||
(apropos_mode == ORCA_W_MODE) ||
(apropos_mode == ORCA_F_MODE)) {
/*
* searching the Orca 15/syscmnd file
*/
if ((fp = fopen(SYSCMND,"r")) == NULL) {
fprintf(stderr,"couldn't open %s\n",SYSCMND);
return -1;
}
/* loop over lines in file */
while ((q = fgets(linebuf,BUFFERSIZE,fp)) != NULL) {
if (*linebuf == ';') continue;
/* loop over keywords */
for(i=0; i<argc; i++) {
keyword = argv[i];
if ((apropos_mode == ORCA_K_MODE && ncstrstr(linebuf,keyword)) ||
(apropos_mode == ORCA_F_MODE && strstr(linebuf,keyword)) ||
(apropos_mode == ORCA_W_MODE &&
!strncmp(linebuf,keyword,strlen(keyword)))) {
r = orcacomment(linebuf);
p = orcacommand(linebuf);
q = orcapadding(p);
printf("%s (Orca) %s- %s",p,q,r);
matches++;
}
}
}
fclose(fp);
return matches;
}
if ((manpath_array = makePathArray(manpath)) == NULL) return -1;
/*
* loop over all the paths in MANPATH
*/
i=0;
current_path = manpath_array[i];
while (current_path) {
dirbrk = (strchr(current_path,':')!=NULL) ? ':' : '/';
if (chdir(current_path) == -1) {
fprintf(stderr,"%s: %s\n",current_path,strerror(errno));
} else if ((fp=fopen(WHATIS,"r"))==NULL) {
if (access(WHATIS,F_OK) == -1) {
fprintf(stderr,"%s%c%s: %s\n",current_path,dirbrk,WHATIS,
strerror(ENOENT));
} else {
fprintf(stderr,"error opening %s%c%s\n",current_path,dirbrk,
WHATIS);
}
} else {
/* read each line, looking for a match */
for (;;) {
q = fgets(linebuf,BUFFERSIZE,fp);
if (q != NULL) {
/* search for a match to any keyword */
for (j=0; j<argc; j++) {
keyword = argv[j];
switch (apropos_mode) {
case MAN_F_MODE:
if (strstr(linebuf,keyword)) {
printf("%s",linebuf);
matches++;
}
break;
case MAN_K_MODE:
if (ncstrstr(linebuf,keyword)) {
printf("%s",linebuf);
matches++;
}
break;
case WHATIS_MODE:
/* avoid unnecessary strcpy's */
if (strstr(linebuf,keyword)==NULL) break;
strcpy(linebuf2,linebuf);
if ((p = strchr(linebuf2,'(')) != NULL) *p = '\0';
if (strstr(linebuf2,keyword)) {
printf("%s",linebuf);
matches++;
}
break;
default:
fprintf(stderr,"internal error line %d of %s\n",
__LINE__,__FILE__);
exit(1);
}
}
} else if (ferror(fp)) {
fprintf(stderr,"error reading %s database: %s\n",WHATIS,
strerror(errno));
break;
} else break;
}
fclose(fp);
}
i++;
current_path = manpath_array[i];
} /* endwhile loop over directories */
return matches;
}

95
usr.bin/man/catman.8 Normal file
View File

@ -0,0 +1,95 @@
.\" Copyright (c) 1995 Devin Reade <gdr@myrias.com>. 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, <gdr@myrias.ab.ca>.
.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.

356
usr.bin/man/catman.c Normal file
View File

@ -0,0 +1,356 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "catman____";
#include <sys/types.h>
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
#include <libc.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/stat.h>
#include <errno.h>
#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<section>" */
char mandir[FILENAME_MAX];
/*
* These are of the form
* "(man|cat)<section>/<name>.<section>[.<compression_suffix>]"
*/
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 <manpath> is a space- or colon-delimited list
* of pathnames.
*
* Post: for each pathname in <manpath>, 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<argc; i++) {
if (!strcmp(argv[i],sections[sectionIndex].name)) {
sec = argv[i];
break;
}
}
if (sec == NULL) continue;
} else sec = sections[sectionIndex].name;
#ifdef DEBUG
assert(sec);
#endif
/*
* we're going to update this section. Open the man? subdir
*/
if (strlen(sec) + 3 >= 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<argc; i++) {
if (!strcmp(argv[i],"local")) argv[i] = "l";
if (!strcmp(argv[i],"new")) argv[i] = "n";
if (!strcmp(argv[i],"old")) argv[i] = "o";
if (!strcmp(argv[i],"public")) argv[i] = "p";
}
/* do the search */
if (M_flag) {
manpath = path;
} else {
manpath = getManpath();
}
result1 = catman(argc-optind, &argv[optind]);
if (!M_flag) free(manpath);
if (m_flag) {
manpath = path;
result2 = catman(argc-optind, &argv[optind]);
}
#ifdef STACK_CHECK
fprintf(stderr,"stack usage: %d bytes\n",end_stack_check());
#endif
return (result1 || result2);
}

29
usr.bin/man/common.c Normal file
View File

@ -0,0 +1,29 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "common____";
#include <types.h>
#include <string.h>
#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;
}

50
usr.bin/man/describe.man Normal file
View File

@ -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.

View File

@ -1,6 +1,10 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "makewhatis";
#include <stdio.h>
#include <string.h>
@ -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((p1<p2) && (*p1 != '\r')) p1++;
while((p1<p2) && (*p1 != '\r')) p1++;
in_comment = 0;
}
if (in_format_BR) {
while ((p1<p2) && !isspace(*p1)) p1++;
while ((p1<p2) && !isspace(*p1)) p1++;
in_format_BR = 0;
}
if (in_format_f) {
p1 = p1 + 3 - in_format_f;
p1 = p1 + 3 - in_format_f;
in_format_f = 0;
}
@ -209,50 +214,50 @@ void fillbuffer (char *filename) {
for (; p1<p2; p1++) {
/* skip .\" comments */
/* skip .\" comments */
if (strncmp(p1,"\r.\\\"",4) == 0) {
while ((p1<p2) && (*p1!='\r')) p1++;
while ((p1<p2) && (*p1!='\r')) p1++;
if (p1==p2) in_comment = 1;
continue;
}
/* skip .BR-type formatting */
if ((p1<p2) && (*p1=='\r') && (*(p1+1)=='.')) {
p1++;
while ((p1<p2) && !isspace(*p1)) p1++;
if ((p1<p2) && (*p1=='\r') && (*(p1+1)=='.')) {
p1++;
while ((p1<p2) && !isspace(*p1)) p1++;
if (p1==p2) in_format_BR = 1;
else --p1;
continue;
}
/* skip \fI-type formatting */
if ((p1<p2) && (*p1=='\\') && (*(p1+1)=='f')) {
if ((p1 + 3) < p2) {
p1 += 3;
if ((p1<p2) && (*p1=='\\') && (*(p1+1)=='f')) {
if ((p1 + 3) < p2) {
p1 += 3;
} else {
in_format_f = p2 - p1;
p1 = p2;
in_format_f = p2 - p1;
p1 = p2;
}
continue;
}
/*
/*
* skip whitespace if we haven't got the beginning of the
* description yet.
*/
#ifdef ISGRAPH_FIX
if (isgraph(*p1) && (*p1!=' ')) foo=1;
if (!foo) {
while ((p1<p2) && !(isgraph(*p1) && (*p1!=' '))) p1++;
if (isgraph(*p1) && (*p1!=' ')) foo=1;
if (!foo) {
while ((p1<p2) && !(isgraph(*p1) && (*p1!=' '))) p1++;
if ((*p1=='.') && (*(p1-1)=='\r')) p1 -=2;
else --p1;
continue;
}
#else
if (isgraph(*p1)) foo=1;
if (!foo) {
while ((p1<p2) && !isgraph(*p1)) p1++;
if (isgraph(*p1)) foo=1;
if (!foo) {
while ((p1<p2) && !isgraph(*p1)) p1++;
if ((*p1=='.') && (*(p1-1)=='\r')) p1 -=2;
else --p1;
continue;
@ -266,43 +271,43 @@ void fillbuffer (char *filename) {
if ((p1<p2) && !iscntrl(*p1)) {
/*
/*
* The conditional below means:
* Copy it so that: 1. There is only one space between words; and
* 2. The buffer doesn't begin with a space.
* Copy it so that: 1. There is only one space between words; and
* 2. The buffer doesn't begin with a space.
*/
if ( !((p3>titlebuf) && (*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((p1<p2) && (*p1 != '\r')) p1++;
while((p1<p2) && (*p1 != '\r')) p1++;
in_comment = 0;
}
if (in_format_BR) {
while ((p1<p2) && !isspace(*p1)) p1++;
while ((p1<p2) && !isspace(*p1)) p1++;
in_format_BR = 0;
}
if (in_format_f) {
p1 = p1 + 3 - in_format_f;
p1 = p1 + 3 - in_format_f;
in_format_f = 0;
}
@ -367,26 +383,26 @@ void fillbuffer (char *filename) {
for (; p1<p2; p1++) {
/* skip .\" comments */
/* skip .\" comments */
if (strncmp(p1,"\r.\\\"",4) == 0) {
while ((p1<p2) && (*p1!='\r')) p1++;
while ((p1<p2) && (*p1!='\r')) p1++;
if (p1==p2) in_comment = 1;
}
/* skip .BR-type formatting */
if ((p1<p2) && (*p1=='\r') && (*(p1+1)=='.')) {
p1++;
while ((p1<p2) && !isspace(*p1)) p1++;
if ((p1<p2) && (*p1=='\r') && (*(p1+1)=='.')) {
p1++;
while ((p1<p2) && !isspace(*p1)) p1++;
if (p1==p2) in_format_BR = 1;
}
/* skip \fI-type formatting */
if ((p1<p2) && (*p1=='\\') && (*(p1+1)=='f')) {
if ((p1 + 3) < p2) {
p1 += 3;
if ((p1<p2) && (*p1=='\\') && (*(p1+1)=='f')) {
if ((p1 + 3) < p2) {
p1 += 3;
} else {
in_format_f = p2 - p1;
p1 = p2;
in_format_f = p2 - p1;
p1 = p2;
}
}
@ -397,52 +413,52 @@ void fillbuffer (char *filename) {
if ((p1<p2) && !iscntrl(*p1)) {
/*
/*
* The conditional below means:
* Copy it so that: 1. There is only one space between words; and
* 2. The buffer doesn't begin with a space.
* Copy it so that: 1. There is only one space between words; and
* 2. The buffer doesn't begin with a space.
*/
if ( !((p3>buffer) && (*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 <man_page_file_name>\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

42
usr.bin/man/globals.c Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
#include <types.h>
#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! */
};

View File

@ -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

View File

@ -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
<command> - <brief description>
\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, <gdr@myrias.com>.
.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 <glyn@cs.ualberta.ca> for the Apple IIgs and Gno.

View File

@ -1,6 +1,10 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "makewhatis";
#include <sys/types.h>
#include <stdio.h>
@ -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 <outfile>
* -l logfile log errors to <logfile>
* -o dbfile force whatis database output to <dbfile>
* -p path use the <path> 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 <outfile>
* -l logfile log errors to <logfile>
* -o dbfile force whatis database output to <dbfile>
* -p path use the <path> 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 <logfile>.\n\
-o dbfile\tforce whatis database output to <dbfile>.\n\
-p path\t\tUse the <path> rather than $MANPATH, $USRMAN, or $MANDIR.\n\
-v n\t\t<n>=1: Verbose, only displaying major errors.\n\
\t\t<n>=2: Very verbose, displaying processing information.\n\
-v n\t\t<n>=1: Slightly verbose, only displaying major errors.\n\
\t\t<n>=2: Verbose, displaying processed file names.\n\
\t\t<n>=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;

View File

@ -1,18 +1,27 @@
#define VERSIONSTRING "1.1, 29 May 1994"
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. 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;

519
usr.bin/man/man.1 Normal file
View File

@ -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 <gdr@myrias.com>. 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, <gdr@myrias.com>.
.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.

154
usr.bin/man/man.c Normal file
View File

@ -0,0 +1,154 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "man_______";
#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <stdlib.h>
#include <libc.h>
#include <ctype.h>
#include <assert.h>
#include <sgtty.h>
#include <unistd.h>
#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<argc; i++) {
if (strcmp(argv[i],"-") == 0) {
hyphen_flag++;
if (k_flag || f_flag) err_flag++;
--argc;
for( ; i<argc; i++) {
argv[i] = argv[i+1];
}
}
}
if ((argc == optind) || (!k_flag && !f_flag && (argc-optind > 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;
}

95
usr.bin/man/man.h Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. 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);

611
usr.bin/man/man2.c Normal file
View File

@ -0,0 +1,611 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "man2______";
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sgtty.h>
#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<total1; i++) {
if (list1[i] == NULL) continue;
for (j=0; j<total2; j++) {
if (list2[j] == NULL) continue;
getBaseName(buffer1,list1[i]);
getBaseName(buffer2,list2[j]);
#ifdef DEBUG
if ((strlen(buffer1) < len + 5) ||
(strlen(buffer2) < len + 5)) {
fprintf(stderr,"internal error at line %d of %s\n",__LINE__,
__FILE__);
exit(1);
}
#endif
/* match after the respective "manXX/" and "catXX/" */
if ( strcmp(&buffer1[len+4],&buffer2[len+4]) == 0 ) {
p = newerFile(list1[i],list2[j]);
if (p == list1[i]) {
free(list2[j]);
list2[j] = NULL;
} else if (p == list2[j]) {
free(list1[i]);
list1[i] = NULL;
break;
} else {
fprintf(stderr,"internal error at line %d of %s\n\t%s\n\t%s\n",
__LINE__,__FILE__,
(list1[i]) ? list1[i] : "(NULL)",
(list2[j]) ? list2[j] : "(NULL)");
perror("newerFile failed");
exit(1);
}
} /* endif */
} /* endfor */
} /* endfor */
/*
* combine the two lists
*/
for (i=0;i<total1;i++) {
if (list1[i] != NULL) {
list3 = addToStringArray(list3, list1[i]);
free(list1[i]);
}
}
for (j=0;j<total2;j++) {
if (list2[j] != NULL) {
list3 = addToStringArray(list3, list2[j]);
free(list2[j]);
}
}
free(list1);
free(list2);
return list3;
}
/*
* cleanManList
*
* Pre: list is a NULL-terminated array of strings, where the array
* and each string in the array was allocated by malloc.
*
* Post: all malloc'd memory in list is free'd.
*/
static void cleanManList(char **list) {
int i;
for (i=0; list[i]; i++) {
free(list[i]);
}
free (list);
return;
}
/*
* display
*/
#define MANSUBDIR 0
#define CATSUBDIR 1
#define FORMAT "Formatting manual page, please wait ..."
#define DECOMP "Decompressing manual page, please wait ..."
#define DECFOR "Decompressing and formatting manual page, please wait ..."
#define OVERFLOW "Internal buffer overflow ... aborted."
static void display(char *file) {
int icompress, isubdir;
char *tmac;
char *roffer;
char *compressor;
fileType *ft;
#ifdef DEBUG
if (file == NULL) {
fprintf(stderr,"internal error line %d of %s\n",__LINE__,__FILE__);
exit(1);
}
if (strlen(file) < 4) {
fprintf(stderr,"internal error line %d of %s\n",__LINE__,__FILE__);
exit(1);
}
#endif
/*
* determine which subdirectory this file is in
*/
if (strncmp(file,"cat",3) == 0) {
isubdir = CATSUBDIR;
} else {
isubdir = MANSUBDIR;
}
/*
* if we're troffing a new file to fmt?, make sure the directory
* exists
*/
if (t_flag && hyphen_flag) {
char *p;
struct stat sbuf;
/* ensure the fmt? directory exists */
sprintf(linebuf,"fmt%s",&file[3]);
if ((p = strchr(linebuf,':')) != NULL) {
*p = '\0';
#ifdef DEBUG
} else if ((p = strchr(linebuf,'/')) == NULL) {
fprintf(stderr,"internal error line %d of %s\n",__LINE__,
__FILE__);
exit(1);
#endif
} else *p = '\0';
if (stat(linebuf,&sbuf) != 0) {
fprintf(stderr,"couldn't stat %s: %s. %s skipped\n",
linebuf,strerror(errno),file);
return;
} else if (!(sbuf.st_mode & S_IFDIR)) {
fprintf(stderr,"cannot access %s: %s. %s skipped\n",
linebuf,strerror(ENOTDIR),file);
return;
}
}
/*
* determine the type of compression used, if any
*/
icompress = getSuffixIndex(file);
if (icompress >= 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 <in> into the buffer
* pointed to by <out>, 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 <out>.
*/
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;
}

View File

@ -1,6 +1,10 @@
#ifdef __CCFRONT__
#include <14:pragma.h>
#endif
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "makewhatis";
#include <stdio.h>
#include <string.h>
@ -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: <filename> is the name of the file to add to the database.
* <tmp_file> is the name for the temporary file. It has not been opened.
* <whatis_fp> is a file pointer to the open whatis database file.
* Pre: <filename> is the name of the file to add to the database.
* <tmp_file> is the name for the temporary file. It has not been opened.
* <whatis_fp> 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 <whatis_fp>.
* appended to <whatis_fp>.
*/
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 <man_page_file_name>\n",argv[0]);
if (argc != 2) {
fprintf(stderr,"Usage: %s <man_page_file_name>\n",argv[0]);
return -1;
}
process (argv[1], ":tmp:garbage", stdout);
process (argv[1], ":tmp:garbage", stdout, "2");
return 0;
}

386
usr.bin/man/util.c Normal file
View File

@ -0,0 +1,386 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "util______";
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <ctype.h>
#include <sgtty.h>
#include <fcntl.h>
#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 <path> 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<count; i++) {
if (a[i] == b[i]) {
if (!a[i]) break;
else continue;
}
return ((int) b[i]-a[i]);
}
return 0;
}
/*
* ncstrstr -- A case insensitive ("no-case") strstr
*
* This is implemented using a convert-copy-to-single-case-
* then-strstr hack.
* It's speed could be increased by switching
* to a Boyer-Moore scan algorithm anytime strlen(substr) > 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 <path>. <path> _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 <path>. This returns a pointer to an internal
* buffer, so the next call to dirname() will overwrite this
* buffer. <path> 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;
}

37
usr.bin/man/util.h Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. 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);

179
usr.bin/man/utilgs.c Normal file
View File

@ -0,0 +1,179 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "utilgs____";
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <gsos.h>
#include <orca.h>
#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 <stdio.h>
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 */

187
usr.bin/man/whatis.1 Normal file
View File

@ -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 <gdr@myrias.com>. 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, <gdr@myrias.ab.ca>.
.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.

110
usr.bin/man/whatis.c Normal file
View File

@ -0,0 +1,110 @@
/*
* Copyright 1995 by Devin Reade <gdr@myrias.com>. For distribution
* information see the README file that is part of the manpack archive,
* or contact the author, above.
*/
segment "apropos___";
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <libc.h>
#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;
}