[net.sources] pman - print parts of preformatted UNIX manual entries

perlman@wanginst.UUCP (Gary Perlman) (06/02/85)

pman allows quick access to specific parts of entries,
rather than printing whole entries.  For example, "pman
who", prints the NAME and SYNOPSIS parts of what "man who"
prints.  Because the output is by section, and so is usually
short, a pipe to a pagination program, like more, is usually
unnecessary, making pman that much faster than man.  There
are options for compressing the output by simple
reformatting, so that for many programs, the basic
information is on one to three lines.  pman makes comparison
of program options a simple exercise. 

A simple system of equivalence classes:
	warnings   = WARNING* STATUS LIMITATION* DIAGNOSTIC*
	           + CAVEAT* BUG* NOTE* RESTRICTION*
	variables  = FILE* ENVRON* VARIABLE*
	details    = DESCRIPTION OPTION* NOTE* COMMENT* COMMAND*
	examples   = EXAMPLE* HINT*
	xrefs      = SEE_ALSO AUTHOR ALGORITHM* REFERENCE*
makes it easier to find sections of interest, despite
variation in section heading conventions.  For example, DEC
ULTRIX documentation avoids BUGS sections by calling them
RESTRICTIONS or LIMITATIONS.

pman is especially useful when conventional section headings
are used extensively.  One unconventional section I find
useful for getting abbreviated on-line help is an OPTIONS
section (accessed with the -o option) with just the command
line options.  I find this section fits nicely right after
the SYNOPSIS section.  Unfortunately, this section is seldom
used.  If you find pman useful, and would like to make it
more useful, you can put an OPTION section into existing
manuals entries. 

Please send comments and changes to me.

Gary Perlman  Wang Institute  Tyngsboro, MA 01879  (617) 649-9731
UUCP: decvax!wanginst!perlman             CSNET: perlman@wanginst

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	pman.1
#	pman.nr
#	pman.c
#	pman.t
#	getopt.c
# This archive created: Sun Jun  2 02:25:35 1985
# By:	Gary Perlman (Wang Institute, Tyngsboro, MA 01879 USA)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(85 characters)'
if test -f 'Makefile'
then
	echo shar: over-writing existing file "'Makefile'"
fi
cat << \SHAR_EOF > 'Makefile'
G=getopt.o
CFLAGS = -O
pman: pman.o $G
	cc $(CFLAGS) -o pman pman.o $G
test:
	pman.t
SHAR_EOF
echo shar: extracting "'pman.1'" '(3833 characters)'
if test -f 'pman.1'
then
	echo shar: over-writing existing file "'pman.1'"
