Replacement for man(1) (part 2 of 2)

John W. Eaton jwe at che.utexas.edu
Mon Jan 7 08:26:25 AEST 1991


-------------------------------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 <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 2)."
# Contents:  man-1.0/glob.c man-1.0/man.c
# Wrapped by jwe at andy.che.utexas.edu on Sun Jan  6 15:10:31 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'man-1.0/glob.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'man-1.0/glob.c'\"
else
echo shar: Extracting \"'man-1.0/glob.c'\" \(12628 characters\)
sed "s/^X//" >'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 <sys/types.h>
X
X#if defined (SYSVr3) || defined (DIRENT)
X#  include <dirent.h>
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 <sys/ndir.h>
X#  else
X#    if defined (SYSV)
X#      include "ndir.h"
X#     else
X#      include <sys/dir.h>
X#    endif
X#  endif
X#endif	/* SYSVr3 or DIRENT.  */
X
X#if defined (NeXT)
X#include <string.h>
X#else
X#if defined (SYSV)
X#include <memory.h>
X#include <string.h>
X#define bcopy(s, d, n) ((void) memcpy ((d), (s), (n)))
X#define rindex	strrchr
X
X#else /* not SYSV */
X#include <strings.h>
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 at che.utexas.edu
X * Department of Chemical Engineering
X * The University of Texas at Austin
X * Austin, Texas  78712
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/file.h>
X#include <signal.h>
X#include "config.h"
X#include "gripes.h"
X#include "version.h"
X
X#ifdef STD_HEADERS
X#include <stdlib.h>
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



More information about the Alt.sources mailing list