home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari FTP
/
ATARI_FTP_0693.zip
/
ATARI_FTP_0693
/
Mint
/
mintman4.zoo
/
mintman
/
catman.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-15
|
27KB
|
857 lines
/******************************************************************/
/* catman.c - a simple-minded catman program for MiNT and TOS */
/* Copyright (c) 1992 by HPP Biersma (schuller@dutiag.tudelft.nl) */
/* This program comes under the GNU public license - */
/* see the file "copying" for details. */
/******************************************************************/
/* bugs: - not UN*X compatible, either in source-code or behavior */
/* - string operations are not safe, ie not limits checked */
/******************************************************************/
/* version: 0.2 (second released version), December 15, 1992 */
/* written for: - GCC version 2.3.1, patchlevel 1 */
/* - mintlib patchlevel 25 */
/* compile with: gcc -o catman.ttp catman.c -mbaserel -mpcrel -O2 */
/******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stat.h>
#include <dirent.h> /* used for opendir(), readdir(), closedir() */
#include <mintbind.h>
/* Comment out the following definitions if you want subprograms */
/* (nroff, less and cat) to get UN*X (not GEMDOS-like) filenames. */
#define SUBPROGRAMS_GROK_GEMDOS_NAMES /* the longest #define yet? */
/* Maximum length of path + file name */
#define NAME_LENGTH 256 /* Note: stacksize must be > (10 * NAME_LENGTH) */
/* Local type definitions */
typedef struct direntry_st
{
char name[NAME_LENGTH];
time_t timestamp;
struct direntry_st *next, *previous;
} direntry_type, *direntry_ptr;
typedef struct whatis_st
{
char line[NAME_LENGTH];
struct whatis_st *next, *previous;
} whatis_type, *whatis_ptr;
/* prototypes for local (static) functions */
static void format_file(const char *mandir, const char *manfile,
const char *catfile_name, const int only_print);
static int format_manpages(const char *mandir, const int sections[9],
const int only_print);
static int update_manfiles(const char *catdir, const char *mandir,
const int only_print);
static direntry_ptr make_direntry(const char *name, const time_t timestamp);
static void destroy_direntry(direntry_ptr destroy);
static void destroy_free_lists(void);
static void make_whatis(const char *mandir);
static void add_to_whatis(whatis_ptr *database, const char *filename,
const char section_code, const char *explanation,
const int catfile);
static void write_whatis_database(const char *mandir, whatis_ptr *database);
static whatis_ptr make_whatis_entry(const char *contents);
static void destroy_whatis_entry(whatis_ptr destroy);
static int get_name_from_catfile(const char *catdir, const char *filename,
char *result);
static int get_name_from_manfile(const char *mandir, const char *filename,
char *result);
static FILE *open_so_file(const char *mandir, const char *so_line);
static int check_directory_name(const char *dirname);
static void build_catdir_name(const char *dirname, const char section_code,
char *catdir_name);
static void build_mandir_name(const char *dirname, const char section_code,
char *mandir_name);
/* Extern and local variables */
static char man_path[NAME_LENGTH] = "/usr/man";
static char macro_package[NAME_LENGTH] = "an";
static direntry_ptr direntry_free_list = NULL;
static whatis_ptr whatis_free_list = NULL;
void main(int argc, char *argv[])
{
char *ptr, *arg_ptr, *manptr, mandir[NAME_LENGTH];
int only_nroff = 0, only_print = 0, only_whatis = 0, sections_set = 0;
int sections[9], counter;
/* Set the search path for the man pages*/
if ((ptr = getenv("MANPATH")) != NULL)
strncpy(man_path, ptr, NAME_LENGTH - 1);
for (counter = 1; counter <= 8; counter++)
sections[counter] = 0;
argv += 1;
ptr = argv[0];
while (argc > 1)
{
if (ptr[0] == '-')
{
/* handle options */
switch(ptr[1])
{
case 'n':
case 'p':
case 'w':
arg_ptr = ptr;
while (*++arg_ptr != 0x00)
{
switch(*arg_ptr)
{
case 'n':
only_nroff = 1;
break;
case 'p':
only_print = 1;
break;
case 'w':
only_whatis = 1;
break;
default:
fprintf(stderr, "catman: no option %s supported\n", ptr);
fprintf(stderr, "usage: catman [-npw] [-M path] [-T macro-package] [sections]\n");
exit(1);
}
} /* End of while (-npw option) */
break;
case 'M':
if (ptr[2] != 0x00)
strncpy(man_path, &(ptr[2]), NAME_LENGTH - 1);
else if (argc > 2)
{
argv += 1;
strncpy(man_path, argv[0], NAME_LENGTH - 1);
argc -= 1;
}
else
{
fprintf(stderr, "catman: -M option needs an argument\n");
exit(1);
}
break;
case 'T':
if (ptr[2] != 0x00)
strncpy(macro_package, &(ptr[2]), NAME_LENGTH - 1);
else if (argc > 2)
{
argv += 1;
strncpy(macro_package, argv[0], NAME_LENGTH - 1);
argc -= 1;
}
else
{
fprintf(stderr, "catman: -T option needs an argument\n");
exit(1);
}
break;
default:
fprintf(stderr, "catman: no option %s supported\n", ptr);
fprintf(stderr, "usage: catman [-npw] [-M path] [-T macro-package] [sections]\n");
exit(1);
}
} /* end of if: argument is option */
else
{
/* Not an option: must be section code (1..8) */
do
{
if ((*ptr < '1') || (*ptr > '8'))
{
fprintf(stderr, "catman: section argument must be in 1..8\n");
exit(1);
}
sections_set = 1;
sections[*ptr - ('1' - 1)] = 1;
ptr += 1;
} while (*ptr != 0x00);
} /* end of else (not an option) */
argc -= 1;
argv += 1;
ptr = argv[0];
} /* end of while (command line arguments left) */
if (sections_set == 0)
for (counter = 1; counter <= 8; counter++)
sections[counter] = 1;
/* walk along manual path and format pages, build whatis database */
ptr = man_path;
while (*ptr != 0x00)
{
int did_format;
/* Copy one directory from the manual search path into mandir */
manptr = mandir;
while ((*ptr != 0x00) && (*ptr != ';') && (*ptr != ','))
*manptr++ = *ptr++;
*manptr = 0x00;
if (*ptr != 0x00)
ptr += 1;
if (check_directory_name(mandir) == 0)
{
fprintf(stderr, "catman: directory %s on search path not found\n",
mandir);
continue; /* go on to next part of manual search path */
}
if (only_whatis == 0)
did_format = format_manpages(mandir, sections, only_print);
else
did_format = 0;
if ((only_nroff == 0) &&
((only_whatis == 1) || (did_format == 1)))
{
if (only_print == 0)
make_whatis(mandir);
else
fprintf(stdout, "makewhatis %s\n", mandir);
}
} /* end of while (walk along manual search path) */
destroy_free_lists();
exit(0);
} /* End of main() */
/* Format all manpages that need updating from specific sections in */
/* a manual directory. Print instead of doing if only_print is set. */
static int format_manpages(const char *dir, const int sections[9],
const int only_print)
{
int counter, changes_made;
changes_made = 0;
for (counter = 1; counter <= 8; counter++)
{
if (sections[counter] == 1)
{
int catdir_exists, mandir_exists;
char catdir_name[NAME_LENGTH], mandir_name[NAME_LENGTH];
build_catdir_name(dir, counter + ('1' - 1), catdir_name);
catdir_exists = check_directory_name(catdir_name);
build_mandir_name(dir, counter + ('1' - 1), mandir_name);
mandir_exists = check_directory_name(mandir_name);
if ((catdir_exists == 1) && (mandir_exists == 1))
changes_made |= update_manfiles(catdir_name, mandir_name, only_print);
} /* End of if (section must be searched and formatted) */
} /* End of for (all sections) */
return(changes_made);
} /* End of format_manpages() */
/* Update the files in the catdir directory from the files in the */
/* mandir directory. Print instead of doing if only_print is set. */
static int update_manfiles(const char *catdir, const char *mandir,
const int only_print)
{
DIR *dir;
struct dirent *this_entry;
direntry_ptr direntry_list;
int changes_made;
direntry_list = NULL;
changes_made = 0;
if ((dir = opendir(catdir)) == NULL)
{
/* Note that the existence of the directory has been checked before */
fprintf(stderr, "catman: could not open directory %s\n", catdir);
exit(1);
}
readdir(dir); /* skip over `.' */
readdir(dir); /* skip over `..' */
while ((this_entry = readdir(dir)) != NULL)
{
struct stat this_stat;
direntry_ptr new;
char full_name[NAME_LENGTH];
strcpy(full_name, catdir);
strcat(full_name, "/");
strcat(full_name, this_entry->d_name);
stat(full_name, &this_stat);
new = make_direntry(this_entry->d_name, this_stat.st_mtime);
if (direntry_list == NULL)
direntry_list = new;
else
{
new->next = direntry_list;
direntry_list->previous = new;
direntry_list = new;
}
} /* End of while (not out of files in catdir) */
closedir(dir);
if ((dir = opendir(mandir)) == NULL)
{
/* Note that the existence of the directory has been checked before */
fprintf(stderr, "catman: could not open directory %s\n", mandir);
exit(1);
}
readdir(dir); /* skip over `.' */
readdir(dir); /* skip over `..' */
while ((this_entry = readdir(dir)) != NULL)
{
struct stat this_stat;
char full_man_name[NAME_LENGTH], full_cat_name[NAME_LENGTH];
direntry_ptr current;
int done;
strncpy(full_man_name, mandir, NAME_LENGTH - 1);
strcat(full_man_name, "/");
strcat(full_man_name, this_entry->d_name);
strncpy(full_cat_name, catdir, NAME_LENGTH - 1);
strcat(full_cat_name, "/");
strcat(full_cat_name, this_entry->d_name);
current = direntry_list;
done = 0;
while ((current != NULL) && (done == 0))
{
if (strncmp(current->name, this_entry->d_name, NAME_LENGTH - 1) == 0)
{
stat(full_man_name, &this_stat);
if (this_stat.st_mtime >= current->timestamp)
{
format_file(mandir, this_entry->d_name, full_cat_name, only_print);
changes_made = 1;
}
if (current == direntry_list)
{
direntry_list = direntry_list->next;
if (direntry_list != NULL)
direntry_list->previous = NULL;
}
else
{
if (current->next != NULL)
current->next->previous = current->previous;
current->previous->next = current->next;
}
destroy_direntry(current);
done = 1;
} /* End of if (current name found) */
else
current = current->next;
} /* End of while (not end of direntry_list) */
if (done == 0)
{
/* Formatted file does not exist in cat directory */
format_file(mandir, this_entry->d_name, full_cat_name, only_print);
changes_made = 1;
}
} /* End of while (not end of mandir) */
closedir(dir);
/* Destroy the list of directory entries */
while (direntry_list != NULL)
{
direntry_ptr ptr;
ptr = direntry_list;
direntry_list = direntry_list->next;
destroy_direntry(ptr);
}
return(changes_made);
} /* End of update_manfiles() */
static direntry_ptr make_direntry(const char *name, const time_t timestamp)
{
direntry_ptr ptr;
if (direntry_free_list != NULL)
{
ptr = direntry_free_list;
direntry_free_list = direntry_free_list->next;
}
else if ((ptr = malloc(sizeof(direntry_type))) == NULL)
{
fprintf(stderr, "catman: malloc() failed in make_direntry()\n");
exit(1);
}
ptr->next = ptr->previous = NULL;
strncpy(ptr->name, name, NAME_LENGTH - 1);
ptr->timestamp = timestamp;
return(ptr);
} /* End of make_direntry() */
/* Destroy a direntry (put in free-list) */
static void destroy_direntry(direntry_ptr destroy)
{
destroy->next = direntry_free_list;
direntry_free_list = destroy;
} /* End of destroy_direntry() */
/* Destroy all the free-lists the program uses */
static void destroy_free_lists(void)
{
while (direntry_free_list != NULL)
{
direntry_ptr ptr;
ptr = direntry_free_list;
direntry_free_list = direntry_free_list->next;
free(ptr);
}
while (whatis_free_list != NULL)
{
whatis_ptr ptr;
ptr = whatis_free_list;
whatis_free_list = whatis_free_list->next;
free(ptr);
}
} /* End of destroy_free_lists() */
/* Build the whatis database in a main manual directory */
static void make_whatis(const char *mandir_name)
{
DIR *man_dir, *this_dir;
struct dirent *this_entry;
whatis_ptr database;
database = NULL;
if ((man_dir = opendir(mandir_name)) == NULL)
{
/* Note that the existence of the directory has been checked before */
fprintf(stderr, "catman: could not open directory %s\n", mandir_name);
exit(1);
}
readdir(man_dir); /* skip over `.' */
readdir(man_dir); /* skip over `..' */
while ((this_entry = readdir(man_dir)) != 0)
{
char section_code, full_name[NAME_LENGTH];
int catdir;
if ((this_entry->d_name[0] == 'c') && (this_entry->d_name[1] == 'a') &&
(this_entry->d_name[2] == 't') && (this_entry->d_name[4] == 0x00) &&
(this_entry->d_name[3] >= '1') && (this_entry->d_name[3] <= '8'))
catdir = 1;
else if ((this_entry->d_name[0] == 'm') && (this_entry->d_name[1] == 'a') &&
(this_entry->d_name[2] == 'n') && (this_entry->d_name[4] == 0x00) &&
(this_entry->d_name[3] >= '1') && (this_entry->d_name[3] <= '8'))
catdir = 0;
else
continue; /* name doesn't match cat? or man?: go on to next entry */
strcpy(full_name, mandir_name);
strcat(full_name, "/");
strcat(full_name, this_entry->d_name);
if (check_directory_name(full_name) != 1)
continue; /* not a directory: go on to next entry in while */
section_code = this_entry->d_name[3];
if ((this_dir = opendir(full_name)) == NULL)
{
/* Note that the existence of the directory has been checked before */
fprintf(stderr, "catman: could not open directory %s\n", full_name);
exit(1);
}
readdir(this_dir); /* skip over `.' */
readdir(this_dir); /* skip over `.' */
while ((this_entry = readdir(this_dir)) != NULL)
{
char result[NAME_LENGTH];
int ok;
if (catdir == 0)
ok = get_name_from_manfile(full_name, this_entry->d_name, result);
else
ok = get_name_from_catfile(full_name, this_entry->d_name, result);
if (ok == 1)
add_to_whatis(&database, this_entry->d_name, section_code, result,
catdir);
} /* End of while (not out of entries in cat/man dir) */
closedir(this_dir);
} /* End of while (not out of entries in manual directory) */
closedir(man_dir);
write_whatis_database(mandir_name, &database);
} /* End of make_whatis() */
/* Add a line to the whatis database. Lines from the unformatted manpage */
/* are preferred (catfile == 0). Lines are sorted alphabetically. */
static void add_to_whatis(whatis_ptr *database, const char *filename,
const char section_code, const char *explanation,
const int catfile)
{
char buffer[NAME_LENGTH], name[NAME_LENGTH], *ptr;
size_t size;
whatis_ptr current, previous;
/* Find the name of the manpage */
strcpy(name, filename);
ptr = name;
while (*ptr != 0x00)
{
if (*ptr == '.')
*ptr = 0x00;
else
ptr += 1;
}
*ptr++ = ' ';
*ptr++ = '(';
*ptr++ = section_code;
*ptr++ = ')';
while ((ptr - name) < 16)
*ptr++ = ' ';
*ptr++ = 0x00;
size = strlen(name);
strcpy(buffer, name);
strcat(buffer, " ");
strcat(buffer, explanation);
/* Search for the correct place in the whatis database */
if (*database == NULL)
{
*database = make_whatis_entry(buffer);
return;
}
if (strncmp(name, (*database)->line, size) < 0)
{
/* new entry fits in before current start of list */
current = make_whatis_entry(buffer);
current->next = *database;
(*database)->previous = current;
*database = current;
return;
}
current = *database;
previous = NULL;
while (current != NULL)
{
int result;
result = strncmp(name, current->line, size);
if (result == 0)
{
if (catfile == 1)
return; /* previous entry is from manfile and wins */
else
{
/* new entry overwrites old one from catfile */
strcpy(current->line, buffer);
return;
}
} /* end of if (result == 0: names are equal) */
else if (result < 0)
{
/* Note that this cannot happen on the first item in the list */
whatis_ptr new;
new = make_whatis_entry(buffer);
new->next = current;
new->previous = previous;
current->previous = new;
previous->next = new;
return;
} /* end of else if (result < 0: name fits before current) */
else
{
previous = current;
current = current->next;
} /* end of else (result > 0: name first after current) */
} /* End of while (current != NULL) */
current = make_whatis_entry(buffer);
previous->next = current;
current->previous = previous;
} /* End of add_to_whatis() */
static void write_whatis_database(const char *mandir, whatis_ptr *database)
{
FILE *whatis;
char name[NAME_LENGTH];
strcpy(name, mandir);
strcat(name, "/whatis");
if ((whatis = fopen(name, "w")) == NULL)
{
fprintf(stderr, "catman: could not open file %s\n", name);
exit(1);
}
while (*database != NULL)
{
whatis_ptr ptr;
ptr = *database;
*database = (*database)->next;
fputs(ptr->line, whatis);
destroy_whatis_entry(ptr);
}
fclose(whatis);
} /* End of write_whatis_database() */
/* Make a new whatis record */
static whatis_ptr make_whatis_entry(const char *contents)
{
whatis_ptr result;
if (whatis_free_list != NULL)
{
result = whatis_free_list;
whatis_free_list = whatis_free_list->next;
}
else if ((result = malloc(sizeof(whatis_type))) == NULL)
{
fprintf(stderr, "catman: malloc() failed in make_whatis_entry()\n");
exit(1);
}
strcpy(result->line, contents);
result->next = result->previous = NULL;
return(result);
} /* End of make_whatis_entry() */
/* Destroy a whatis record (add to free-list) */
static void destroy_whatis_entry(whatis_ptr destroy)
{
destroy->next = whatis_free_list;
whatis_free_list = destroy;
} /* End of destroy_whatis_entry() */
/* Extract the man page name from a man file in a cat? directory */
static int get_name_from_catfile(const char *catdir, const char *filename,
char *result)
{
FILE *catfile;
int lines_read;
char full_name[NAME_LENGTH], buffer[NAME_LENGTH], *ptr;
strcpy(full_name, catdir);
strcat(full_name, "/");
strcat(full_name, filename);
if ((catfile = fopen(full_name, "r")) == NULL)
{
/* Note that the existence of the file has been checked before */
fprintf(stderr, "catman: could not open file %s\n", full_name);
return(0); /* failure */
}
lines_read = 0;
while (!feof(catfile) && (lines_read <= 15))
{
fgets(buffer, NAME_LENGTH - 1, catfile);
lines_read += 1;
if ((strstr(buffer, "NAME") != NULL) && !feof(catfile))
{
fgets(buffer, NAME_LENGTH - 1, catfile);
/* Set ptr to the start of the explanation (minus char) */
ptr = buffer;
while ((*ptr != 0x00) && (*ptr != '-'))
ptr += 1;
strcpy(result, ptr);
fclose(catfile);
return(1);
}
}
fclose(catfile);
return(0); /* failure */
} /* End of get_name_from_catfile() */
/* Extract the man page name from a man file in a man? directory */
static int get_name_from_manfile(const char *mandir, const char *filename,
char *result)
{
FILE *manfile;
char full_name[NAME_LENGTH], buffer[NAME_LENGTH], *ptr;
int first_line, no_redirections;
strcpy(full_name, mandir);
strcat(full_name, "/");
strcat(full_name, filename);
if ((manfile = fopen(full_name, "r")) == NULL)
{
/* Note that the existence of the file has been checked before */
fprintf(stderr, "catman: could not open file %s\n", full_name);
return(0); /* failure */
}
first_line = 1;
no_redirections = 0;
while (!feof(manfile))
{
fgets(buffer, NAME_LENGTH - 1, manfile);
if (first_line == 1)
{
if ((buffer[0] == '.') && (buffer[1] == 's') && (buffer[2] == 'o'))
{
fclose(manfile);
if (++no_redirections > 5)
{
fprintf(stderr, "catman: too many redirections from file %s\n",
full_name);
return(0); /* failure */
}
if ((manfile = open_so_file(mandir, buffer)) == NULL)
{
fprintf(stderr, "catman: redirection from file %s failed\n",
full_name);
return(0); /* failure */
}
} /* End of if (line start with .so) */
else
first_line = 0;
} /* End of if (first line) */
if ((strncmp(buffer, ".SH NAME", 7) == 0) && !feof(manfile))
{
fgets(buffer, NAME_LENGTH - 1, manfile);
/* Set ptr to the start of the explanation (minus char) */
ptr = buffer;
while ((*ptr != 0x00) && (*ptr != '-'))
ptr += 1;
strcpy(result, ptr);
fclose(manfile);
return(1); /* success */
}
} /* End of while (not end of file and not found) */
fclose(manfile);
return(0); /* failure */
} /* End of get_name_from_manfile() */
/* Find and open a file from a .so redirection in a manfile */
static FILE *open_so_file(const char *mandir, const char *so_line)
{
char name[NAME_LENGTH], full_name[NAME_LENGTH], *ptr1, *ptr2;
strcpy(name, &(so_line[3])); /* Right after the .so */
/* ptr1 gets set to the start of the filename */
ptr1 = name;
while ((*ptr1 == ' ') || (*ptr1 == '\t'))
ptr1 += 1;
ptr2 = ptr1;
while ((*ptr2 != 0x00) && (*ptr2 != ' ') && (*ptr2 != '\t') &&
(*ptr2 != '\n') && (*ptr2 != '\r'))
ptr2 += 1;
*ptr2 = 0x00;
strcpy(full_name, mandir);
strcat(full_name, "/");
strcat(full_name, ptr1);
return(fopen(full_name, "r"));
} /* End of open_so_file() */
/* Format (nroff) a file and write the result to another file */
static void format_file(const char *mandir, const char *manfile,
const char *catfile, const int only_print)
{
char command_line[NAME_LENGTH], cwd[NAME_LENGTH];
#ifdef SUBPROGRAMS_GROK_GEMDOS_NAMES
char dosname[NAME_LENGTH];
#endif
getcwd(cwd, NAME_LENGTH);
if (chdir(mandir) != 0)
{
/* Note that the existence of the directory has been checked before */
fprintf(stderr, "catman: change directory to %s failed\n", mandir);
exit(1);
}
strcpy(command_line, "nroff -m");
strcat(command_line, macro_package);
strcat(command_line, " ");
#ifdef SUBPROGRAMS_GROK_GEMDOS_NAMES
_unx2dos(manfile, dosname); /* send nroff a proper GEMDOS name */
strcat(command_line, dosname);
#else
strcat(command_line, manfile);
#endif
strcat(command_line, " >");
#ifdef SUBPROGRAMS_GROK_GEMDOS_NAMES
_unx2dos(catfile, dosname); /* redirect to a proper GEMDOS name */
strcat(command_line, dosname);
#else
strcat(command_line, catfile);
#endif
if (only_print == 0)
{
fprintf(stderr, "Formatting file %s. Wait...", manfile);
if (system(command_line) == 0) /* successful execution */
{
fprintf(stderr, "Done\n");
return;
}
else
{
fprintf(stderr, "Aborted (sorry)\n");
exit(1);
}
}
else
{
fprintf(stdout, command_line);
fprintf(stdout, "\n");
}
if (chdir(cwd) != 0)
{
fprintf(stderr, "catman: cannot change back to directory %s\n", cwd);
exit(1);
}
} /* End of format_file() */
/* Check if a dirname is a valid directory */
static int check_directory_name(const char *dirname)
{
struct stat dir_stat;
if (stat(dirname, &dir_stat) == -1)
return(0);
else if (dir_stat.st_mode & S_IFDIR == 0)
{
fprintf(stderr, "catman: %s is not a directory\n", dirname);
return(0);
}
else
return(1);
} /* End of check_directory_name() */
static void build_catdir_name(const char *dirname, const char section_code,
char *catdir_name)
{
static char extension[] = "/cat0";
strcpy(catdir_name, dirname);
extension[4] = section_code;
strcat(catdir_name, extension);
} /* End of build_catdir_name() */
/* Build the name of man dir #section_code within the man dir */
static void build_mandir_name(const char *dirname, const char section_code,
char *mandir_name)
{
static char extension[] = "/man0";
strcpy(mandir_name, dirname);
extension[4] = section_code;
strcat(mandir_name, extension);
} /* End of build_mandir_name() */