fi
cat << \SHAR_EOF > 'pman.1'
.TH PMAN 1WI "May 27, 1985" "Wang Institute" "UNIX User's Manual"
.SH NAME
pman \- extract selected parts of an on-line manual page
.SH SYNTAX
.B pman
[-abcdehknosvwx] [-+ name] [section] [-] names
.SH DESCRIPTION
.I pman
is used to print one or more parts of a
.I man
page, such as the NAME or EXAMPLE section.
The program allows quick reference to the on-line manual,
showing only parts of interest.
Synonyms are used to avoid overlooking topics.
A part begins with a section name,
and ends with a new part.
A new part is a line beginning with at least with two upper case letters
(except for \fInroff\fR page breaks that may contain the upper case
name of the entry).
Sections are printed in the order they appear in the manual entry,
not in the order requested.
Blank lines are suppressed, and there is an option for extra-compact
output, making pagination by programs like
.I more
unnecessary.
.SH OPTIONS
.PP
The section of the manual (1-8) can be supplied after all the flag options
and before the names.
Otherwise, all sections are searched until an entry is found.
The manual entry can be read from the standard where a single - is placed
instead of a name.
.de OP\"option
.TP
.B -\\$1 \\$2 \\$3
..
.PP
Most option letters correspond to a man page section.
With no options, the -n, -s, and -e options are assumed.
.OP a
Print all entries in a requested section or all sections
of the given name.
This allows searching for more than one version of an entry,
which can happen with local implementations.
This option implies the -h option so that the section is printed.
.OP b
Non-redundant blank lines are printed.
By default, these are removed to compress the output.
.OP c
Compacted output.
With this option,
.I pman
tries to put parts on one line.
This option assumes that text is indented five spaces
and may be upset by tabs in the formatted entry.
.OP h
Print a header with the entry's name and source section.
.SS Sections
.PP
The following options print parts of manual entries
or types of manual entries (such as all sections with warnings).
.OP + name
Add \fBname\fR to the list of printed parts.
This allows access to sections not anticipated by
.I pman,
or using
.I pman
without having to know the options.
.OP d
DESCRIPTION, OPTIONS, NOTES, COMMENTS, COMMANDS
(detail about the entry)
.OP e
EXAMPLES or HINTS
.OP k
KEYWORDS, NAME, or SEE ALSO
.OP n
NAME
(name and purpose of the entry)
.OP o
OPTIONS
(unfortunately, few files use a separate section expressly for
option descriptions)
.OP s
SYNTAX, SYNOPSIS, or USAGE
.OP v
VARIABLES, ENVIRONMENT, or FILES
(special variables or files used by the entry)
.OP w
WARNINGS, BUGS, LIMITATIONS, RESTRICTIONS, DIAGNOSTICS, CAVEATS, NOTES,
and STATUS
.OP x
SEE ALSO, REFERENCES, ALGORITHM, and AUTHOR (cross-references)
.SH EXAMPLES
.de EX
.nf
.ta 2.5i
\fB\\$1	\fR# \\$2
.fi
..
.EX "pman -s echo"                   "SYNTAX from \fIman echo"
.EX "pman -vw 1 man"                 "VARIABLES & WARNINGS from \fIman 1 man\fR"
.EX "pman -+ 7 REQ man"              "REQUESTS section on \fIman\fR macros"
.EX "pman -hd w | sed 's/.^H//g'"    "header & detail unhighlighted"
.fi
.SH FILE
/usr/man/cat?/* (formatted manual entries searched for here)
.SH "SEE ALSO
man(1)
.SH KEYWORDS
help, documentation
.SH AUTHOR
Gary \fIP\fPerl\fPman\fP (based on a shell script by Bob Marcus)
.SH BUGS
.PP
The compacted output may have problems when there are tabs in
the formatted text.
.SH RESTRICTIONS
.PP
.I pman
will not work if sections headings are indented or contain
overstriking to embolden.
The filter: \fBsed 's/.^H//g'\fR can be used with the standard input
option to help with this problem.
.SH STATUS
.PP
I am open to suggestions for enhancements.
Bug fixes and new features are appreciated and will be acknowledged.
.PP
The program has been tested on 4.2 BSD UNIX and System V.
SHAR_EOF
echo shar: extracting "'pman.nr'" '(4442 characters)'
if test -f 'pman.nr'
then
	echo shar: over-writing existing file "'pman.nr'"
fi
cat << \SHAR_EOF > 'pman.nr'



PMAN(1WI)              UNIX User's Manual               PMAN(1WI)



NAME
     pman - extract selected parts of an on-line manual page

SYNTAX
     pman [-abcdehknosvwx] [-+ name] [section] [-] names

DESCRIPTION
     pman is used to print one or more parts of a man page, such
     as the NAME or EXAMPLE section.  The program allows quick
     reference to the on-line manual, showing only parts of
     interest.  Synonyms are used to avoid overlooking topics.  A
     part begins with a section name, and ends with a new part.
     A new part is a line beginning with at least with two upper
     case letters (except for nroff page breaks that may contain
     the upper case name of the entry).  Sections are printed in
     the order they appear in the manual entry, not in the order
     requested.  Blank lines are suppressed, and there is an
     option for extra-compact output, making pagination by pro-
     grams like more unnecessary.

OPTIONS
     The section of the manual (1-8) can be supplied after all
     the flag options and before the names.  Otherwise, all sec-
     tions are searched until an entry is found.  The manual
     entry can be read from the standard where a single - is
     placed instead of a name.

     Most option letters correspond to a man page section.  With
     no options, the -n, -s, and -e options are assumed.

     -a   Print all entries in a requested section or all sec-
          tions of the given name.  This allows searching for
          more than one version of an entry, which can happen
          with local implementations.  This option implies the -h
          option so that the section is printed.

     -b   Non-redundant blank lines are printed.  By default,
          these are removed to compress the output.

     -c   Compacted output.  With this option, pman tries to put
          parts on one line.  This option assumes that text is
          indented five spaces and may be upset by tabs in the
          formatted entry.

     -h   Print a header with the entry's name and source sec-
          tion.

     Sections

     The following options print parts of manual entries or types
     of manual entries (such as all sections with warnings).




Printed 6/2/85            May 27, 1985                          1






PMAN(1WI)              UNIX User's Manual               PMAN(1WI)



     -+ name
          Add name to the list of printed parts.  This allows
          access to sections not anticipated by pman, or using
          pman without having to know the options.

     -d   DESCRIPTION, OPTIONS, NOTES, COMMENTS, COMMANDS (detail
          about the entry)

     -e   EXAMPLES or HINTS

     -k   KEYWORDS, NAME, or SEE ALSO

     -n   NAME (name and purpose of the entry)

     -o   OPTIONS (unfortunately, few files use a separate sec-
          tion expressly for option descriptions)

     -s   SYNTAX, SYNOPSIS, or USAGE

     -v   VARIABLES, ENVIRONMENT, or FILES (special variables or
          files used by the entry)

     -w   WARNINGS, BUGS, LIMITATIONS, RESTRICTIONS, DIAGNOSTICS,
          CAVEATS, NOTES, and STATUS

     -x   SEE ALSO, REFERENCES, ALGORITHM, and AUTHOR (cross-
          references)

EXAMPLES
     pman -s echo             # SYNTAX from man echo
     pman -vw 1 man           # VARIABLES & WARNINGS from man 1 man
     pman -+ 7 REQ man        # REQUESTS section on man macros
     pman -hd w | sed 's/.^H//g'# header & detail unhighlighted

FILE
     /usr/man/cat?/* (formatted manual entries searched for here)

SEE ALSO
     man(1)

KEYWORDS
     help, documentation

AUTHOR
     Gary Perlman (based on a shell script by Bob Marcus)

BUGS
     The compacted output may have problems when there are tabs
     in the formatted text.

RESTRICTIONS




Printed 6/2/85            May 27, 1985                          2






PMAN(1WI)              UNIX User's Manual               PMAN(1WI)



     pman will not work if sections headings are indented or con-
     tain overstriking to embolden.  The filter: sed 's/.^H//g'
     can be used with the standard input option to help with this
     problem.

STATUS
     I am open to suggestions for enhancements.  Bug fixes and
     new features are appreciated and will be acknowledged.

     The program has been tested on 4.2 BSD UNIX and System V.













































Printed 6/2/85            May 27, 1985                          3



SHAR_EOF
echo shar: extracting "'pman.c'" '(13550 characters)'
if test -f 'pman.c'
then
	echo shar: over-writing existing file "'pman.c'"
fi
cat << \SHAR_EOF > 'pman.c'
/*
	contents:
		pman main program to print sections of formatted manuals
	make:
		pman: pman.o getopt.o (putopt.o)
			cc -o pman pman.o getopt.o (putopt.o)
	compiler options:
		-DMONITOR="file"    saves monitor info in file (local only)
		-DCATMANDIR="dir"   looks for manual entries here
	author:
		Gary Perlman     Wang Institute      May 25 1985
		(based on a script by Bob Marcus)
	assumptions:
		1. section headings are on the left margin
		2. section headings do not contain any overstriking
		   as is possible with some versions of nroff
	possible extensions:
	calling pattern: the real workhorse is checklines
		main (argc, argv)
			initial (argc, argv)
				putopt (argc, argv, optstring, file)
				getopt (argc, argv, optstring)
				addsection (optarg)
			checklines (stdin, "-")
				getname (from file text)
			pman (name)
				findfile (section, name)
					printman (name, section, fullpath)
						printheader (name, section, fullpath)
						checklines (ioptr, name)
							getname (from file name)
*/

