mirror of
https://github.com/GnoConsortium/gno.git
synced 2025-02-24 22:29:12 +00:00
makewhatis version 1.1 (later to become part of the manpack archive)
This commit is contained in:
parent
39f4efc5b8
commit
8ae768d073
@ -1,14 +1,71 @@
|
||||
--------------------------------------------
|
||||
Name: makewhatis
|
||||
Version: 1.0
|
||||
Version: 1.1
|
||||
Author: Devin Reade <glyn@cs.ualberta.ca>
|
||||
Computer: Apple IIgs
|
||||
Requires: Gno v2.x
|
||||
--------------------------------------------
|
||||
|
||||
Description: Generates the whatis database for apropos(1) and whatis(1)
|
||||
See the man page for a detailed description.
|
||||
===========
|
||||
Description:
|
||||
===========
|
||||
|
||||
Generates the whatis database for apropos(1) and whatis(1). See the man
|
||||
page for a detailed description.
|
||||
|
||||
============
|
||||
Installation:
|
||||
Copy makewhatis to /usr/sbin and makewhatis.1 to $(USRMAN)/man1.
|
||||
Alternately, you can type "dmake install" from this directory.
|
||||
============
|
||||
|
||||
Copy makewhatis to /usr/sbin and makewhatis.1 to $(USRMAN)/man1.
|
||||
Alternately, you can type "dmake install" from this directory.
|
||||
|
||||
============
|
||||
Distribution:
|
||||
============
|
||||
|
||||
Makewhatis is freeware. You may distribute this anywhere provided
|
||||
that the archive remains intact.
|
||||
|
||||
=======
|
||||
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.
|
||||
|
||||
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 from the bork stream
|
||||
to
|
||||
foo, bar (1) - extract and add thingys from the bork stream
|
||||
|
||||
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.
|
||||
|
@ -7,8 +7,28 @@
|
||||
#include <ctype.h>
|
||||
#include "makewhatis.h"
|
||||
|
||||
char buffer[BUFFERSIZE];
|
||||
static char buffer2[BUFFERSIZE];
|
||||
#define NAME1 "NAME"
|
||||
#define NAME2 "N\bNA\bAM\bME\bE"
|
||||
#define NAME3 "N\bN\bN\bNA\bA\bA\bAM\bM\bM\bME\bE\bE\bE"
|
||||
#define SYNOPSIS1 "SYNOPSIS"
|
||||
#define SYNOPSIS2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS"
|
||||
#define SYNOPSIS3 "S\bS\bS\bSY\bY\bY\bYN\bN\bN\bNO\bO\bO\bOP\bP\bP\bPS\bS\bS\bSI\bI\bI\bIS\bS\bS\bS"
|
||||
#define DESCRIPTION1 "DESCRIPTION"
|
||||
#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 titlebuf[BUFFERSIZE]; /* contains the command name */
|
||||
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
|
||||
#else
|
||||
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);
|
||||
*
|
||||
@ -19,10 +39,19 @@ static char buffer2[BUFFERSIZE];
|
||||
*
|
||||
* Post: <buffer> will contain all the text, minus formatting and control
|
||||
* code, starting from the word "NAME" and ending with either ".SH".
|
||||
* "SYNOPSIS", or "DESCRIPTION", whichever comes first.
|
||||
* "SYNOPSIS", or "DESCRIPTION", whichever comes first. <titlebuf>
|
||||
* will contain all printable text starting with the first printable
|
||||
* non-whitespace character following "NAME" and ending with the
|
||||
* last printable character before the first '-' following "NAME".
|
||||
*
|
||||
* If an error occurs, <buffer> will be an empty string (ie:
|
||||
* buffer[0] == '\0')
|
||||
*
|
||||
* Warning: This routine was written to be fast at the expense of code
|
||||
* size. It also has a lot of "special case"ing since it could
|
||||
* be fed nroff source, aroff'd output, or text files that may
|
||||
* include formatting control codes. If you're looking for some
|
||||
* nice neat code, you're not going to find it here.
|
||||
*/
|
||||
|
||||
void fillbuffer (char *filename) {
|
||||
@ -35,6 +64,18 @@ void fillbuffer (char *filename) {
|
||||
short in_comment;
|
||||
short in_format_BR;
|
||||
short in_format_f;
|
||||
short foo;
|
||||
|
||||
/*
|
||||
* Set p4 and p5 to the ends of buffer and titlebuf, respectively.
|
||||
* These are used for error checking, so that we don't overflow the
|
||||
* buffers. Using pointers will speed things up a bit at the cost
|
||||
* of four bytes of local storage. They are not global for the sake
|
||||
* of speed.
|
||||
*/
|
||||
|
||||
char *p4 = buffer + BUFFERSIZE;
|
||||
char *p5 = titlebuf + BUFFERSIZE;
|
||||
|
||||
/*
|
||||
* open the file
|
||||
@ -42,58 +83,232 @@ void fillbuffer (char *filename) {
|
||||
|
||||
if ((fp = fopen(filename,"rb")) == NULL) {
|
||||
buffer[0] = '\0';
|
||||
if (v_flag) fprintf (error_fp,"Open failed for file \"%s\"\n",filename);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make p1 point to spot in buffer2 where the first "NAME" occurs.
|
||||
* Note that if "NAME" is within a comment line (nroff source), it
|
||||
* will still be picked up.
|
||||
* see if it includes another man page
|
||||
*/
|
||||
if ((fgets(buffer2,4,fp) == NULL) || (strncmp(buffer2,".so",3)==0)) {
|
||||
buffer[0] = '\0';
|
||||
titlebuf[0] = '\0';
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
fseek(fp,0L,SEEK_SET);
|
||||
|
||||
/*
|
||||
* Make fp point to the first newline following NAME so that the
|
||||
* next block read will pick it up as the first character. This is
|
||||
* needed for the next section of code following this one.
|
||||
*/
|
||||
|
||||
for(;;) {
|
||||
count = fread(buffer2,sizeof(char),BUFFERSIZE-1,fp);
|
||||
if (count == 0) {
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
/*
|
||||
* eof or error, and we haven't found "NAME" yet ... return
|
||||
* an empty string
|
||||
*/
|
||||
buffer[0] = '\0';
|
||||
titlebuf[0] = '\0';
|
||||
fclose(fp);
|
||||
if (v_flag) fprintf (error_fp,
|
||||
"EOF or error on %s, NAME not found.\n",filename);
|
||||
return;
|
||||
}
|
||||
buffer2[count] = '\0';
|
||||
p1 = strstr(buffer2,"NAME");
|
||||
if (p1 != NULL) break;
|
||||
|
||||
/* ignore comment lines and any .TH line(s) */
|
||||
if ((strncmp(buffer2,".\\\"",3)==0) || (strncmp(buffer2,".TH",3)==0))
|
||||
continue;
|
||||
|
||||
/* check the various versions of "NAME" */
|
||||
if (strstr(buffer2,NAME1) != NULL) break;
|
||||
if (strstr(buffer2,NAME2) != NULL) break;
|
||||
if (strstr(buffer2,NAME3) != NULL) break;
|
||||
}
|
||||
|
||||
|
||||
/* we need the previous newline for the next algorithm to work */
|
||||
fseek(fp,-1L,SEEK_CUR);
|
||||
|
||||
/*
|
||||
* Make p1 point to spot in buffer2 where there occurs the first
|
||||
* character following '-' which in turn follows "NAME".
|
||||
* Note that if "NAME" or '-' are within a comment line
|
||||
* (nroff source), it will still be picked up.
|
||||
*
|
||||
* Also copy selected chars to titlebuf until the first '-' is found.
|
||||
*/
|
||||
|
||||
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 */
|
||||
for(;;) {
|
||||
p2 = strchr(p1,'-');
|
||||
if (p2 != NULL) {
|
||||
p2++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* read another block into buffer2. */
|
||||
|
||||
count = fread(buffer2,sizeof(char),BUFFERSIZE-1,fp);
|
||||
if (count == 0) {
|
||||
/*
|
||||
* eof or error, and we haven't found '-' yet ... return
|
||||
* an empty string
|
||||
*/
|
||||
/* 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);
|
||||
return;
|
||||
}
|
||||
buffer2[count] = '\0';
|
||||
p1 = buffer2;
|
||||
|
||||
/* mark the "end" of buffer2 with p2 */
|
||||
if ((p2 = strchr(p1,'-')) != NULL) {
|
||||
found = 1;
|
||||
} else {
|
||||
p2 = buffer + count;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is not our first iteration, dump any formatting information
|
||||
* or comments left over from the last interation.
|
||||
*/
|
||||
|
||||
if (in_comment) {
|
||||
while((p1<p2) && (*p1 != '\r')) p1++;
|
||||
in_comment = 0;
|
||||
}
|
||||
|
||||
if (in_format_BR) {
|
||||
while ((p1<p2) && !isspace(*p1)) p1++;
|
||||
in_format_BR = 0;
|
||||
}
|
||||
|
||||
if (in_format_f) {
|
||||
p1 = p1 + 3 - in_format_f;
|
||||
in_format_f = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this time, p1 points to the start of the key words, p2
|
||||
* to either the end of the key words or the end of buffer2,
|
||||
* and p3 into the spot in titlebuf where the next character should
|
||||
* be put.
|
||||
*
|
||||
* Copy *p1 to *p3 while p1<p2 (not at end of titlebuf or key words),
|
||||
* skipping comments, formatting info, and control chars
|
||||
*/
|
||||
|
||||
for (; p1<p2; p1++) {
|
||||
|
||||
/* skip .\" comments */
|
||||
if (strncmp(p1,"\r.\\\"",4) == 0) {
|
||||
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) in_format_BR = 1;
|
||||
else --p1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip \fI-type formatting */
|
||||
if ((p1<p2) && (*p1=='\\') && (*(p1+1)=='f')) {
|
||||
if ((p1 + 3) < p2) {
|
||||
p1 += 3;
|
||||
} else {
|
||||
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 ((*p1=='.') && (*(p1-1)=='\r')) p1 -=2;
|
||||
else --p1;
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
if (isgraph(*p1)) foo=1;
|
||||
if (!foo) {
|
||||
while ((p1<p2) && !isgraph(*p1)) p1++;
|
||||
if ((*p1=='.') && (*(p1-1)=='\r')) p1 -=2;
|
||||
else --p1;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* at this point, *p1 is either a control char or something that
|
||||
* we want in titlebuf, assuming that p1<p2.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
if ( !((p3>titlebuf) && (*p1 == ' ') && (*(p3-1) == ' ')) &&
|
||||
!((p3==titlebuf) && (*p3 == ' '))
|
||||
) {
|
||||
|
||||
/* don't let a space precede a comma */
|
||||
if ((*p1==',') && (*(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 (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;
|
||||
}
|
||||
|
||||
}
|
||||
p1 = p2 + 1;
|
||||
#ifdef ISGRAPH_FIX
|
||||
while ( (p1 < buffer2 + BUFFERSIZE) &&!(isgraph(*p1) && (*p1 != ' '))) p1++;
|
||||
#else
|
||||
while ((p1 < buffer2 + BUFFERSIZE) && !isgraph(*p1)) p1++;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* now copy selected chars to buffer until the next subheading is found
|
||||
@ -108,8 +323,12 @@ void fillbuffer (char *filename) {
|
||||
|
||||
/* mark the "end" of buffer2 with p2 */
|
||||
if ( ((p2 = strstr(p1,".SH")) != NULL) ||
|
||||
((p2 = strstr(p1,"SYNOPSIS")) != NULL) ||
|
||||
((p2 = strstr(p1,"DESCRIPTION")) != 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;
|
||||
} else {
|
||||
@ -156,6 +375,7 @@ void fillbuffer (char *filename) {
|
||||
|
||||
/* skip .BR-type formatting */
|
||||
if ((p1<p2) && (*p1=='\r') && (*(p1+1)=='.')) {
|
||||
p1++;
|
||||
while ((p1<p2) && !isspace(*p1)) p1++;
|
||||
if (p1==p2) in_format_BR = 1;
|
||||
}
|
||||
@ -175,7 +395,29 @@ void fillbuffer (char *filename) {
|
||||
* we want in buffer, assuming that p1<p2.
|
||||
*/
|
||||
|
||||
if ((p1<p2) && !iscntrl(*p1)) *p3++ = *p1;
|
||||
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.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) { /* we've got the entire description */
|
||||
@ -193,8 +435,11 @@ void fillbuffer (char *filename) {
|
||||
/* 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);
|
||||
return;
|
||||
}
|
||||
buffer2[count] = '\0';
|
||||
p1 = buffer2;
|
||||
|
||||
}
|
||||
@ -214,18 +459,28 @@ void fillbuffer (char *filename) {
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
if (argc != 2) {
|
||||
printf("Usage: %s <man_page_file_name>\n\n",argv[0]);
|
||||
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 %u chars long\n%s\n",strlen(buffer),buffer);
|
||||
printf("main: buffer is %lu chars long\n%s\n",strlen(buffer),buffer);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,19 @@ MANDIR = /usr/man
|
||||
#
|
||||
# Nothing past this point should have to be changed
|
||||
#
|
||||
# -DISGRAPH_FIX should come out when Orca/C's isgraph() function is fixed.
|
||||
#
|
||||
# -DTEST_PROCESS is for debugging process(). Use "dmake process".
|
||||
# -DDEBUG will give stack usage.
|
||||
#
|
||||
|
||||
CFLAGS = -w -O -v -DISGRAPH_FIX -s1024
|
||||
|
||||
CFLAGS = -w -O -v
|
||||
OBJS = makewhatis.o fillbuffer.o process.o
|
||||
LDLIBS = -l/usr/lib/gnulib -l/usr/lib/stack
|
||||
|
||||
makewhatis: $(OBJS)
|
||||
$(CC) $(OBJS) -o makewhatis
|
||||
$(CC) $(OBJS) $(LDLIBS) -o makewhatis
|
||||
|
||||
makewhatis.o: makewhatis.c makewhatis.h
|
||||
$(CC) -c $(CFLAGS) makewhatis.c
|
||||
|
@ -1,4 +1,4 @@
|
||||
.TH MAKEWHATIS 1 "Commands and Applications" "15 May 1994" "Version 1.0"
|
||||
.TH MAKEWHATIS 1 "Commands and Applications" "29 May 1994" "Version 1.1"
|
||||
.SH NAME
|
||||
.B makewhatis
|
||||
\- generate the whatis database file
|
||||
@ -9,13 +9,17 @@
|
||||
|
|
||||
.I -C
|
||||
] [
|
||||
.I -ovV
|
||||
] [
|
||||
.I "-f outfile"
|
||||
] [
|
||||
.I "-l logfile"
|
||||
] [
|
||||
.I "-o dbfile"
|
||||
] [
|
||||
.I "-p path"
|
||||
] [
|
||||
.I "-v n"
|
||||
] [
|
||||
.I "-V"
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B makewhatis
|
||||
@ -82,17 +86,31 @@ man/catX sub-directories, not man/manX sub-directories.
|
||||
.I "-f outfile"
|
||||
causes the
|
||||
.B makewhatis
|
||||
status output to be placed in \fIoutfile\fR.
|
||||
status output to be placed in \fIoutfile\fR. Invoking
|
||||
.I "-f"
|
||||
without
|
||||
.I "-v2"
|
||||
produces no output.
|
||||
.LP
|
||||
.I "-l logfile"
|
||||
will cause any error messages to be printed to \fIlogfile\fR.
|
||||
will cause any error messages to be printed to \fIlogfile\fR. Invoking
|
||||
.I "-l"
|
||||
without either
|
||||
.I "-v1"
|
||||
or
|
||||
.I "-v2"
|
||||
produces no output.
|
||||
.LP
|
||||
.I "-o dbfile"
|
||||
will make
|
||||
.B makewhatis
|
||||
use
|
||||
.I dbfile
|
||||
as the name for the generated whatis databases.
|
||||
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"
|
||||
overrides the environment variables
|
||||
@ -100,8 +118,10 @@ overrides the environment variables
|
||||
et al for determining for which manual page hierarchies the databases must
|
||||
be generated.
|
||||
.LP
|
||||
.I -v
|
||||
creates verbose status messages during execution.
|
||||
.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
|
||||
will show version and usage information, then exit.
|
||||
@ -121,6 +141,14 @@ and
|
||||
.I .
|
||||
being part of these paths, it will not correctly handle \fI..\fR.
|
||||
.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.
|
||||
.LP
|
||||
Because
|
||||
.B makewhatis
|
||||
looks for the string
|
||||
@ -130,12 +158,13 @@ and one of \fI.SH\fR, \fISYNOPSIS\fR, or
|
||||
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
|
||||
is boldfaced by repeated backspace characters as in \fIN^HNA^HAM^HME^HE\fR,
|
||||
then the generated description for that particular man page is unpredictable,
|
||||
though usually blank. For any diehards who like placing such information
|
||||
in their hand-coded man/catX pages, using a string similar to
|
||||
.I "NAME^H^H^H^HNAME"
|
||||
will create a proper description in the database file.
|
||||
is underlined by repeated backspace-_ sequences, then the generated
|
||||
description for that particular man page is unpredictable,
|
||||
though usually blank. When parsing man pages,
|
||||
.B makewhatis
|
||||
will understand the common double- and quadruple-boldfaced
|
||||
subheadings, provided
|
||||
that the backspace character (control-H) is used to achieve this effect.
|
||||
.LP
|
||||
Similarily,
|
||||
.B makewhatis
|
||||
@ -148,34 +177,29 @@ to be in the format:
|
||||
.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.
|
||||
.LP
|
||||
Where unpredictable output has been mentioned above, this means that
|
||||
the description in the database file will either be blank or random
|
||||
text from the man page. It
|
||||
.I "does not"
|
||||
mean that system integrity or that the remainder of the database file
|
||||
has been affected.
|
||||
.LP
|
||||
Any text appearing after
|
||||
.I NAME
|
||||
on the NAME header line will be ignored.
|
||||
.SH BUGS
|
||||
If a man page describes multiple items and has a NAME subheading such as
|
||||
.nf
|
||||
|
||||
NAME
|
||||
item1, item2, item3 - This is the description.
|
||||
|
||||
.fi
|
||||
Then
|
||||
.B makewhatis
|
||||
should create a database record that reads:
|
||||
.nf
|
||||
|
||||
item1 (3), item2 (3), item3 (3) - This is the description.
|
||||
|
||||
.fi
|
||||
Instead, if item2.l and item3.l are links to item1.3, the created record reads
|
||||
.nf
|
||||
|
||||
item1 (3) - This is the description.
|
||||
|
||||
.fi
|
||||
.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
|
||||
in the output. This was not fixed due to the overhead of having to
|
||||
check for such a condition.
|
||||
.SH FILES
|
||||
.nf
|
||||
/usr/sbin/makewhatis -- whatis database generator
|
||||
@ -183,8 +207,12 @@ man/whatis -- the whatis database
|
||||
.fi
|
||||
.SH SEE ALSO
|
||||
.BR apropos (1),
|
||||
.BR aroff (1),
|
||||
.BR catman (1),
|
||||
.BR compress (1),
|
||||
.BR freeze (1),
|
||||
.BR man (1),
|
||||
.BR whatis (1),
|
||||
.BR nroff (1),
|
||||
.BR whatis (1)
|
||||
.SH AUTHOR
|
||||
Written by Devin Reade <glyn@cs.ualberta.ca> for the Apple IIgs and Gno.
|
||||
|
@ -9,10 +9,16 @@
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include "getopt.h"
|
||||
#include <libc.h>
|
||||
|
||||
#include "makewhatis.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
extern void begin_stack_check(void);
|
||||
extern int end_stack_check(void);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Options:
|
||||
*
|
||||
@ -23,7 +29,7 @@
|
||||
* -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 verbose
|
||||
* -v{1|2} verbose
|
||||
* -V show version and usage info and exit
|
||||
*/
|
||||
|
||||
@ -41,18 +47,6 @@ char *man_subdir[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
/* For the various command line flags */
|
||||
|
||||
short c_flag = 0;
|
||||
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 */
|
||||
|
||||
static char filebuffer[FILENAME_MAX]; /* used when traversing cat* pages */
|
||||
static char progdir[FILENAME_MAX]; /* the directory where makewhatis started */
|
||||
|
||||
/*
|
||||
* we include cat* since some Gno utility man pages aren't written in
|
||||
* either nroff or aroff source ... go figure.
|
||||
@ -72,6 +66,18 @@ char *cat_subdir[] = {
|
||||
NULL /* _must_ be NULL terminated! */
|
||||
};
|
||||
|
||||
/* For the various command line flags */
|
||||
|
||||
short c_flag = 0;
|
||||
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 */
|
||||
|
||||
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;
|
||||
|
||||
@ -98,6 +104,10 @@ int main (int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
begin_stack_check();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* set the defaults
|
||||
*/
|
||||
@ -113,7 +123,7 @@ int main (int argc, char **argv) {
|
||||
* parse the command line
|
||||
*/
|
||||
|
||||
while((i = getopt(argc,argv,"cCf:l:o:p:vV")) != EOF)
|
||||
while((i = getopt(argc,argv,"cCf:l:o:p:v:V")) != EOF)
|
||||
switch(i) {
|
||||
case 'c':
|
||||
if (C_flag) errflag++;
|
||||
@ -148,11 +158,12 @@ int main (int argc, char **argv) {
|
||||
p = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
v_flag++;
|
||||
v_flag = (short) atoi(optarg);
|
||||
if ((v_flag!=1) && (v_flag!=2)) errflag++;
|
||||
break;
|
||||
case 'V':
|
||||
fprintf(stderr,
|
||||
"%s -- Create the %s database.\n\tVersion %s by Devin Reade\n\n",
|
||||
"%s --\n\tCreate the %s database.\n\tVersion %s by Devin Reade\n\n",
|
||||
argv[0],WHATIS,VERSIONSTRING);
|
||||
errflag++;
|
||||
break;
|
||||
@ -162,15 +173,17 @@ int main (int argc, char **argv) {
|
||||
}
|
||||
if (errflag) {
|
||||
fprintf(error_fp,
|
||||
"Usage: %s [-c|-C] [-ovV] [-f outfile] [-l logfile] [-p path]\n\n\
|
||||
"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\
|
||||
-C\t\tCheck _only_ catX subdirectories, not manX subdirectories.\n\
|
||||
-f outfile\tForce whatis output to <outfile>.\n\
|
||||
-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\t\tVerbose.\n\
|
||||
-V\t\tShow version and usage information, then exit.\n",argv[0],WHATIS);
|
||||
-v n\t\t<n>=1: Verbose, only displaying major errors.\n\
|
||||
\t\t<n>=2: Very verbose, displaying processing information.\n\
|
||||
-V\t\tShow version and usage information, then exit.\n",argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -192,7 +205,8 @@ environment variables\n$MANPATH, $USRMAN, or $MANDIR, or use the -p flag.\n\n");
|
||||
|
||||
/* make a copy of the location */
|
||||
if ((manpath = malloc (strlen(p) + 1)) == NULL) {
|
||||
if (v_flag) fprintf(error_fp,"couldn't make copy of \"%s\"",p);
|
||||
if (v_flag) fprintf(error_fp,
|
||||
"malloc failed while making copy of \"%s\"\nAborted.\n",p);
|
||||
return -1;
|
||||
}
|
||||
strcpy(manpath,p);
|
||||
@ -221,7 +235,8 @@ environment variables\n$MANPATH, $USRMAN, or $MANDIR, or use the -p flag.\n\n");
|
||||
whatis_fp = fopen(dbfile,"w");
|
||||
if (whatis_fp == NULL) {
|
||||
fprintf (error_fp,
|
||||
"Could not create whatis database file %s in directory %s.\n",
|
||||
"Could not create whatis database file %s in directory %s.\n\
|
||||
Aborted.\n",
|
||||
dbfile,path);
|
||||
exit(-1);
|
||||
}
|
||||
@ -235,7 +250,7 @@ environment variables\n$MANPATH, $USRMAN, or $MANDIR, or use the -p flag.\n\n");
|
||||
if (subdir != NULL) {
|
||||
|
||||
/* print status */
|
||||
if (v_flag) fprintf(output_fp,
|
||||
if (v_flag>=2) fprintf(output_fp,
|
||||
"Now working on directory %s\t%s ...\n",path,man_subdir[i]);
|
||||
|
||||
/* no need to error check because of opendir() */
|
||||
@ -247,7 +262,7 @@ environment variables\n$MANPATH, $USRMAN, or $MANDIR, or use the -p flag.\n\n");
|
||||
}
|
||||
closedir(subdir);
|
||||
} else {
|
||||
if (v_flag) fprintf(output_fp,
|
||||
if (v_flag>=2) fprintf(output_fp,
|
||||
"Could not access files in %s\t%s ...\n",path,man_subdir[i]);
|
||||
}
|
||||
chdir(path);
|
||||
@ -263,7 +278,7 @@ environment variables\n$MANPATH, $USRMAN, or $MANDIR, or use the -p flag.\n\n");
|
||||
if (subdir != NULL) {
|
||||
|
||||
/* print status */
|
||||
if (v_flag) fprintf(output_fp,
|
||||
if (v_flag>=2) fprintf(output_fp,
|
||||
"Now working on directory %s\t%s ...\n",path,cat_subdir[i]);
|
||||
|
||||
/* no need to error check because of opendir() */
|
||||
@ -284,7 +299,7 @@ environment variables\n$MANPATH, $USRMAN, or $MANDIR, or use the -p flag.\n\n");
|
||||
}
|
||||
closedir(subdir);
|
||||
} else {
|
||||
if (v_flag) fprintf(output_fp,
|
||||
if (v_flag>=2) fprintf(output_fp,
|
||||
"Could not access files in %s\t%s ...\n",path,cat_subdir[i]);
|
||||
}
|
||||
chdir(path);
|
||||
@ -303,5 +318,10 @@ environment variables\n$MANPATH, $USRMAN, or $MANDIR, or use the -p flag.\n\n");
|
||||
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());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
#define VERSIONSTRING "1.0"
|
||||
#define VERSIONSTRING "1.1, 29 May 1994"
|
||||
|
||||
/* The size of the IO buffers */
|
||||
#define BUFFERSIZE 1024
|
||||
@ -15,11 +15,4 @@ extern int system (const char *);
|
||||
void fillbuffer (char *filename);
|
||||
void process (char *filename, char *tmp_file, FILE *whatis_fp);
|
||||
|
||||
extern short c_flag;
|
||||
extern short C_flag;
|
||||
extern short f_flag;
|
||||
extern short l_flag;
|
||||
extern short O_flag;
|
||||
extern short p_flag;
|
||||
extern short v_flag;
|
||||
extern short errflag;
|
||||
|
@ -12,14 +12,23 @@
|
||||
|
||||
#include "makewhatis.h"
|
||||
|
||||
/* These are the compression types */
|
||||
#define NO_COMPRESS 0
|
||||
#define Z_COMPRESS 1
|
||||
#define F_COMPRESS 2
|
||||
|
||||
#ifdef TEST_PROCESS
|
||||
short v_flag = 1;
|
||||
short v_flag = 1;
|
||||
FILE *output_fp;
|
||||
FILE *error_fp;
|
||||
#else
|
||||
extern FILE *output_fp;
|
||||
extern FILE *error_fp;
|
||||
#endif
|
||||
|
||||
extern GSString255Ptr __C2GSMALLOC (char *s);
|
||||
extern char buffer[];
|
||||
extern FILE *output_fp;
|
||||
extern FILE *error_fp;
|
||||
extern char titlebuf[];
|
||||
|
||||
/*
|
||||
* void process (char *filename, char *tmp_file, FILE *whatis_fp);
|
||||
@ -40,12 +49,12 @@ void process (char *filename, char *tmp_file, FILE *whatis_fp) {
|
||||
char *p1; /* a scratch pointer */
|
||||
int namelength; /* length of 'name (section)' */
|
||||
char *name; /* points to the file basename */
|
||||
int sufflen; /* length of the filename suffix */
|
||||
short compression; /* the compression type (if nec) */
|
||||
|
||||
if (v_flag) fprintf(output_fp,"Working on file %s ...\n",filename);
|
||||
if (v_flag>=2) fprintf(output_fp,"Working on file %s ...\n",filename);
|
||||
|
||||
/*
|
||||
* get the file basename and suffix
|
||||
* get the file basename
|
||||
*/
|
||||
|
||||
if ((name = malloc (strlen(filename)+1)) == NULL) {
|
||||
@ -55,66 +64,89 @@ void process (char *filename, char *tmp_file, FILE *whatis_fp) {
|
||||
return;
|
||||
}
|
||||
strcpy(name,filename);
|
||||
if ((suffix = strchr(name,'.')) == NULL) {
|
||||
|
||||
/*
|
||||
* 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;
|
||||
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);
|
||||
return;
|
||||
}
|
||||
*suffix = '\0';
|
||||
suffix++;
|
||||
sufflen = strlen(suffix);
|
||||
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;
|
||||
} else compression = NO_COMPRESS;
|
||||
*p1 = '\0';
|
||||
|
||||
/*
|
||||
* define the suffix
|
||||
*/
|
||||
|
||||
if (compression == NO_COMPRESS) {
|
||||
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;
|
||||
}
|
||||
*p1 = '\0';
|
||||
suffix = p1 + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* find out the file type
|
||||
*/
|
||||
|
||||
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);
|
||||
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 ((info_record.fileType == 0x50u) && (info_record.auxType == 0x8010u)) {
|
||||
if ((compression == NO_COMPRESS) &&
|
||||
(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);
|
||||
system(command_buf);
|
||||
fillbuffer(tmp_file);
|
||||
|
||||
} else if ( (toupper(*(suffix+sufflen-1))=='Z') &&
|
||||
(*(suffix+sufflen-2)=='.')) {
|
||||
} 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);
|
||||
|
||||
/* fix suffix for printout */
|
||||
sufflen -= 2;
|
||||
*(suffix + sufflen) = '\0';
|
||||
|
||||
} else if ( (toupper(*(suffix+sufflen-1))=='F') &&
|
||||
(*(suffix+sufflen-2)=='.')) {
|
||||
} 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);
|
||||
|
||||
/* fix suffix for printout */
|
||||
sufflen -= 2;
|
||||
*(suffix + sufflen) = '\0';
|
||||
|
||||
} else if ((toupper(*suffix)=='L') && (*(suffix+1)=='\0')) {
|
||||
|
||||
/* It's a link to another man page; do nothing. */
|
||||
@ -126,6 +158,13 @@ void process (char *filename, char *tmp_file, FILE *whatis_fp) {
|
||||
fillbuffer(filename);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there was an error, or it is an .so reference to another man
|
||||
* page, then return without writing anything to the database
|
||||
*/
|
||||
|
||||
if ((buffer[0] == '\0') || (titlebuf[0] == '\0')) return;
|
||||
|
||||
/*
|
||||
* At this point, buffer contains the line that we need to print to
|
||||
* whatis_fd. Strip off any leading spaces, then give it a nice
|
||||
@ -134,27 +173,31 @@ void process (char *filename, char *tmp_file, FILE *whatis_fp) {
|
||||
|
||||
p1 = buffer;
|
||||
while (isspace(*p1)) p1++;
|
||||
namelength = strlen(name) + strlen(suffix) + 4;
|
||||
namelength = strlen(titlebuf) + strlen(suffix) + 4;
|
||||
|
||||
if (namelength > (TABLENGTH * 3)) {
|
||||
fprintf(whatis_fp,"%s (%s) - %s\n", name, suffix, p1);
|
||||
fprintf(whatis_fp,"%s (%s) - %s\n", titlebuf, suffix, p1);
|
||||
} else if (namelength > (TABLENGTH * 2)) {
|
||||
fprintf(whatis_fp,"%s (%s)\t- %s\n", name, 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", name, suffix, p1);
|
||||
fprintf(whatis_fp,"%s (%s)\t\t- %s\n", titlebuf, suffix, p1);
|
||||
} else {
|
||||
fprintf(whatis_fp,"%s (%s)\t\t\t- %s\n", name, suffix, p1);
|
||||
fprintf(whatis_fp,"%s (%s)\t\t\t- %s\n", titlebuf, suffix, p1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST_PROCESS
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
|
||||
output_fp = stdout;
|
||||
error_fp = stderr;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("Usage: %s <man_page_file_name>\n",argv[0]);
|
||||
fprintf(stderr,"Usage: %s <man_page_file_name>\n",argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user