gno/usr.bin/man/makewhatis.c

335 lines
9.2 KiB
C
Raw Normal View History

/*
* 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>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include "getopt.h"
#include <libc.h>
#include "makewhatis.h"
#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|3} verbose
* -V show version and usage info and exit
*/
char *man_subdir[] = {
"man1",
"man2",
"man3",
"man3f",
"man4",
"man5",
"man6",
"man7",
"man8",
"mann",
"manl",
"manp",
"mano",
NULL
};
/*
* we include cat* since some Gno utility man pages aren't written in
* either nroff or aroff source ... go figure.
*/
char *cat_subdir[] = {
"cat1",
"cat2",
"cat3f",
"cat4",
"cat5",
"cat6",
"cat7",
"cat8",
"catn",
"catl",
"catp",
"cato",
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;
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 *dirsep; /* the directory separator, either "/" or ":" */
int i;
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
/*
* set the defaults
*/
output_fp = stdout;
error_fp = stderr;
if (getwd(progdir) == NULL) {
perror("getwd() failed");
exit(1);
}
/*
* parse the command line
*/
while((i = getopt(argc,argv,"cCf:l:o:p:v:V")) != EOF)
switch(i) {
case 'c':
if (C_flag) errflag++;
else c_flag++;
break;
case 'C':
if (c_flag) errflag++;
else C_flag++;
break;
case 'f':
output_fp = fopen (optarg,"w");
if (output_fp == NULL) {
fprintf(stderr,"Could not open output file %s; using stdout.\n",
optarg);
output_fp = stdout;
}
break;
case 'l':
error_fp = fopen (optarg,"w");
if (error_fp == NULL) {
fprintf(stderr,"Could not open log file %s; using stderr.\n",
optarg);
error_fp = stderr;
}
break;
case 'o':
o_flag++;
dbfile = optarg;
break;
case 'p':
p_flag++;
p = optarg;
break;
case 'v':
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",
argv[0],WHATIS,VERSIONSTRING);
errflag++;
break;
default:
errflag++;
break;
}
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\
-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 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;
}
/*
* 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) 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);
return -1;
}
strcpy(manpath,p);
/* get the name of the temporary file */
tmpnam (tmp_file);
/*
* loop over all the paths in manpath. Don't use ':' as a delimiter since
* the colon is a pathname separator under GS/OS.
*/
path = strtok (manpath," ");
while (path != NULL) {
if (access(path,F_OK)==0) {
if (strcmp(path,".") == 0) {
chdir(progdir);
} else {
chdir(path);
}
/* 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\
Aborted.\n",
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) {
/* 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]);
/* 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) {
/* 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]);
/* 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);
if (access(filebuffer,F_OK)!=0)
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);
}
/* get the next path in manpath */
path = strtok (NULL," ");
}
/* clean up and exit */
unlink(tmp_file);
if (output_fp != stdout) fclose(output_fp);
if (error_fp != stderr) fclose(error_fp);
#ifdef STACK_CHECK
fprintf(stderr,"Makewhatis stack usage: %d bytes\n",end_stack_check());
#endif
return 0;
}