#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/dir.h>

/*
	directory functions/macros for portability between 4.2 BSD
	on older UNIX systems.  syntax ends up being like 4.2 BSD.
*/
#ifdef MAXNAMLEN            /* probably should be BSD4_2 or the like */

#define	namedir(entry)      (entry->d_name)
#define	MAXNAME             256

#else

#define	DIR	                FILE
#define	MAXNAME             (DIRSIZ+2)
#define	opendir(path)       fopen (path, "r")
#define closedir(dirp)      fclose (dirp)
char	*strncpy ();
static	char DiRtNaMe[MAXNAME]; /* name of current dir saved here */
#define	namedir(entry)      strncpy (DiRtNaMe, entry->d_name, DIRSIZ)

struct direct *
readdir (dirp)
DIR 	*dirp;
	{
	static	struct	direct	entry;
	if (dirp == NULL) return (NULL);
	for (;;)
		{
		if (fread (&entry, sizeof (struct direct), 1, dirp) == 0) return (NULL);
		if (entry.d_ino) return (&entry);
		}
	}

#endif

#define	EOS           '\0'
#define	MAXSECTIONS   8      /* sections 1 - 8 in manual */
#define	INDENT        5      /* number of spaces man text is indented */
#define	issection(s)  (s[1] == EOS && *s >= '1' && (*s-'0') <= MAXSECTIONS)
#define	newsection(s) (isupper (s[0]) && isupper (s[1]))

