Path: utzoo!utgpu!cs.utexas.edu!ut-emx!che.utexas.edu From: jwe@che.utexas.edu (John W. Eaton) Newsgroups: alt.sources Subject: Replacement for man(1) (part 2 of 2) Message-ID: <42183@ut-emx.uucp> Date: 6 Jan 91 21:26:25 GMT Sender: news@ut-emx.uucp Reply-To: jwe@che.utexas.edu (John W. Eaton) Distribution: alt Organization: University of Texas at Austin Lines: 1575 -------------------------------cut here------------------------------- #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'man-1.0/glob.c' <<'END_OF_FILE' X/* File-name wildcard pattern matching for GNU. X Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc. X X This program is free software; you can redistribute it and/or modify X it under the terms of the GNU General Public License as published by X the Free Software Foundation; either version 1, or (at your option) X any later version. X X This program is distributed in the hope that it will be useful, X but WITHOUT ANY WARRANTY; without even the implied warranty of X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the X GNU General Public License for more details. X X You should have received a copy of the GNU General Public License X along with this program; if not, write to the Free Software X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ X X/* To whomever it may concern: I have never seen the code which most X Unix programs use to perform this function. I wrote this from scratch X based on specifications for the pattern matching. --RMS. */ X X#if defined (SYSV) && !defined (Xenix) X# define SYSVr3 X#endif X X#include X X#if defined (SYSVr3) || defined (DIRENT) X# include X# define direct dirent X# define D_NAMLEN(d) strlen((d)->d_name) X#else X# define D_NAMLEN(d) ((d)->d_namlen) X# if defined (xenix) X# include X# else X# if defined (SYSV) X# include "ndir.h" X# else X# include X# endif X# endif X#endif /* SYSVr3 or DIRENT. */ X X#if defined (NeXT) X#include X#else X#if defined (SYSV) X#include X#include X#define bcopy(s, d, n) ((void) memcpy ((d), (s), (n))) X#define rindex strrchr X X#else /* not SYSV */ X#include X Xextern void bcopy (); X#endif /* not SYSV */ X#endif /* not NeXT */ X Xextern char *malloc (), *realloc (); Xextern void free (); X X#ifndef NULL X#define NULL 0 X#endif X X/* Global variable which controls whether or not * matches .*. X Non-zero means don't match .*. */ Xint noglob_dot_filenames = 1; X X Xstatic int glob_match_after_star (); X X/* Return nonzero if PATTERN has any special globbing chars in it. */ Xint Xglob_pattern_p (pattern) X char *pattern; X{ X register char *p = pattern; X register char c; X X while ((c = *p++) != '\0') X switch (c) X { X case '?': X case '[': X case '*': X return 1; X X case '\\': X if (*p++ == '\0') X return 0; X } X X return 0; X} X X/* Match the pattern PATTERN against the string TEXT; X return 1 if it matches, 0 otherwise. X X A match means the entire string TEXT is used up in matching. X X In the pattern string, `*' matches any sequence of characters, X `?' matches any character, [SET] matches any character in the specified set, X [!SET] matches any character not in the specified set. X X A set is composed of characters or ranges; a range looks like X character hyphen character (as in 0-9 or A-Z). X [0-9a-zA-Z_] is the set of characters allowed in C identifiers. X Any other character in the pattern must be matched exactly. X X To suppress the special syntactic significance of any of `[]*?!-\', X and match the character exactly, precede it with a `\'. X X If DOT_SPECIAL is nonzero, X `*' and `?' do not match `.' at the beginning of TEXT. */ X Xint Xglob_match (pattern, text, dot_special) X char *pattern, *text; X int dot_special; X{ X register char *p = pattern, *t = text; X register char c; X X while ((c = *p++) != '\0') X switch (c) X { X case '?': X if (*t == '\0' || (dot_special && t == text && *t == '.')) X return 0; X else X ++t; X break; X X case '\\': X if (*p++ != *t++) X return 0; X break; X X case '*': X if (dot_special && t == text && *t == '.') X return 0; X return glob_match_after_star (p, t); X X case '[': X { X register char c1 = *t++; X int invert; X X if (!c1) X return (0); X X invert = ((*p == '!') || (*p == '^')); X if (invert) X p++; X X c = *p++; X while (1) X { X register char cstart = c, cend = c; X X if (c == '\\') X { X cstart = *p++; X cend = cstart; X } X X if (c == '\0') X return 0; X X c = *p++; X if (c == '-') X { X cend = *p++; X if (cend == '\\') X cend = *p++; X if (cend == '\0') X return 0; X c = *p++; X } X if (c1 >= cstart && c1 <= cend) X goto match; X if (c == ']') X break; X } X if (!invert) X return 0; X break; X X match: X /* Skip the rest of the [...] construct that already matched. */ X while (c != ']') X { X if (c == '\0') X return 0; X c = *p++; X if (c == '\0') X return 0; X else if (c == '\\') X ++p; X } X if (invert) X return 0; X break; X } X X default: X if (c != *t++) X return 0; X } X X return *t == '\0'; X} X X/* Like glob_match, but match PATTERN against any final segment of TEXT. */ X Xstatic int Xglob_match_after_star (pattern, text) X char *pattern, *text; X{ X register char *p = pattern, *t = text; X register char c, c1; X X while ((c = *p++) == '?' || c == '*') X if (c == '?' && *t++ == '\0') X return 0; X X if (c == '\0') X return 1; X X if (c == '\\') X c1 = *p; X else X c1 = c; X X while (1) X { X if ((c == '[' || *t == c1) && glob_match (p - 1, t, 0)) X return 1; X if (*t++ == '\0') X return 0; X } X} X X/* Return a vector of names of files in directory DIR X whose names match glob pattern PAT. X The names are not in any particular order. X Wildcards at the beginning of PAT do not match an initial period. X X The vector is terminated by an element that is a null pointer. X X To free the space allocated, first free the vector's elements, X then free the vector. X X Return 0 if cannot get enough memory to hold the pointer X and the names. X X Return -1 if cannot access directory DIR. X Look in errno for more information. */ X Xchar ** Xglob_vector (pat, dir) X char *pat; X char *dir; X{ X struct globval X { X struct globval *next; X char *name; X }; X X DIR *d; X register struct direct *dp; X struct globval *lastlink; X register struct globval *nextlink; X register char *nextname; X unsigned int count; X int lose; X register char **name_vector; X register unsigned int i; X X d = opendir (dir); X if (d == NULL) X return (char **) -1; X X lastlink = 0; X count = 0; X lose = 0; X X /* Scan the directory, finding all names that match. X For each name that matches, allocate a struct globval X on the stack and store the name in it. X Chain those structs together; lastlink is the front of the chain. */ X while (1) X { X dp = readdir (d); X if (dp == NULL) X break; X if (dp->d_ino != 0 X && glob_match (pat, dp->d_name, noglob_dot_filenames)) X { X nextlink = (struct globval *) alloca (sizeof (struct globval)); X nextlink->next = lastlink; X nextname = (char *) malloc (D_NAMLEN(dp) + 1); X if (nextname == NULL) X { X lose = 1; X break; X } X lastlink = nextlink; X nextlink->name = nextname; X bcopy (dp->d_name, nextname, D_NAMLEN(dp) + 1); X ++count; X } X } X (void) closedir (d); X X if (!lose) X { X name_vector = (char **) malloc ((count + 1) * sizeof (char *)); X lose |= name_vector == NULL; X } X X /* Have we run out of memory? */ X if (lose) X { X /* Here free the strings we have got. */ X while (lastlink) X { X free (lastlink->name); X lastlink = lastlink->next; X } X return NULL; X } X X /* Copy the name pointers from the linked list into the vector. */ X for (i = 0; i < count; ++i) X { X name_vector[i] = lastlink->name; X lastlink = lastlink->next; X } X X name_vector[count] = NULL; X return name_vector; X} X X/* Return a new array which is the concatenation X of each string in ARRAY to DIR. */ X Xstatic char ** Xglob_dir_to_array (dir, array) X char *dir, **array; X{ X register unsigned int i, l; X int add_slash; X char **result; X X l = strlen (dir); X if (l == 0) X return array; X X add_slash = dir[l - 1] != '/'; X X i = 0; X while (array[i] != NULL) X ++i; X X result = (char **) malloc ((i + 1) * sizeof (char *)); X if (result == NULL) X return NULL; X X for (i = 0; array[i] != NULL; i++) X { X result[i] = (char *) malloc (l + (add_slash ? 1 : 0) X + strlen (array[i]) + 1); X if (result[i] == NULL) X return NULL; X sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]); X } X result[i] = NULL; X X /* Free the input array. */ X for (i = 0; array[i] != NULL; i++) X free (array[i]); X free ((char *) array); X X return result; X} X X/* Do globbing on PATHNAME. Return an array of pathnames that match, X marking the end of the array with a null-pointer as an element. X If no pathnames match, then the array is empty (first element is null). X If there isn't enough memory, then return NULL. X If a file system error occurs, return -1; `errno' has the error code. */ Xchar ** Xglob_filename (pathname) X char *pathname; X{ X char **result; X unsigned int result_size; X char *directory_name, *filename; X unsigned int directory_len; X X result = (char **) malloc (sizeof (char *)); X result_size = 1; X if (result == NULL) X return NULL; X X result[0] = NULL; X X /* Find the filename. */ X filename = rindex (pathname, '/'); X if (filename == NULL) X { X filename = pathname; X directory_name = ""; X directory_len = 0; X } X else X { X directory_len = (filename - pathname) + 1; X directory_name = (char *) alloca (directory_len + 1); X X bcopy (pathname, directory_name, directory_len); X directory_name[directory_len] = '\0'; X ++filename; X } X X /* If directory_name contains globbing characters, then we X have to expand the previous levels. Just recurse. */ X if (glob_pattern_p (directory_name)) X { X char **directories; X register unsigned int i; X X if (directory_name[directory_len - 1] == '/') X directory_name[directory_len - 1] = '\0'; X X directories = glob_filename (directory_name); X X if (directories == NULL) X goto memory_error; X else if ((int) directories == -1) X return (char **) -1; X else if (*directories == NULL) X { X free ((char *) directories); X return (char **) -1; X } X X /* We have successfully globbed the preceding directory name. X For each name in DIRECTORIES, call glob_vector on it and X FILENAME. Concatenate the results together. */ X for (i = 0; directories[i] != NULL; ++i) X { X char **temp_results = glob_vector (filename, directories[i]); X X /* Handle error cases. */ X if (temp_results == NULL) X goto memory_error; X else if (temp_results == (char **)-1) X /* This filename is probably not a directory. Ignore it. */ X ; X else X { X char **array = glob_dir_to_array (directories[i], temp_results); X register unsigned int l; X X l = 0; X while (array[l] != NULL) X ++l; X X result = X (char **)realloc (result, (result_size + l) * sizeof (char *)); X X if (result == NULL) X goto memory_error; X X for (l = 0; array[l] != NULL; ++l) X result[result_size++ - 1] = array[l]; X X result[result_size - 1] = NULL; X X /* Note that the elements of ARRAY are not freed. */ X free ((char *) array); X } X } X /* Free the directories. */ X for (i = 0; directories[i]; i++) X free (directories[i]); X X free ((char *) directories); X X return result; X } X X /* If there is only a directory name, return it. */ X if (*filename == '\0') X { X result = (char **) realloc ((char *) result, 2 * sizeof (char *)); X if (result == NULL) X return NULL; X result[0] = (char *) malloc (directory_len + 1); X if (result[0] == NULL) X goto memory_error; X bcopy (directory_name, result[0], directory_len + 1); X result[1] = NULL; X return result; X } X else X { X /* Otherwise, just return what glob_vector X returns appended to the directory name. */ X char **temp_results = glob_vector (filename, X (directory_len == 0 X ? "." : directory_name)); X X if (temp_results == NULL || temp_results == (char **)-1) X return temp_results; X X return glob_dir_to_array (directory_name, temp_results); X } X X memory_error:; X if (result != NULL) X { X register unsigned int i; X for (i = 0; result[i] != NULL; ++i) X free (result[i]); X free ((char *) result); X } X return NULL; X} X X#ifdef TEST X Xmain (argc, argv) X int argc; X char **argv; X{ X unsigned int i; X X for (i = 1; i < argc; ++i) X { X char **value = glob_filename (argv[i]); X if (value == NULL) X puts ("Out of memory."); X else if ((int) value == -1) X perror (argv[i]); X else X for (i = 0; value[i] != NULL; i++) X puts (value[i]); X } X X exit (0); X} X#endif /* TEST. */ X X END_OF_FILE if test 12628 -ne `wc -c <'man-1.0/glob.c'`; then echo shar: \"'man-1.0/glob.c'\" unpacked with wrong size! fi # end of 'man-1.0/glob.c' fi if test -f 'man-1.0/man.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'man-1.0/man.c'\" else echo shar: Extracting \"'man-1.0/man.c'\" \(19322 characters\) sed "s/^X//" >'man-1.0/man.c' <<'END_OF_FILE' X/* X * man.c X * X * Copyright (c) 1991, John W. Eaton. X * X * You may distribute under the terms of the GNU General Public X * License as specified in the README file that comes with the man 1.0 X * distribution. X * X * John W. Eaton X * jwe@che.utexas.edu X * Department of Chemical Engineering X * The University of Texas at Austin X * Austin, Texas 78712 X */ X X#include X#include X#include X#include X#include X#include X#include X#include "config.h" X#include "gripes.h" X#include "version.h" X X#ifdef STD_HEADERS X#include X#else Xextern char *malloc (); Xextern char *getenv (); Xextern void free (); Xextern int system (); Xextern int strcmp (); Xextern int strncmp (); Xextern int exit (); Xextern int fflush (); Xextern int fprintf (); Xextern FILE *fopen (); Xextern int fclose (); X#ifdef CHARSPRINTF Xextern char *sprintf (); X#else Xextern int sprintf (); X#endif X#endif X Xextern char *strdup (); X Xextern char **glob_vector (); Xextern int access (); Xextern int unlink (); Xextern int system (); Xextern int stat (); X Xchar *prognam; Xstatic char *pager; Xstatic char *manp; Xstatic char *manpathlist[MAXDIRS]; Xstatic char *section; Xstatic int apropos; Xstatic int whatis; Xstatic int findall; X X#ifdef ALT_SYSTEMS Xstatic int alt_system; Xstatic char *alt_system_name; X#endif X X#ifdef HAS_TROFF Xstatic int troff; X#endif X Xint debug; X Xint Xmain (argc, argv) X int argc; X char **argv; X{ X int status = 0; X char *nextarg; X char *tmp; X extern int optind; X extern char *mkprogname (); X char *is_section (); X void man_getopt (); X void do_apropos (); X void do_whatis (); X int man (); X X prognam = mkprogname (argv[0]); X X man_getopt (argc, argv); X X if (optind == argc) X gripe_no_name (NULL); X X if (optind == argc - 1) X { X tmp = is_section (argv[optind]); X X if (tmp != NULL) X gripe_no_name (tmp); X } X X while (optind < argc) X { X nextarg = argv[optind++]; X X /* X * See if this argument is a valid section name. If not, X * is_section returns NULL. X */ X tmp = is_section (nextarg); X X if (tmp != NULL) X { X section = tmp; X X if (debug) X fprintf (stderr, "\nsection: %s\n", section); X X continue; X } X X if (apropos) X do_apropos (nextarg); X else if (whatis) X do_whatis (nextarg); X else X { X status = man (nextarg); X X if (status == 0) X gripe_not_found (nextarg, section); X } X } X return status; X} X X/* X * Get options from the command line and user environment. X */ Xvoid Xman_getopt (argc, argv) X register int argc; X register char **argv; X{ X register int c; X register char *p; X register char *end; X register char **mp; X extern char *optarg; X extern int getopt (); X extern void downcase (); X extern char *manpath (); X void usage (); X X#ifdef HAS_TROFF X#ifdef ALT_SYSTEMS X while ((c = getopt (argc, argv, "M:P:S:adfhkt?")) != EOF) X#else X while ((c = getopt (argc, argv, "M:P:adfhkt?")) != EOF) X#endif X#else X#ifdef ALT_SYSTEMS X while ((c = getopt (argc, argv, "M:P:S:adfhk?")) != EOF) X#else X while ((c = getopt (argc, argv, "M:P:adfhk?")) != EOF) X#endif X#endif X { X switch (c) X { X case 'M': X manp = strdup (optarg); X break; X case 'P': X pager = strdup (optarg); X break; X#ifdef ALT_SYSTEMS X case 'S': X alt_system++; X alt_system_name = strdup (optarg); X break; X#endif X case 'a': X findall++; X break; X case 'd': X debug++; X break; X case 'f': X#ifdef HAS_TROFF X if (troff) X gripe_incompatible ("-f and -t"); X#endif X if (apropos) X gripe_incompatible ("-f and -k"); X whatis++; X break; X case 'k': X#ifdef HAS_TROFF X if (troff) X gripe_incompatible ("-t and -k"); X#endif X if (whatis) X gripe_incompatible ("-f and -k"); X apropos++; X break; X#ifdef HAS_TROFF X case 't': X if (apropos) X gripe_incompatible ("-t and -k"); X if (whatis) X gripe_incompatible ("-t and -f"); X troff++; X break; X#endif X case 'h': X case '?': X default: X usage(); X break; X } X } X X if (pager == NULL || *pager == NULL) X if ((pager = getenv ("PAGER")) == NULL) X pager = strdup (PAGER); X X if (debug) X fprintf (stderr, "\nusing %s as pager\n", pager); X X if (manp == NULL) X { X if ((manp = manpath (0)) == NULL) X gripe_manpath (); X X if (debug) X fprintf (stderr, X "\nsearch path for pages determined by manpath is\n%s\n\n", X manp); X } X X#ifdef ALT_SYSTEMS X if (alt_system_name == NULL || *alt_system_name == NULL) X if ((alt_system_name = getenv ("SYSTEM")) == NULL) X alt_system_name = strdup (alt_system_name); X X downcase (alt_system_name); X#endif X X /* X * Expand the manpath into a list for easier handling. X */ X mp = manpathlist; X for (p = manp ; ; p = end+1) X { X if ((end = strchr (p, ':')) != NULL) X *end = '\0'; X X if (debug) X fprintf (stderr, "adding %s to manpathlist\n", p); X X#ifdef ALT_SYSTEMS X if (alt_system) X { X char buf[BUFSIZ]; X X strcpy (buf, p); X strcat (buf, "/"); X strcat (buf, alt_system_name); X X *mp++ = strdup (buf); X } X#else X *mp++ = strdup (p); X#endif X X if (end == NULL) X break; X } X *mp = NULL; X X} X Xvoid Xusage () X{ X static char usage_string[1024] = "%s, version %s\n\n"; X X#ifdef HAS_TROFF X#ifdef ALT_SYSTEMS X static char s1[] = "usage: %s [-afhkt] [section] [-M path] [-P pager] [-S system] name ...\n\n"; X#else X static char s1[] = "usage: %s [-afhkt] [section] [-M path] [-P pager] name ...\n\n"; X#endif X#else X#ifdef ALT_SYSTEMS X static char s1[] = "usage: %s [-afhk] [section] [-M path] [-P pager] [-S system] name ...\n\n"; X#else X static char s1[] = "usage: %s [-afhk] [section] [-M path] [-P pager] name ...\n\n"; X#endif X#endif X Xstatic char s2[] = " a : find all matching entries\n\ X d : print gobs of debugging information\n\ X f : same as whatis(1)\n\ X h : print this help message\n\ X k : same as apropos(1)\n"; X X#ifdef HAS_TROFF X static char s3[] = " t : use troff to format pages for printing\n"; X#endif X X static char s4[] = "\n M path : set search path for manual pages to `path'\n\ X P pager : use program `pager' to display pages\n"; X X#ifdef ALT_SYSTEMS X static char s5[] = " S system : search for alternate system's man pages\n"; X#endif X X strcat (usage_string, s1); X strcat (usage_string, s2); X X#ifdef HAS_TROFF X strcat (usage_string, s3); X#endif X X strcat (usage_string, s4); X X#ifdef ALT_SYSTEMS X strcat (usage_string, s5); X#endif X X fprintf (stderr, usage_string, prognam, version, prognam); X exit(1); X} X X/* X * Check to see if the argument is a valid section number. If the X * first character of name is a numeral, or the name matches one of X * the sections listed in config.h, we'll assume that it's a section. X * The list of sections in config.h simply allows us to specify oddly X * named directories like .../man3f. Yuk. X */ Xchar * Xis_section (name) X register char *name; X{ X register char **vs; X X for (vs = valid_sections; *vs != NULL; vs++) X if ((strcmp (*vs, name) == NULL) || (isdigit (name[0]))) X return strdup (name); X X return NULL; X} X X/* X * Handle the apropos option. Cheat by using another program. X */ Xvoid Xdo_apropos (name) X register char *name; X{ X int status; X register int len; X register char *command; X X len = strlen (APROPOS) + strlen (name) + 2; X X if ((command = malloc(len)) == NULL) X gripe_alloc (len, "command"); X X sprintf (command, "%s %s", APROPOS, name); X X status = 0; X if (debug) X fprintf (stderr, "\ntrying command: %s\n", command); X else X status = system (command); X X if (status == 127) X gripe_system_command (status); X X free (command); X} X X/* X * Handle the whatis option. Cheat by using another program. X */ Xvoid Xdo_whatis (name) X register char *name; X{ X int status; X register int len; X register char *command; X X len = strlen (WHATIS) + strlen (name) + 2; X X if ((command = malloc(len)) == NULL) X gripe_alloc (len, "command"); X X sprintf (command, "%s %s", WHATIS, name); X X status = 0; X if (debug) X fprintf (stderr, "\ntrying command: %s\n", command); X else X status = system (command); X X if (status == 127) X gripe_system_command (status); X X free (command); X} X X/* X * Search for manual pages. X * X * If preformatted manual pages are supported, look for the formatted X * file first, then the man page source file. If they both exist and X * the man page source file is newer, or only the source file exists, X * try to reformat it and write the results in the cat directory. If X * it is not possible to write the cat file, simply format and display X * the man file. X * X * If preformatted pages are not supported, or the troff option is X * being used, only look for the man page source file. X * X */ Xint Xman (name) X char *name; X{ X register int found; X register int glob; X register char **mp; X register char **sp; X int try_section (); X X found = 0; X X fflush (stdout); X if (section != NULL) X { X for (mp = manpathlist; *mp != NULL; mp++) X { X if (debug) X fprintf (stderr, "\nsearching in %s\n", *mp); X X glob = 0; X X found += try_section (*mp, section, name, glob); X X if (found && !findall) /* i.e. only do this section... */ X return found; X } X } X else X { X for (sp = valid_sections; *sp != NULL; sp++) X { X for (mp = manpathlist; *mp != NULL; mp++) X { X if (debug) X fprintf (stderr, "\nsearching in %s\n", *mp); X X glob = 1; X X found += try_section (*mp, *sp, name, glob); X X if (found && !findall) /* i.e. only do this section... */ X return found; X X } X } X } X return found; X} X X/* X * See if the preformatted man page or the source exists in the given X * section. X */ Xint Xtry_section (path, section, name, glob) X register char *path; X register char *section; X register char *name; X register int glob; X{ X register int found = 0; X register int to_cat; X register int cat; X register char **names; X register char **np; X char **glob_for_file (); X char **make_name (); X char *convert_name (); X char *ultimate_source (); X int display_cat_file (); X int format_and_display (); X X if (debug) X { X if (glob) X fprintf (stderr, "trying section %s with globbing\n", section); X else X fprintf (stderr, "trying section %s without globbing\n", section); X } X X /* X * Look for man page source files. X */ X cat = 0; X if (glob) X names = glob_for_file (path, section, name, cat); X else X names = make_name (path, section, name, cat); X X if ((int) names == -1 || *names == NULL) X /* X * No files match. If we're not using troff and we're supporting X * preformatted pages, see if there's one around that we can X * display. X */ X { X#ifdef HAS_TROFF X if (cat_support && !troff) X#else X if (cat_support) X#endif X { X cat = 1; X if (glob) X names = glob_for_file (path, section, name, cat); X else X names = make_name (path, section, name, cat); X X if ((int) names != -1 && *names != NULL) X { X for (np = names; *np != NULL; np++) X found+= display_cat_file (*np); X } X } X } X else X { X for (np = names; *np != NULL; np++) X { X register char *cat_file = NULL; X register char *man_file; X X man_file = ultimate_source (*np, path); X X#ifdef HAS_TROFF X if (cat_support && !troff) X#else X if (cat_support) X#endif X { X to_cat = 1; X X cat_file = convert_name (man_file, to_cat); X if (debug) X fprintf (stderr, "will try to write %s if needed\n", cat_file); X } X X found += format_and_display (path, man_file, cat_file); X } X } X X return found; X} X X/* X * Change a name of the form ...man/man1/name.1 to ...man/cat1/name.1 X * or a name of the form ...man/cat1/name.1 to ...man/man1/name.1 X */ Xchar * Xconvert_name (name, to_cat) X register char *name; X register int to_cat; X{ X register char *to_name; X register char *t1; X register char *t2 = NULL; X X to_name = strdup (name); X X t1 = strrchr (to_name, '/'); X if (t1 != NULL) X { X *t1 = NULL; X t2 = strrchr (to_name, '/'); X *t1 = '/'; X } X X if (t2 == NULL) X gripe_converting_name (name, to_cat); X X if (to_cat) X { X *(++t2) = 'c'; X *(t2+2) = 't'; X } X else X { X *(++t2) = 'm'; X *(t2+2) = 'n'; X } X X return to_name; X} X X X/* X * Try to find the man page corresponding to the given name. The X * reason we do this with globbing is because some systems have man X * page directories named man3 which contain files with names like X * XtPopup.3Xt. Rather than requiring that this program know about X * all those possible names, we simply try to match things like X * .../man[sect]/name[sect]*. This is *much* easier. X * X * Note that globbing is only done when the section is unspecified. X */ Xchar ** Xglob_for_file (path, section, name, cat) X register char *path; X register char *section; X register char *name; X register int cat; X{ X char pathname[BUFSIZ]; X char **glob_filename (); X char **gf; X X if (cat) X sprintf (pathname, "%s/cat%s/%s.%s*", path, section, name, section); X else X sprintf (pathname, "%s/man%s/%s.%s*", path, section, name, section); X X if (debug) X fprintf (stderr, "globbing %s\n", pathname); X X gf = glob_filename (pathname); X X if (((int) gf == -1 || *gf == NULL) && isdigit (*section)) X { X if (cat) X sprintf (pathname, "%s/cat%s/%s.%c*", path, section, name, *section); X else X sprintf (pathname, "%s/man%s/%s.%c*", path, section, name, *section); X X gf = glob_filename (pathname); X } X return gf; X} X X/* X * Return an un-globbed name in the same form as if we were doing X * globbing. X */ Xchar ** Xmake_name (path, section, name, cat) X register char *path; X register char *section; X register char *name; X register int cat; X{ X register int i = 0; X static char *names[3]; X char buf[BUFSIZ]; X X if (cat) X sprintf (buf, "%s/cat%s/%s.%s", path, section, name, section); X else X sprintf (buf, "%s/man%s/%s.%s", path, section, name, section); X X if (access (buf, R_OK) == 0) X names[i++] = strdup (buf); X X /* X * If we're given a section that looks like `3f', we may want to try X * file names like .../man3/foo.3f as well. This seems a bit X * kludgey to me, but what the hey... X */ X if (section[1] != '\0') X { X if (cat) X sprintf (buf, "%s/cat%c/%s.%s", path, section[0], name, section); X else X sprintf (buf, "%s/man%c/%s.%s", path, section[0], name, section); X X if (access (buf, R_OK) == 0) X names[i++] = strdup (buf); X } X X names[i] = NULL; X X return &names[0]; X} X X/* X * Simply display the preformmated page. X */ Xint Xdisplay_cat_file (file) X register char *file; X{ X int status; X register int found; X char command[BUFSIZ]; X X found = 0; X X if (access (file, R_OK) == NULL) X { X sprintf (command, "%s %s", pager, file); X X status = 0; X if (debug) X fprintf (stderr, "\ntrying command: %s\n", command); X else X status = system (command); X X if (status == 127) X gripe_system_command (status); X else X found++; X } X return found; X} X X/* X * Try to find the ultimate source file. If the first line of the X * current file is not of the form X * X * .so man3/printf.3s X * X * the input file name is returned. X */ Xchar * Xultimate_source (name, path) X char *name; X char *path; X{ X FILE *fp; X char buf[BUFSIZ]; X char ult[BUFSIZ]; X char *beg; X char *end; X X strcpy (ult, name); X strcpy (buf, name); X X next: X X if ((fp = fopen (ult, "r")) == NULL) X return buf; X X if (fgets (buf, BUFSIZ, fp) == NULL) X return ult; X X if (strlen (buf) < 5) X return ult; X X beg = buf; X if (*beg++ == '.' && *beg++ == 's' && *beg++ == 'o') X { X while ((*beg == ' ' || *beg == '\t') && *beg != '\0') X beg++; X X end = beg; X while (*end != ' ' && *end != '\t' && *end != '\n' && *end != '\0') X end++; X X *end = '\0'; X X strcpy (ult, path); X strcat (ult, "/"); X strcat (ult, beg); X X strcpy (buf, ult); X X goto next; X } X X if (debug) X fprintf (stderr, "found ultimate source file %s\n", ult); X X return ult; X} X X/* X * Try to format the man page source and save it, then display it. If X * that's not possible, try to format the man page source and display X * it directly. X * X * Note that in the commands below, the cd is necessary because some X * man pages are one liners like my version of sprintf.3s: X * X * .so man3/printf.3s X */ Xint Xformat_and_display (path, man_file, cat_file) X register char *path; X register char *man_file; X register char *cat_file; X{ X int status; X int mode; X register int found; X FILE *fp; X char command[BUFSIZ]; X int is_newer (); X X found = 0; X X if (access (man_file, R_OK) != 0) X return found; X X#ifdef HAS_TROFF X if (troff || !cat_support) X { X if (troff) X sprintf (command, "(cd %s ; %s %s)", path, troff_command, man_file); X else X sprintf (command, "(cd %s ; %s %s | %s)", path, nroff_command, X man_file, pager); X#else X if (!cat_support) X { X sprintf (command, "(cd %s ; %s %s | %s)", path, nroff_command, X man_file, pager); X#endif X status = 0; X if (debug) X fprintf (stderr, "\ntrying command: %s\n", command); X else X status = system (command); X X if (status == 127) X gripe_system_command (status); X else X found++; X } X else X { X if ((status = is_newer (man_file, cat_file)) == 1 || status == -2) X { X if ((fp = fopen (cat_file, "w")) != NULL) X { X fclose (fp); X unlink (cat_file); X X fprintf (stderr, "Formatting page, please wait...\n"); X X sprintf (command, "(cd %s ; %s %s > %s)", path, X nroff_command, man_file, cat_file); X X signal (SIGINT, SIG_IGN); X X status = 0; X if (debug) X fprintf (stderr, "\ntrying command: %s\n", command); X else X status = system (command); X X if (status == 127) X gripe_system_command (status); X else X found++; X X mode = CATMODE; X chmod (cat_file, mode); X X if (debug) X fprintf (stderr, "mode of %s is now %o\n", cat_file, mode); X X signal (SIGINT, SIG_DFL); X X found = display_cat_file (cat_file); X } X else X { X sprintf (command, "(cd %s ; %s %s | %s)", path, nroff_command, X man_file, pager); X X status = 0; X if (debug) X fprintf (stderr, "\ntrying command: %s\n", command); X else X status = system (command); X X if (status == 127) X gripe_system_command (status); X else X found++; X } X } X else if (access (cat_file, R_OK) == 0) X { X found = display_cat_file (cat_file); X } X } X return found; X} X X/* X * Is file a newer than file b? X * X * case: X * X * a newer than b returns 1 X * a older than b returns 0 X * stat on a fails returns -1 X * stat on b fails returns -2 X * stat on a and b fails returns -3 X */ Xint Xis_newer (fa, fb) X register char *fa; X register char *fb; X{ X struct stat fa_sb; X struct stat fb_sb; X register int fa_stat; X register int fb_stat; X register int status = 0; X X fa_stat = stat (fa, &fa_sb); X if (fa_stat != 0) X status = 1; X X fb_stat = stat (fb, &fb_sb); X if (fb_stat != 0) X status |= 2; X X if (status != 0) X return -status; X X if (fa_sb.st_mtime > fb_sb.st_mtime) X { X status = 1; X X if (debug) X fprintf (stderr, "%s is newer than %s\n", fa, fb); X } X else X { X status = 0; X X if (debug) X fprintf (stderr, "%s is older than %s\n", fa, fb); X } X return status; X} END_OF_FILE if test 19322 -ne `wc -c <'man-1.0/man.c'`; then echo shar: \"'man-1.0/man.c'\" unpacked with wrong size! fi # end of 'man-1.0/man.c' fi echo shar: End of archive 2 \(of 2\). cp /dev/null ark2isdone MISSING="" for I in 1 2 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked both archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0