/* PARAMETERS */
#ifndef
#define	CATMANDIR "/usr/man/cat"
#endif
char	*Catmandir = CATMANDIR;       /* cat files in Catmandir[1-8] */
int 	Section = 0;                  /* manual section number */

/* OPTIONS: print the corresponding section in the UNIX manual */
int 	Header;          /* print a header */
int 	Compact;         /* compact output format */
int 	All;             /* print all occurances of name */
int 	Blanklines;      /* print blank lines */
int 	Name;            /* NAME */
int 	Options;         /* OPTIONS */
int 	Keywords;        /* KEYWORDS NAME SEE ALSO */
int 	Syntax;          /* SYNTAX SYNOPSIS USAGE */
int 	Description;     /* DESCRIPTION */
int 	Variables;       /* VARIABLES FILES ENVIRON */
int 	Warnings;        /* BUGS LIMITATIONS DIAGNOSTICS WARNINGS RESTRICTION */
    	                 /* STATUS */
int 	Examples;        /* EXAMPLES */
int 	Xrefs;           /* SEE ALSO  AUTHOR */

initial (argc, argv) char **argv;
	{
	extern	char	*optarg;
	extern	int 	optind;
	int 	errflg = 0;
	int 	C;
	char	*optstring = "abcdehknosvwx+:";
	int 	popt = 0;        /* have any printing options been selected? */
#define	USAGE "Usage: %s [-abcdehknosvwx] [-+ name] [section] [-] names\n"
#ifdef MONITOR
	putopt (argc, argv, optstring, MONITOR);
#endif
	while ((C = getopt (argc, argv, optstring)) != EOF)
		switch (C)
			{
			default: errflg++; break;
			case 'a': All++;           Header++;  break;
			case 'b': Blanklines++;               break;
			case 'c': Compact++;                  break;
			case 'd': Description++;   popt++;    break;
			case 'e': Examples++;      popt++;    break;
			case 'h': Header++;                   break;
			case 'k': Keywords++;      popt++;    break;
			case 'n': Name++;          popt++;    break;
			case 'o': Options++;       popt++;    break;
			case 's': Syntax++;        popt++;    break;
			case 'v': Variables++;     popt++;    break;
			case 'w': Warnings++;      popt++;    break;
			case 'x': Xrefs++;         popt++;    break;
			case '+':
				if (addsection (optarg)) popt++;
				else
					{
					fprintf (stderr, "%s: Can't add '%s'.  ", argv[0], optarg);
					fprintf (stderr, "(Too many sections)\n");
					errflg++;
					}
				break;
			}
	if (issection (argv[optind]))
		{
		Section = argv[optind][0] - '0';
		optind++;
		}
	if (optind == argc)
		{
		fprintf (stderr, "%s: no names supplied\n", argv[0]);
		errflg++;
		}
	if (errflg)
		{
		fprintf (stderr, USAGE, argv[0]);
		exit (1);
		}
	if (popt == 0) /* no printing options selected */
		Name = Syntax = Examples = 1;
	}

main (argc, argv) char **argv;
	{
	extern	int 	optind;
	char	*name;
	initial (argc, argv);
	while (optind < argc)
		{
		name = argv[optind++];
		if (!strcmp (name, "-")) /* process stdin */
			checklines (stdin, name);
		else if (pman (name) == 0)
			{
			fprintf (stderr, "%s: no manual entry found for %s", argv[0], name);
			if (Section)
				fprintf (stderr, " in section %d", Section);
			putc ('\n', stderr);
			}
		}
	exit (0);
	}

printman (name, section, fullpath)
char	*name;
int 	section;
char	*fullpath;
	{
	FILE	*ioptr;
	if (!fullpath || (ioptr = fopen (fullpath, "r")) == NULL)
		return (0);
	if (Header)
		printheader (name, section, fullpath);
	checklines (ioptr, name);
	(void) fclose (ioptr);
	return (1);
	}

/* searches dir, prints, returns success */
findfile (section, name)
int 	section;
char	*name;
	{
	char	fullpath[BUFSIZ];
	char	dir[BUFSIZ];
	DIR 	*dirp;
	int 	success = 0;
	(void) sprintf (dir, "%s%d", Catmandir, section);
	*fullpath = EOS;
	if (dirp = opendir (dir))
		{
		struct	direct	*dp;
		int 	len = strlen (name);
		while (dp = readdir (dirp))
			{
			if (begins (name, namedir(dp))
			&& (namedir(dp)[len] == '.' || namedir(dp)[len] == EOS))
				{
				(void) sprintf (fullpath, "%s/%s", dir, namedir(dp));
				if (printman (name, section, fullpath))
					{
					success++;
					if (!All) break;
					}
				}
			}
		closedir (dirp);
		}
	return (success);
	}

/* print what is requested from name, if possible, and return success */
pman (name)
char	*name;
	{
	int 	section;
	int 	success = 0;
	if (Section)
		return (findfile (Section, name));
	/* check all sections, stop at first hit */
	for (section = 1; section < MAXSECTIONS; section++)
		if (findfile (section, name))
			{
			success++;
			if (!All) break;
			}
	return (success);
	}

/*
	Data structure definition pairing parts of a manual with options
	There are defined parts left while the name is undefined
	The very last part has the printflag set to NULL
*/
typedef struct
	{
	int 	*pflag;    /* if true, then print this section */
	char	*name;     /* the name of the manual part to be printed */
	} PART;
#define	partname(i)  (Part[i].name)
#define	partprint(i) (*(Part[i].pflag))
#define	partsleft(i) (Part[i].name)
#define	lastpart(i)  (Part[i].pflag == NULL)
int 	True = 1;    /* dummy pflag */
PART	Part[] =     /* end with null elements */
	{
	{ &Name,          "NAME"          },
	{ &Keywords,      "NAME"          },
	{ &Keywords,      "KEYWORD"       },
	{ &Keywords,      "SEE ALSO"      },
	{ &Options,       "OPTIONS"       },
	{ &Syntax,        "SYNTAX"        },
	{ &Syntax,        "SYNOPSIS"      },
	{ &Syntax,        "USAGE"         },
	{ &Description,   "DESCRIPTION"   },
	{ &Description,   "NOTE"          },
	{ &Description,   "COMMENT"       },
	{ &Description,   "OPTION"        },
	{ &Description,   "COMMAND"       },
	{ &Variables,     "FILE"          },
	{ &Variables,     "VARIABLE"      },
	{ &Variables,     "ENVIRON"       },
	{ &Examples,      "EXAMPLE"       },
	{ &Examples,      "HINT"          },
	{ &Xrefs,         "SEE ALSO"      },
	{ &Xrefs,         "REFERENCE"     },
	{ &Xrefs,         "ALGORITHM"     },
	{ &Xrefs,         "AUTHOR"        },
	{ &Warnings,      "WARNING"       },
	{ &Warnings,      "STATUS"        },
	{ &Warnings,      "NOTE"          },
	{ &Warnings,      "CAVEAT"        },
	{ &Warnings,      "DIAGNOSTIC"    },
	{ &Warnings,      "BUG"           },
	{ &Warnings,      "RESTRICTION"   },
	{ &Warnings,      "LIMIT"         },
	{ &True,           NULL           }, /* last one must be null */
	{ &True,           NULL           }, /* extras left for + option */
	{ &True,           NULL           },
	{ &True,           NULL           },
	{ &True,           NULL           },
	{ &True,           NULL           },
	{ &True,           NULL           },
	{ &True,           NULL           },
	{ &True,           NULL           },
	{ &True,           NULL           },
	{ NULL,            NULL           } /* very last nust be NULL NULL */
	};

/*
	checklines reads the lines from its file until exhausted,
	printing the sections requested.  It matches the name part
	in the Part structure and then if that part has been asked
	for, it prints until the next part of the manual entry.
	checklines skips many unwanted lines:
		page numbering lines, blank lines, copyright lines,
		and miscallaneous page header/footer lines
	note: most of this program's time is spent here (esp. in fgets)
*/
checklines (ioptr, name)
FILE	*ioptr;
char	*name;
	{
	char	line[BUFSIZ];
	char	NAME[BUFSIZ];        /* upper case version of name */
	register	int	part;        /* index through all the different parts */
	int 	printing = 0;        /* are we printing the lines in this part? */
	int 	prevblank = 0;       /* was previous line a blank? */
	register char	*ptr;
	getname (name, NAME, ioptr);
	while (fgets (ptr = line, BUFSIZ, ioptr))
		{
		/* set ptr to first non-space character */
		if (isspace (*ptr))           /* most common case first */
			{
			while (isspace (*ptr)) ptr++;
			if (*ptr == EOS)          /* a visually empty line */
				{
				if (Blanklines && printing && !prevblank)
					prevblank = putchar ('\n');
				/* else skip over blank lines */
				continue;
				}
			}
		else if (isdigit (*ptr))      /* page number in column 0 */
			continue;
		else if (begins ("Printed ", ptr))
			continue;                 /* skip over page footer */
		/* assert (!isspace (*ptr)); */
		if (begins (NAME, ptr))  /* just a page break header */
			{
			char	*eptr = ptr;
			if (ptr == line)          /* NAME(#) at line start */
				continue;     
			while (*eptr && !isspace (*eptr)) eptr++; /* go to first space */
			while (isspace (*eptr)) eptr++;
			if (*eptr == EOS)         /* NAME(#) at line end */
				continue;
			}
		else if (begins ("(c) Digital", ptr))
			continue;                 /* skip over DEC copyright lines */
		/* we now have a printable line */
		if (newsection (line)) /* see if lines will be printed */
			{
			printing = 0;
			for (part = 0; partsleft (part); part++)
				if (begins (partname(part), line))
					if (printing = partprint(part))
						break;
					/* else continue to check for -+ option parts */
			}
		if (printing)
			{
			if (Compact)
				{
				if (newsection (line))
					{
					while (*ptr) ptr++;
					while (ptr > line && isspace (*(ptr-1))) ptr--;
					*ptr = EOS;
					printf ("%-.7s", line);
					}
				else
					{
					putchar ('\t');
					if (ptr-line > INDENT) /* only skip indent */
						ptr = line+INDENT; /* might foul up tabstops */
					fputs (ptr, stdout);
					}
				}
			else fputs (line, stdout);
			prevblank = 0; /* previous line not a blank line */
			}
		}
	}

/* add a new section name to the search list and return success */
addsection (name)
char	*name;
	{
	int 	part;
	for (part = 0; partsleft (part); part++); /* get last part */
	if (!lastpart (part))
		{
		partname (part) = name;
		return (1);
		}
	else return (0);
	}

begins (s1, s2) /* true if s1 is the beginning of s2 */
register	char	*s1;
register	char	*s2;
	{
	while (*s1)
		if (*s1++ != *s2++) return (0);
	return (1);
	}

underline (s) /* prints s underlined */
char	*s;
	{
	while (*s)
		{
		if (isprint (*s) && *s != ' ')
			{
			putchar ('_');
			putchar ('\b');
			}
		putchar (*s++);
		}
	}

/* print the name and section (e.g., 1local, 3g) of name */
printheader (name, section, fullpath)
char	*name;       /* base name of man entry */
int 	section;     /* the section number of the entry */
char	*fullpath;   /* the full path name of the entry */
	{
	char	header[BUFSIZ];
	register	char *sptr;  /* eventually, a sub-section pointer */
	for (sptr = fullpath; *sptr; sptr++);
	while (*sptr != '.' && *sptr != '/' && sptr > fullpath) sptr--;
	if (*sptr) sptr++; /* skip over . */
	if (*sptr) sptr++; /* skip over section digit */
	(void) sprintf (header, "SOURCE%c\t%s %d%s\n",
		(Compact ? ' ' : '\n'), name, section, sptr);
	underline (header);
	}

/* get NAME used to search for lines with -man format headers */
getname (name, NAME, ioptr)
char	*name;     /* the base name of the entry */
char	*NAME;     /* eventually, the upper case name with ( suffix */
FILE	*ioptr;    /* man file, needed if input is from stdin */
	{
	char	line[BUFSIZ];
	register	char *ptr;
	extern	char	*strcpy ();
	if (!strcmp (name, "-")) /* input will be from stdin */
		{
		while (fgets (ptr = line, BUFSIZ, ioptr))
			{
			while (isspace (*ptr)) ptr++;
			if (*ptr) /* we have the title */
				{
				name = ptr;
				while (*ptr && !isspace (*ptr) && *ptr != '(') ptr++;
				*ptr = EOS;
				break;
				}
			}
		}
	(void) strcpy (NAME, name); /* copy, map to UC, and add open paren */
	for (ptr = NAME; *ptr; ptr++)
		if (islower (*ptr)) *ptr = toupper (*ptr);
	*ptr++ = '(';
	*ptr = EOS;
	}
SHAR_EOF
echo shar: extracting "'pman.t'" '(1313 characters)'
if test -f 'pman.t'
then
	echo shar: over-writing existing file "'pman.t'"
fi
cat << \SHAR_EOF > 'pman.t'
#! /bin/sh
# test script for pman options
E="echo ============ "
F='mv rm cp ln find'
$E ILLEGAL OPTION: pman -z $F
	pman -z $F
$E MISSING NAMES: pman
	pman
$E UNFOUND NAME: pman nomanual foobaz
	pman nomanual foobaz
$E UNFOUND NAME IN SECTION: pman 5 ls
	pman 5 ls
$E SIMPLE TEST SHOULD PRINT NAME SECTION AND EXAMPLES: pman $F
	pman $F
$E NAME: pman -n $F
	pman -n $F
$E COMPACT SYNTAX: pman -cs $F
	pman -cs $F
$E PROCESSED MAN OUTPUT: pman -cnwv - '<' pman.nr
	pman -cnwv - < pman.nr
$E HEADER WITH BLANK LINES WITH WARNINGS: pman -wbh $F
	pman -wbh $F
$E COMPACT LISTING OF SEE ALSO FOR FILES: pman -c -+ '"SEE ALSO"' $F
	pman -c -+ "SEE ALSO" $F
$E COMPACT VARIABLES FOR SECTION 7 MAN MACROS: pman -cv 7 man
	pman -cv 7 man
$E REQUESTS FOR SECTION 7 MAN MACROS: pman -+ REQ 7 man
	pman -+ REQ 7 man
$E EXAMPLES FOR SECT 3 VARARGS W/OUT SECT SUPPLIED: pman -e varargs
	pman -e varargs
$E ABOVE, WITH -+ OPTION AND SECT SUPPLIED: pman -+ EXAMPLE 3 varargs
	pman -+ EXAMPLE 3 varargs
$E OPTIONS AND NAME FOR FTP: pman -on ftp
	pman -on ftp
$E FILES AND VARIABLES FOR MAIL: pman -v mail
	pman -v mail
$E COMPACT HEADER AND WARNINGS FOR UUCP: pman -cwh uucp
	pman -cwh uucp
$E HEADER AND XREFS WITH BLANKS FOR SH AND CSH: pman -hbx sh csh
	pman -hbx sh csh
$E ALL VERSIONS OF MKDIR: pman -a mkdir
	pman -a mkdir
SHAR_EOF
chmod +x 'pman.t'
echo shar: extracting "'getopt.c'" '(1437 characters)'
if test -f 'getopt.c'
then
	echo shar: over-writing existing file "'getopt.c'"
fi
cat << \SHAR_EOF > 'getopt.c'
/* got this off net.sources */
#include <stdio.h>

/*
 * get option letter from argument vector
 */
int	opterr = 1,		/* useless, never set or used */
	optind = 1,		/* index into parent argv vector */
	optopt;			/* character checked for validity */
char	*optarg;		/* argument associated with option */

#define BADCH	(int)'?'
#define EMSG	""
#define tell(s)	fputs(*nargv,stderr);fputs(s,stderr); \
		fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);

getopt(nargc,nargv,ostr)
int	nargc;
char	**nargv,
	*ostr;
{
	static char	*place = EMSG;	/* option letter processing */
	register char	*oli;		/* option letter list index */
	char	*index();

	if(!*place) {			/* update scanning pointer */
		if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
		if (*place == '-') {	/* found "--" */
			++optind;
			return(EOF);
		}
	}				/* option letter okay? */
	if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
		if(!*place) ++optind;
		tell(": illegal option -- ");
	}
	if (*++oli != ':') {		/* don't need argument */
		optarg = NULL;
		if (!*place) ++optind;
	}
	else {				/* need an argument */
		if (*place) optarg = place;	/* no white space */
		else if (nargc <= ++optind) {	/* no arg */
			place = EMSG;
			tell(": option requires an argument -- ");
		}
	 	else optarg = nargv[optind];	/* white space */
		place = EMSG;
		++optind;
	}
	return(optopt);			/* dump back option letter */
}
SHAR_EOF
#	End of shell archive
exit 0
-- 
Gary Perlman  Wang Institute  Tyngsboro, MA 01879  (617) 649-9731
UUCP: decvax!wanginst!perlman             CSNET: perlman@wanginst