[comp.sources.misc] v06i011: replacement "man" program

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (01/24/89)

Posting-number: Volume 6, Issue 11
Submitted-by: chip@vector.UUCP (Chip Rosenthal)
Archive-name: ya-man

The "man" program is a replacement for the system "man" command.  It
offers the following features:

    (1)  Ability to organize man directories to your preferences.
    (2)  Understands both normal UNIX and bizarre XENIX naming conventions.
    (3)  Supports packed and compressed files.
    (4)  Supports cross-index, for example to locate strcpy(3) in string(3).
    (5)  Ability to make "man" do what you want - 'cause you now have source.

--- cut here -----------------------------------------------------------------
#! /bin/sh
# this is a "shar" archive - run through "/bin/sh" to extract 11 files:
#   README man.h patchlevel.h man.c lookup.c index.c manpage.c man.man catman Install Makefile
# Wrapped by bin@vector on Fri Dec 30 20:46:19 CST 1988
# Unpacking this archive requires:  sed test wc (possibly mkdir)
# Existing files will not be clobbered unless "-c" is specified on the cmd line.
if test -f README -a "$1" != "-c" ; then
    echo "README: file exists - will not be overwritten"
else
    echo "x - README (file 1 of 11, 5523 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_README' > README
X
X	         man - Locate and Display Manual Pages
X                 === = ====== === ======= ====== =====
X
XThe "man" program is a replacement for the system "man" command.  It
Xoffers the following features:
X
X    (1)  Ability to organize man directories to your preferences.
X    (2)  Understands both normal UNIX and bizarre XENIX naming conventions.
X    (3)  Supports packed and compressed files.
X    (4)  Supports cross-index, for example to locate strcpy(3) in string(3).
X    (5)  Ability to make "man" do what you want - 'cause you now have source.
X
XIn addition, a "catman" script is included to pre-format man pages en masse.
XThe distributed configuration of this package is for SCO XENIX.  These notes
Xdescribe how to configure it for your system.
X
XInstallation summary:
X
X    1.  Configure "Makefile" and "lookup.c" for your system directory routines.
X    2.  Configure the definitions in "man.h".
X    3.  Configure the tables in "man.c".
X    4.  Run "make all".
X    5.  Install "man", "man.man", and "catman".
X
XI would be interested in receiving any bugfixes, comments, or suggestions.
XI will try to release official patches to USENET as appropriate.  This
Xpackage is copyrighten with the intent to encourage "free" use and
Xdistribution.  Notice is at the end of this file.
X
X
XConfigure "Makefile" and "lookup.c" for your system directory routines.
X========= ========== === ========== === ==== ====== ========= =========
X
X    This package requires your local directory search ("ndir") procedures.
X    As distributed, the package is configured for SCO XENIX's directory
X    library.  For any other sort of system, you will need to change the
X    following:
X
X	Makefile -- change LIBS from "-lx" to "-lndir" or as appropriate.
X	lookup.c -- change "<sys/ndir.h>" to "<ndir.h>" or as appropriate.
X
X
XConfigure the definitions in "man.h".
X========= === =========== == ========
X
X    The following items are defined in "man.h", and you might want
X    to change them:
X
X	 FORMAT_CMD	Command to format manual pages.
X	 COL_CMD	Command to filter formatted output.
X	 SQUEEZE_CMD	Command to squeeze multiple blank lines.
X	 PAGE_CMD	Command to page output.
X	 COMRESS_CMD	Command to compress file.
X	 INDEX_FILE	Path to cross-ref.
X	 DEFAULT_TERM	Default device for formatting.
X
X
XConfigure the tables in "man.c".
X========= === ====== == ========
X
X    You will almost certainly want to modify the "Base_dir_list[]", which
X    specifies which directories contain man pages.  You might want to
X    customize some of the other tables in this file.
X
X    Base_dir_list[]
X
X        This specifies which directories have manual pages in them, in
X        the order they are to be searched.  It also specifies whether the
X        directory follows UNIX naming conventions (e.g. "man1") or XENIX
X        naming conventions (e.g. "man.C").  The comments in the source
X        should provide some guidance.
X
X    Unix_section_list[]
X    Xenix_section_list[]
X
X        These lists give the manual sections for UNIX-style man pages
X        (e.g. "1", "2", etc.) and XENIX-style man pages (e.g. "C", "S",
X        etc.)  Please note the section name does not need to correspond
X        to the manpage file suffix.  For example, if you have a "man1/boot.1m"
X        manpage, then you need to have "1" in your "Unix_section_list[]",
X        but not necessarily "1m".  The subdirectories are searched in the
X        order specified here.
X
X        When "man" tries to locate a manual page, it permutes all the
X        directories of "Base_dir_list[]" with one of these section lists.
X	The "xenixish" flag in the "Base_dir_list[]" entry selects whether
X	to use "Unix_section_list[]" or "Xenix_section_list[]".
X
X    Compress_list[]
X
X	This list tells "man" that ".Z" files run through "compress", etc.
X    
X    No_col_list[]
X
X        This list tells "man" which terminal types don't need output run
X        through "col".
X
X
X    By the way ... you might want to edit the catman script so that its
X    DIRLIST corresponds to the "Base_dir_list[]" directories you've defined
X    in man.
X
X
XRun "make all".
X=== ===== =====
X
X    This will create the "man" executable.
X
X
XInstall "man", "man.man", and "catman".
X======= ====== ========== === =========
X
X    The "make install" option is configured to run with my "install"
X    program.  Drop me a line if you want a copy.  Otherwise, do something
X    like:
X
X	cp man /local/bin/man
X	cp catman /local/bin/man
X	cp man.man /usr/man/local/man1/man.1
X
X
X------------------------------------------------------------------------------
XCopyright 1988, Chip Rosenthal.  Permission is granted to use, distribute, or
Xmodify the files in this package as long as you don't charge money for these
Xfiles or packages which include these files beyond reasonable handling and
Xdistribution costs, and if you distribute any portion or executable version
Xof this package, you must make the full distributed package available at no
Xadditional charge and provide notice of such.  The author retains all rights
Xon derivative works.  This software is provided without warranty or guarantee
Xof support.  The author is not responsible for any loss or damage arising
Xfrom use or misuse of this software.
X------------------------------------------------------------------------------
X
X                                                                Chip Rosenthal
X                                                              chip@vector.uucp
X                                                                     26 Dec 88
X@(#) README 1.1 88/12/30 20:42:24
X
END_OF_FILE_README
    size="`wc -c < README`"
    if test 5523 -ne "$size" ; then
	echo "README: extraction error - got $size chars"
    fi
fi
if test -f man.h -a "$1" != "-c" ; then
    echo "man.h: file exists - will not be overwritten"
else
    echo "x - man.h (file 2 of 11, 4098 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_man.h' > man.h
X/*
X * @(#) man.h 1.1 88/12/30 20:42:55
X *
X * Mon Dec 26 17:10:06 CST 1988 - C. Rosenthal (chip@vector.UUCP)
X *	Original composition.
X *
X * Copyright 1988, Chip Rosenthal.
X * Permission granted to use, modify, and distribute the files in this
X * package as described in the accompanying "README" file.
X */
X
X#define	BUFLEN		128
X#define LBUFLEN		1024
X#define TRUE		1
X#define FALSE		0
X#define Dprintf		if (!Debug) ; else fprintf
X
X/*
X * FORMAT_CMD	Command to format manual pages.  "%s" replaced with term type.
X * COL_CMD	Command to filter formatted output.
X * SQUEEZE_CMD	Command to squeeze multiple blank lines.
X * PAGE_CMD	Command to page output.  (Overridden by $PAGER).
X * COMRESS_CMD	Command to compress file.  "%s" replaced with file name.
X * INDEX_FILE	Path to cross-ref.  Undefine to suppress this feature.
X * DEFAULT_TERM	Default device for formatting.  (Overriden by -T option).
X */
X#define FORMAT_CMD	"tbl | eqn | nroff -man -T%s"
X#define COL_CMD		"col"
X#define SQUEEZE_CMD	\
X	"awk '{ if(length(\$0)==0){++n}else{n=-2} ; if(n<0){print} }'"
X#define PAGE_CMD	"less"
X#define COMPRESS_CMD	"compress %s"
X#define INDEX_FILE	"/usr/man/index"
X#define DEFAULT_TERM	"lp"
X
X#ifdef LINT
X#   define SCCSID(STR)
X#else
X#   define SCCSID(STR) static char Sccsid[] = STR;
X#endif
X
X/*
X * Information on a manual page file.
X *
X *      .------------------------- basedir
X *      |             
X *      |              .---------- ( source ? "man" : "cat" )
X *      |              |  .------- section
X *      |              |  |
X *      |              |  | .----- entry
X *      |              |  | |  .-- suffix
X *      |              |  | |  |.- zsuffix
X *      |              |  | |  ||
X *      --------------=---=-==-=--
X *	/usr/man/u_man/man1/ls.1.Z
X *      --------------=---=-==-=--
X *                    |    |  |
X *                    `----`--`--- implied
X */
Xstruct fileinfo {
X    char *basedir;	/* base directory, e.g. "/usr/man/u_man"	*/
X    int source;		/* true if roff source, false if pre-formatted	*/
X    int xenixish;	/* true if "." before section in dir name	*/
X    char *section;	/* section name, e.g. "1"			*/
X    char *entry;	/* manpage name, e.g. "ls"			*/
X    char *suffix;	/* manpage suffix, e.g. "1"			*/
X    char *zsuffix;	/* file compression suffix, e.g. ".Z"		*/
X    long mtime;		/* time of modification, or 0 if not found	*/
X    char *catcmd;	/* cmd to (possibly uncompress and) cat file	*/
X};
X
X/*
X * List of directories to search in the order to search.
X */
Xextern struct base_dir_entry {
X    char *basedir;	/* base dir, contains the "{man,cat}*" dirs	*/
X    int xenixish;	/* TRUE for "man.C/ls.C", FALSE for "man1/ls.1"	*/
X} Base_dir_list[];
X
X/*
X * List of sections for UNIX-style man pages in search order.
X */
Xextern char *Unix_section_list[];
X
X/*
X * List of sections for XENIX-style man pages in search order.
X */
Xextern char *Xenix_section_list[];
X
X/*
X * List of suffixes which indicate file compression, and how to "cat" them.
X */
Xextern struct zsuffix_entry {
X    char *suffix;	/* suffix appended to the file			*/
X    char *catcmd;	/* cmd which dumps the possibly compressed file	*/
X} Compress_list[];
X
X/*
X * List of terminals which aren't run through col.
X */
Xextern char *No_col_list[];
X
X/*
X * Execution options - selected through command line arguments.
X */
Xextern int Do_update;		/* format and save manpage if out of date?    */
Xextern int Do_format;		/* format even if not required?		      */
Xextern int Do_first_only;	/* show first manpage or all manpages found?  */
Xextern int Do_squeeze;		/* squeeze out multiple blank lines?	      */
Xextern int Do_col;		/* run output through col(1)?		      */
Xextern int Do_names_only;	/* show pathnames rather display manpages?    */
Xextern int Debug;		/* debug mode				      */
Xextern char *Term;		/* terminal type for formatter output	      */
X
X/*
X * Procedures.
X */
Xchar *manpath();	/* Generate pathname to a manpage file.		      */
Xint do_index();		/* Search through the index file for a manpage entry. */
Xint do_lookup();	/* Determine whether a manpage file exists.	      */
Xint do_manpage();	/* Process the manpage.				      */
X
END_OF_FILE_man.h
    size="`wc -c < man.h`"
    if test 4098 -ne "$size" ; then
	echo "man.h: extraction error - got $size chars"
    fi
fi
if test -f patchlevel.h -a "$1" != "-c" ; then
    echo "patchlevel.h: file exists - will not be overwritten"
else
    echo "x - patchlevel.h (file 3 of 11, 71 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_patchlevel.h' > patchlevel.h
X/*
X * @(#) patchlevel.h 1.1 88/12/30 20:43:12
X */
X#define PATCHLEVEL 0
END_OF_FILE_patchlevel.h
    size="`wc -c < patchlevel.h`"
    if test 71 -ne "$size" ; then
	echo "patchlevel.h: extraction error - got $size chars"
    fi
fi
if test -f man.c -a "$1" != "-c" ; then
    echo "man.c: file exists - will not be overwritten"
else
    echo "x - man.c (file 4 of 11, 5994 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_man.c' > man.c
X/*
X * @(#) man.c 1.1 88/12/30 20:42:48
X *
X * Mon Dec 26 17:10:06 CST 1988 - C. Rosenthal (chip@vector.UUCP)
X *	Original composition.
X *
X * Copyright 1988, Chip Rosenthal.
X * Permission granted to use, modify, and distribute the files in this
X * package as described in the accompanying "README" file.
X */
X
X#include <stdio.h>
X#include "man.h"
X#include "patchlevel.h"
X
XSCCSID("@(#) man.c 1.1 88/12/30 20:42:48");
Xstatic char Copyright[] = "@(#) Copyright 1988, Chip Rosenthal";
X
X#define USAGE "usage: %s [-abcfwU] [-T term] [section] command\n"
X
X/*
X * List of directories to search in the order to search.
X */
Xstruct base_dir_entry Base_dir_list[] = {
X/*
X *    basedir           xenixish
X */
X    { "/usr/man/local",	FALSE	},	/* my local man pages	*/
X    { "/usr/man",	TRUE	},	/* XENIX man pages	*/
X/***{ "/usr/man",	FALSE	},	/* BSD man pages	*/
X/***{ "/usr/man/l_man",	FALSE	},	/* SYSV local		*/
X/***{ "/usr/man/u_man",	FALSE	},	/* SYSV user		*/
X/***{ "/usr/man/a_man",	FALSE	},	/* SYSV administrative	*/
X/***{ "/usr/man/p_man",	FALSE	},	/* SYSV programmers	*/
X    { NULL,		0	},
X};
X
X/*
X * List of sections for UNIX-style man pages in search order.
X */
Xchar *Unix_section_list[] = {
X    "1", "2", "3", "4", "5", "6", "7", "8", "l", "n", "p", NULL
X};
X
X/*
X * List of sections for XENIX-style man pages in search order.
X */
Xchar *Xenix_section_list[] = {
X    "C", "CP", "CT", "S", "M", "F", "HW", "DOS", "UCB", "LOCAL", NULL
X};
X
X/*
X * List of suffixes which indicate file compression, and how to "cat" them.
X * A "%s" in the "catcmt" is replaced with the file name.
X */
Xstruct zsuffix_entry Compress_list[] = {
X/*
X *    suffix	catcmd
X */
X    { ".Z",	"zcat %s"	},	/* a "compressed" file	*/
X    { ".z",	"pcat %s"	},	/* a "packed" file	*/
X    { "",	"cat %s"	},	/* a normal file	*/
X    { NULL,	NULL		}
X};
X
X/*
X * List of terminals which aren't run through col.
X */
Xchar *No_col_list[] = {
X    "300", "300s", "450", "37", "4000a", "382", "4014", "tek", "1620", "X", NULL
X};
X
X/*
X * Execution options - selected through command line arguments.
X */
Xint Do_update = FALSE;		/* format and save manpage if out of date?    */
Xint Do_format = FALSE;		/* format even if not required?		      */
Xint Do_first_only = TRUE;	/* show first manpage or all manpages found?  */
Xint Do_squeeze = TRUE;		/* squeeze out multiple blank lines?	      */
Xint Do_col = FALSE;		/* run output through col(1)?		      */
Xint Do_names_only = FALSE;	/* show pathnames rather display manpages?    */
Xint Debug = FALSE;		/* debug mode				      */
Xchar *Term = DEFAULT_TERM;	/* terminal type for formatter output	      */
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X    char *command, *section, *basedir, **sect_p;
X    int found_flag, xenixish,  i, d;
X    struct fileinfo cat_info, man_info;
X    extern int optind;
X    extern char *optarg;
X
X    found_flag = FALSE;
X
X    /*
X     * Process the command line options.
X     */
X    while ( (i=getopt(argc,argv,"abcfwUT:D")) != EOF ) {
X	switch ( i ) {
X	case 'a':			/* display all entries */
X	    Do_first_only = FALSE;
X	    break;
X	case 'b':			/* keep blank lines */
X	    Do_squeeze = FALSE;
X	    break;
X	case 'c':			/* run through col */
X	    Do_col = TRUE;
X	    break;
X	case 'f':			/* force format */
X	    Do_format = TRUE;
X	    break;
X	case 'w':			/* which names? */
X	    Do_names_only = TRUE;
X	    Do_first_only = FALSE;
X	    break;
X	case 'U':			/* perform update */
X	    Do_update = TRUE;
X	    Do_first_only = FALSE;
X	    Do_squeeze = FALSE;
X	    break;
X	case 'T':			/* output terminal type */
X	    Term = optarg;
X	    break;
X	case 'D':			/* debug output */
X	    Debug = TRUE;
X	    break;
X	default:
X	    fprintf(stderr,USAGE,argv[0]);
X	    (void) exit(1);
X	}
X    }
X
X    /*
X     * Get the entry name.
X     */
X    switch ( argc-optind ) {
X    case 1:				/* man [options] command */
X	command = argv[optind];
X	section = NULL;
X	break;
X    case 2:				/* man [options] section command */
X	command = argv[optind+1];
X	Xenix_section_list[0] = Unix_section_list[0] = section = argv[optind];
X	Xenix_section_list[1] = Unix_section_list[1] = NULL;
X	break;
X    default:
X	fprintf(stderr,USAGE,argv[0]);
X	(void) exit(1);
X    }
X
X
X    /*
X     * Go through each base directory.
X     */
X    for ( d = 0 ; (basedir=Base_dir_list[d].basedir) != NULL ; ++d ) {
X
X	xenixish = Base_dir_list[d].xenixish;
X	Dprintf(stderr,">do_index() - checking %s-style dir '%s'\n",
X	    ( xenixish ? "xenix" : "unix" ), basedir);
X
X	/*
X	 * Go through each possible manual section in this directory.
X	 */
X	for (
X	    sect_p = ( xenixish ? Xenix_section_list : Unix_section_list ) ;
X	    *sect_p != NULL ;
X	    ++sect_p
X	) {
X
X	    cat_info.basedir = basedir;
X	    cat_info.source = FALSE;
X	    cat_info.xenixish = xenixish;
X	    cat_info.section = *sect_p;
X	    cat_info.entry = command;
X	    (void) do_lookup(&cat_info);
X
X	    man_info.basedir = basedir;
X	    man_info.source = TRUE;
X	    man_info.xenixish = xenixish;
X	    man_info.section = *sect_p;
X	    man_info.entry = command;
X	    (void) do_lookup(&man_info);
X
X	    if ( cat_info.mtime != 0 || man_info.mtime != 0 ) {
X		(void) do_manpage(&man_info,&cat_info);
X		found_flag = TRUE;
X		if ( Do_first_only )
X		    (void) exit(0);
X	    }
X
X	}
X
X    }
X
X    /*
X     * See if this command appears in the index under a different name.
X     */
X#ifdef INDEX_FILE
X    if ( !found_flag && !Do_update )
X	found_flag = do_index(command,section);
X#endif
X
X    if ( !found_flag ) {
X	fprintf(stderr,
X	    ( section == NULL ? "%s: %s '%s'.\n" : "%s: %s '%s(%s)'.\n" ),
X	    argv[0], "No manual entry found for", command, section );
X	(void) exit(1);
X    }
X
X    (void) exit(0);
X    /*NOTREACHED*/
X}
X
X
X/*
X * manpath() - Generate full pathname to a manpage from a description.
X *
X * Returns:  Pointer to static data which will be overwritten next call.
X */
Xchar *manpath(f)
Xstruct fileinfo *f;
X{
X    static char path[BUFLEN];
X    sprintf(path,"%s/%s%s%s/%s.%s%s",
X	f->basedir,
X	( f->source ? "man" : "cat" ), ( f->xenixish ? "." : "" ), f->section,
X	f->entry, f->suffix, f->zsuffix
X    );
X    return path;
X}
X
END_OF_FILE_man.c
    size="`wc -c < man.c`"
    if test 5994 -ne "$size" ; then
	echo "man.c: extraction error - got $size chars"
    fi
fi
if test -f lookup.c -a "$1" != "-c" ; then
    echo "lookup.c: file exists - will not be overwritten"
else
    echo "x - lookup.c (file 5 of 11, 3504 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_lookup.c' > lookup.c
X/*
X * @(#) lookup.c 1.1 88/12/30 20:42:42
X *
X * Mon Dec 26 17:10:06 CST 1988 - C. Rosenthal (chip@vector.UUCP)
X *	Original composition.
X *
X * Copyright 1988, Chip Rosenthal.
X * Permission granted to use, modify, and distribute the files in this
X * package as described in the accompanying "README" file.
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/ndir.h>
X#include "man.h"
X
XSCCSID("@(#) lookup.c 1.1 88/12/30 20:42:42");
X
Xstatic char *Sstrdup();
X
X/*
X * do_lookup() - Search for a manual page.
X *
X * Returns:  TRUE if a man page was found here.
X *
X * This procedure determines whether a manual page exists, and if so
X * returns information on this man page.  A single "struct fileinfo" is
X * used to pass information into and back from this procedure.  Prior to
X * calling "do_lookup()", the following items must be defined:
X *
X *	basedir, source, xenixish, section, and entry
X *
X * Upon return, if a manual page was found, the following items will
X * be filled in:
X *
X *	suffix, zsuffix, mtime, catcmd
X *
X * If a manual page was not found, then "mtime" will be zero.
X */
Xint do_lookup(f)
Xstruct fileinfo *f;	/* Structure to store results in.		*/
X{
X    int i;
X    char *path, *c;
X    struct stat sbuf;
X    DIR *dirp;
X    struct direct *dinfo;
X    static char buf[BUFLEN];
X    extern char *strchr(), *strcat(), *strcpy();
X
X    /*
X     * Initialize the items this procedure fills in.
X     */
X    f->suffix = "";
X    f->zsuffix = "";
X    f->mtime = 0;
X    f->catcmd = "";
X
X    /*
X     * Open the directory where this manpage would be.
X     */
X    (void) sprintf(buf,"%s/%s%s%s",
X	f->basedir,
X	( f->source ? "man" : "cat" ), ( f->xenixish ? "." : "" ), f->section
X    );
X    if ( (dirp=opendir(buf)) == (DIR *) NULL )
X	return FALSE;
X
X    /*
X     * Create a file pattern to search the directory against.
X     */
X    (void) strcat(strcpy(buf,f->entry),".");
X    i = strlen(buf);
X
X    /*
X     * Go through each entry in the directory looking for the file pattern.
X     */
X    do {
X	if ( (dinfo=readdir(dirp)) == (struct direct *) NULL ) {
X	    (void) closedir(dirp);
X	    return FALSE;
X	}
X    } while ( strncmp(buf,dinfo->d_name,i) != 0 );
X    (void) closedir(dirp);
X
X    /*
X     * Pull off the manpage suffix and the compression zsuffix.  We will
X     * be malloc'ing a small amount of space here which won't be returned
X     * until exiting.  But it's small enough to not worry about.
X     */
X    f->suffix = Sstrdup(dinfo->d_name+i);
X    if ( (c=strchr(f->suffix,'.')) != NULL ) {
X	f->zsuffix = Sstrdup(c);
X	*c = '\0';
X    }
X
X    /*
X     * We now have full pathname information on the manpage.
X     * Stat it so we can get the modification time.
X     */
X    path = manpath(f);
X    Dprintf(stderr,">do_lookup() - found file '%s'\n",path);
X    if ( stat(path,&sbuf) != 0 ) {
X	perror(path);
X	return FALSE;
X    }
X
X    /*
X     * Verify that this is a valid zsuffix.
X     */
X    for ( i = 0 ; Compress_list[i].suffix != NULL ; ++i ) {
X	if ( strcmp(f->zsuffix,Compress_list[i].suffix) == 0 )
X	    break;
X    }
X    if ( Compress_list[i].suffix == NULL ) {
X	fprintf(stderr,"%s: unknown suffix '%s' - file ignored\n",
X	    path, f->zsuffix);
X	return FALSE;
X    }
X    f->catcmd = Compress_list[i].catcmd;
X
X    f->mtime = sbuf.st_mtime;
X    return TRUE;
X}
X
X
Xstatic char *Sstrdup(s)
Xchar *s;
X{
X    char *p;
X    extern char *malloc(), *strcpy();
X    if ( (p=malloc((unsigned)strlen(s)+1)) == NULL ) {
X	fputs("malloc: out of space\n",stderr);
X	exit(2);
X    }
X    return strcpy(p,s);
X}
END_OF_FILE_lookup.c
    size="`wc -c < lookup.c`"
    if test 3504 -ne "$size" ; then
	echo "lookup.c: extraction error - got $size chars"
    fi
fi
if test -f index.c -a "$1" != "-c" ; then
    echo "index.c: file exists - will not be overwritten"
else
    echo "x - index.c (file 6 of 11, 3868 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_index.c' > index.c
X/*
X * @(#) index.c 1.1 88/12/30 20:42:36
X *
X * Mon Dec 26 17:10:06 CST 1988 - C. Rosenthal (chip@vector.UUCP)
X *	Original composition.
X *
X * Copyright 1988, Chip Rosenthal.
X * Permission granted to use, modify, and distribute the files in this
X * package as described in the accompanying "README" file.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include "man.h"
X
XSCCSID("@(#) index.c 1.1 88/12/30 20:42:36");
X
X#ifdef INDEX_FILE /*{*/
X
X/*
X * do_index() - Go through the index file for a reference for this command.
X *
X * Returns:  TRUE if one or more man pages were found here.
X *
X * The index file is useful for indicating when the manpage for the command
X * is not the name of the manpage.  For example, the manpage for "strcpy"
X * is "string".  The format of the index file is:
X *
X *	<command>	<manpage>	<section>
X *
X * Comments beginning with "#" are stripped.  All manpages found which meet
X * the criteria passed to this procedure are passed to "do_manpage()" for
X * processing.
X */
Xint do_index(command,section)
Xchar *command;	/* name of the command to look for	*/
Xchar *section;	/* section to look in, or NULL for any	*/
X{
X    FILE *fp;
X    char *field1, *field2, *field3, *basedir, *c;
X    struct fileinfo cat_info, man_info;
X    int found_flag, xenixish, lineno, d;
X    static char buf[BUFLEN];
X    extern char *strchr();
X
X    Dprintf(stderr,">do_index() - consulting '%s' index\n",INDEX_FILE);
X
X    /*
X     * Open the index file.
X     */
X    if ( (fp=fopen(INDEX_FILE,"r")) == (FILE *) NULL ) {
X	perror(INDEX_FILE);
X	return FALSE;
X    }
X
X    /*
X     * Go through each line of the index file.
X     */
X    found_flag = FALSE;
X    for ( lineno = 1 ; fgets(buf,sizeof(buf),fp) != NULL ; ++lineno ) {
X
X	/*
X	 * Strip comments and trailing space.  Ignore empty lines.
X	 */
X	if ( (c=strchr(buf,'#')) != NULL )
X	    *c = '\0';
X	for ( c = buf+strlen(buf)-1 ; isspace(*c) && c >= buf ; --c ) ;
X	*(c+1) = '\0';
X	if ( *buf == '\0' )
X	    continue;
X
X	/*
X	 * Field 1 is the command name.
X	 */
X	for ( field1 = buf ; isspace(*field1) ; ++field1 ) ;
X	for ( c = field1 ; *c != '\0' && !isspace(*c) ; ++c ) ;
X	if ( *field1 == '\0' || *c == '\0' ) {
X	    fprintf(stderr, "%s(%d): bad format\n", INDEX_FILE, lineno);
X	    continue;
X	}
X	*c = '\0';
X	if ( strcmp(field1,command) != 0 )
X	    continue;
X
X	/*
X	 * Field 2 is the entry name.
X	 */
X	for ( field2 = c+1 ; isspace(*field2) ; ++field2 ) ;
X	for ( c = field2 ; *c != '\0' && !isspace(*c) ; ++c ) ;
X	if ( *field2 == '\0' || *c == '\0' ) {
X	    fprintf(stderr, "%s(%d): bad format\n", INDEX_FILE, lineno);
X	    continue;
X	}
X	*c = '\0';
X
X	/*
X	 * Field 3 is the entry section.
X	 */
X	for ( field3 = c+1 ; isspace(*field3) ; ++field3 ) ;
X	for ( c = field3 ; *c != '\0' && !isspace(*c) ; ++c ) ;
X	if ( *field3 == '\0' || *c != '\0' ) {
X	    fprintf(stderr, "%s(%d): bad format\n", INDEX_FILE, lineno);
X	    continue;
X	}
X	if ( section != NULL && strcmp(field3,section) != 0 )
X	    continue;
X
X	/*
X	 * Go through each base directory.
X	 */
X	for ( d = 0 ; (basedir=Base_dir_list[d].basedir) != NULL ; ++d ) {
X
X	    xenixish = Base_dir_list[d].xenixish;
X	    Dprintf(stderr,">do_index() - checking %s-style dir '%s'\n",
X		( xenixish ? "xenix" : "unix" ), basedir);
X
X	    man_info.basedir = basedir;
X	    man_info.source = TRUE;
X	    man_info.xenixish = xenixish;
X	    man_info.section = field3;
X	    man_info.entry = field2;
X	    (void) do_lookup(&man_info);
X
X	    cat_info.basedir = basedir;
X	    cat_info.source = FALSE;
X	    cat_info.xenixish = xenixish;
X	    cat_info.section = field3;
X	    cat_info.entry = field2;
X	    (void) do_lookup(&cat_info);
X
X	    if ( man_info.mtime != 0 || cat_info.mtime == 0 ) {
X		found_flag = TRUE;
X		(void) do_manpage(&man_info,&cat_info);
X		if ( Do_first_only ) {
X		    (void) fclose(fp);
X		    return TRUE;
X		}
X	    }
X
X	}
X
X    }
X
X    (void) fclose(fp);
X    return found_flag;
X}
X
X#endif /*}INDEX_FILE*/
X
END_OF_FILE_index.c
    size="`wc -c < index.c`"
    if test 3868 -ne "$size" ; then
	echo "index.c: extraction error - got $size chars"
    fi
fi
if test -f manpage.c -a "$1" != "-c" ; then
    echo "manpage.c: file exists - will not be overwritten"
else
    echo "x - manpage.c (file 7 of 11, 4938 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_manpage.c' > manpage.c
X/*
X * @(#) manpage.c 1.1 88/12/30 20:43:05
X *
X * Mon Dec 26 17:10:06 CST 1988 - C. Rosenthal (chip@vector.UUCP)
X *	Original composition.
X *
X * Copyright 1988, Chip Rosenthal.
X * Permission granted to use, modify, and distribute the files in this
X * package as described in the accompanying "README" file.
X */
X
X#include <stdio.h>
X#include <sys/signal.h>
X#include "man.h"
X
XSCCSID("@(#) manpage.c 1.1 88/12/30 20:43:05");
X
X/* 
X * do_manpage() - Process a manual page.
X *
X * Returns:  0 if processing was successful.
X *
X * This procedure does whatever processing is required:  either display
X * a manpage, print the pathname to the file (Do_names_only), or update
X * the formatted version (Do_update).  A command pipeline is build up
X * depending upon the global configuration settings, and then a shell
X * is forked to process it.
X */
Xint do_manpage(man_info,cat_info)
Xstruct fileinfo *man_info, *cat_info;
X{
X    int pid, status, i;
X    char *path, *savepath, *c;
X    struct fileinfo *finfo;
X    int (*saveintr)();
X    static char cmdbuf[LBUFLEN], buf[BUFLEN];
X    extern char *getenv(), *strcat(), *strcpy(), *memcpy();
X
X    /*
X     * The command to process the manpage will be built up in "cmdbuf".
X     */
X    *cmdbuf = '\0';
X
X    /*
X     * Select the manpage to use.  The more recent file will be used
X     * unless we are forcing a reformat.
X     */
X    finfo = (
X	Do_format || man_info->mtime > cat_info->mtime ? man_info : cat_info
X    );
X
X    /*
X     * If we are doing updates and there is nothing to update then return.
X     */
X    if ( Do_update && finfo != man_info )
X	return 0;
X
X    /*
X     * If there isn't a manpage here then return.  This could happen, for
X     * example, if "Do_format" was specified and there was a formatted man
X     * page but not a source man page.
X     */
X    if ( finfo->mtime == 0 )
X	return 0;
X
X    /*
X     * Generate the path to the selected manpage.
X     */
X    path = manpath(finfo);
X    Dprintf(stderr,">do_manpage() - processing '%s'\n",path);
X
X    /*
X     * If we are only showing pathnames then show the selected file and return.
X     */
X    if ( Do_names_only ) {
X	puts(path);
X	return 0;
X    }
X
X    /*
X     * Generate the command to uncompress/output the file.
X     */
X    (void) sprintf(buf,finfo->catcmd,path);
X    (void) strcat(cmdbuf,buf);
X
X    /*
X     * Generate the command to format the file.
X     */
X    if ( finfo->source ) {
X	fprintf(stderr,"Formatting %s(%s) . . .\n",finfo->entry,finfo->section);
X	(void) sprintf(buf, FORMAT_CMD, Term);
X	(void) strcat(cmdbuf,"|");
X	(void) strcat(cmdbuf,buf);
X	for ( Do_col = TRUE, i = 0 ; No_col_list[i] != NULL ; ++i ) {
X	    if ( strcmp(No_col_list[i],Term) == 0 ) {
X		Do_col = FALSE;
X		break;
X	    }
X	}
X    }
X
X    /*
X     * Generate the command to filter the file.
X     */
X    if ( Do_col ) {
X	(void) strcat(cmdbuf,"|");
X	(void) strcat(cmdbuf,COL_CMD);
X    }
X
X    /*
X     * Generate the command to squeeze multiple spaces.
X     */
X    if ( Do_squeeze ) {
X	(void) strcat(cmdbuf,"|");
X	(void) strcat(cmdbuf,SQUEEZE_CMD);
X    }
X
X    /*
X     * Generate the command to page the output.
X     */
X    if ( isatty(fileno(stdout)) && !Do_update ) {
X	c = getenv("PAGER");
X	(void) strcat(cmdbuf,"|");
X	(void) strcat(cmdbuf, ( c != NULL ? c : PAGE_CMD) );
X    }
X
X    /*
X     * Generate the command to save the output to a file.
X     */
X    if ( Do_update ) {
X
X	/*
X	 * Zap old file.
X	 */
X	if ( cat_info->mtime > 0 && unlink(savepath=manpath(cat_info)) != 0 ) {
X	    perror(savepath);
X	    return -1;
X	}
X
X	/*
X	 * Figure out what to call the new file.
X	 */
X	(void) memcpy(cat_info,man_info,sizeof(struct fileinfo));
X	cat_info->source = FALSE;
X	cat_info->zsuffix = "";
X	savepath = manpath(cat_info);
X
X	/*
X	 * Tack on command to redirect output to the save file.
X	 */
X	(void) strcat(cmdbuf,">");
X	(void) strcat(cmdbuf,savepath);
X
X	/*
X	 * Tack on command to compress the save file.
X	 */
X	(void) sprintf(buf,COMPRESS_CMD,savepath);
X	(void) strcat(cmdbuf,";");
X	(void) strcat(cmdbuf,buf);
X
X    }
X
X
X    /*
X     * Go execute the command.
X     */
X    Dprintf(stderr,">do_manpage() - executing '%s'\n",cmdbuf);
X    saveintr = signal(SIGINT,SIG_IGN);
X    switch ( pid = fork() ) {
X    case -1:			/* fork error */
X	perror("fork");
X	(void) exit(1);
X    case 0:			/* child */
X	(void) signal(SIGINT,saveintr);
X	(void) execl("/bin/sh", "sh", "-c", cmdbuf, NULL);
X	fprintf(stderr,"exec /bin/sh failed\n");
X	(void) exit(1);
X    default:			/* parent */
X	break;
X    }
X
X    /*
X     * Wait for command to complete and check returned status.
X     */
X    while ( wait(&status) != pid ) ;
X    Dprintf(stderr,">do_manpage() - exit status 0x%04X\n",status);
X    (void) signal(SIGINT,saveintr);
X    if ( status == 0177 )
X	fprintf(stderr,"command stopped\n");
X    else if ( (status&0377) != 0 )
X	fprintf(stderr,"command interrupted - signal %d\n", (status&0377) );
X    else if ( (status>>8) != 0 )
X	fprintf(stderr,"command failed - exit status %d\n", (status>>8));
X
X    return status;
X}
X
END_OF_FILE_manpage.c
    size="`wc -c < manpage.c`"
    if test 4938 -ne "$size" ; then
	echo "manpage.c: extraction error - got $size chars"
    fi
fi
if test -f man.man -a "$1" != "-c" ; then
    echo "man.man: file exists - will not be overwritten"
else
    echo "x - man.man (file 8 of 11, 5651 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_man.man' > man.man
X''' @(#) man.man 1.1 88/12/30 20:43:00
X'''
X''' Mon Dec 26 17:10:06 CST 1988 - C. Rosenthal (chip@vector.UUCP)
X'''	Original composition.
X'''
X''' Copyright 1988, Chip Rosenthal.
X''' Permission granted to use, modify, and distribute the files in this
X''' package as described in the accompanying "README" file.
X'''
X.TH MAN 1L
X.SH NAME
Xman - Display manual entries.
X.SH SYNTAX
X.B man
X[
X.B \-abcfwU
X] [
X.B \-T
Xterm ] [ section ] command
X.sp
X.B catman
X[ options ]
X.SH DESCRIPTION
X.I Man
Xlocates and displays the manual entry for
X.IR command .
XIf a
X.I section
Xis specified, the search is restricted to that
Xsection of the manual.
X.PP
XScreen output will be displayed through a pager.  The "PAGER" environment
Xvalue will override the default pager selection.  Manual pages may be
Xstored as either
X.I nroff
Xsources or pre-formatted files.
X.PP
XOptions are:
X.IP "\fB\-a\fR"
XDisplay all entries.  If a command has several entries,
Xnormally only the first entry found is displayed.  When
X.B \-a
Xis specified, all entries are displayed.
X.IP "\fB\-b\fR"
XKeep blank lines.  Normally multiple blank lines are squeezed out of the
Xmanual page when displayed to the screen.  The
X.B \-b
Xoption requests that these blank lines be retained.  This option is implied
Xwhen the output is redirected.
X.IP "\fB\-c\fR"
XFilter output through
X.IR col(1) .
XNormally,
X.I man
Xfilters output through
X.I col(1)
Xonly when formatting manual pages, unless the target terminal (c.f. the
X.B \-T
Xoption) is contained within an internal list of devices which don't require
Xit.  This option forces the output to be filtered by
X.IR col(1) ,
Xeven if you are reviewing a pre-formatted manual page or formatting a
Xmanual page for a terminal type in this list.
X.IP "\fB\-f\fR"
XForce formatting.  When this option is specified,
X.I man
Xignores the presence of any pre-formatted manual pages.
X.IP "\fB\-w\fR"
XWhich files?  When this option is specified, the pathnames of the manual
Xpage files will be displayed rather than the manual pages themselves.
XThis option implies the
X.B \-a
Xoption.  The
X.B \-f
Xoption may be specified to display only unformatted source files pathnames.
X.IP "\fB\-T\fR term"
XTerminal type.  Specifies the target device for
X.I nroff(1)
Xformatting.  The name of the default device is built into the
X.I man
Xprogram, usually "lp".  This information is used when formatting manual
Xpage sources -- it has no effect when reviewing formatted manual pages.
XAs initially configured,
X.I col(1)
Xwill not be invoked when formatting for the following devices:  300, 300s,
X450, 37, 4000a, 382, 4014, tek, 1620, and X.
X.IP "\fB\-U\fR"
XUpdate mode.  In this mode manual pages are not displayed, but rather the
Xformatted versions are updated if required.
X.I Man
Xwill compare a manual page source file to its formatted version, and
Xif the formatted version is missing or out of date one will be created.
XThe formatted output will be run through the
X.I col(1)
Xand
X.I compress(1L)
Xcommands.
XIf
X.B \-f
Xhas been specified, the update will always occur.  If
X.B \-w
Xhas been specified, then the update will be suppressed, and the pathname
Xof the source file will be displayed instead.
XThis option implies
Xthe
X.B \-a
Xand
X.B \-s
Xoptions, and is intended for use by the
X.I catman(1L)
Xcommand.
X.PP
X.I Man
Xsupports file packing (".z" file suffix) and compression (".Z" file suffix)
Xto save space.  When a manual page requires formatting, it is run through
Xthe
X.I tbl
Xand
X.I eqn
Xpre-processors as well as the
X.I nroff
Xformatter.
X.PP
XThere are several conventions for organizing manual pages, and
X.I man
Xmay be configured locally as appropriate.  For example, the
X.I ls(1)
Xmanual page could appear in any of the following ways:
X.RS
X.nf
X.sp
X.ta 10 35
X.I "system	source	formatted"
XSystem V	/usr/man/u_man/man1/ls.1	/usr/man/u_man/cat1/ls.1
XBSD	/usr/man/man1/ls.1	/usr/man/cat1/ls.1
XXENIX	/usr/man/man.C/ls.C	/usr/man/cat.C/ls.C
X.fi
X.RE
X.PP
XWhen a manual page isn't found by scanning the manual directories, a
Xcross-reference index may be consulted.  The format of the index is:
X.RS
X.sp
X<command> <manpage> <section>
X.RE
X.PP
XFor example, the following entry would correctly locate the manual page for
X.IR strcpy :
X.RS
X.sp
Xstrcpy string 3
X.sp
X.RE
XText beginning with a "#" pound sign is ignored as a comment.
X.PP
XThe
X.I catman
Xcommand scans manual directories looking for manual pages to format.
XIt also notifies you when the manual page source is missing for a formatted
Xmanual page.
X.I Catman
Xuses the
X.B \-U
Xoption of
X.I man
Xto perform the update.  Any command line options specified are passed along to
X.IR man .
XFor example, use "catman \-w" to display the manual pages which require
Xupdate without actually performing the update.  The list of directories
Xscanned is contained within the
X.I catman
Xscript.
X.I
X.SH FILES
X.ta 20 30
X.nf
X/usr/man/...	manual directories
X  .../man\fIsection\fR/*	unformatted source (UNIX naming)
X  .../man.\fIsection\fR/*	unformatted source (XENIX naming)
X  .../cat\fIsection\fR/*	formatted text (UNIX naming)
X  .../cat.\fIsection\fR/*	formatted text (XENIX naming)
X/usr/man/index	cross-reference index
Xtbl,eqn,nroff	to format manual pages
Xcol	to filter output
Xzcat,pcat	to examine compressed entries
Xcompress	to compress updated entries
Xless,$PAGER	output pager
X.fi
X.SH SEE ALSO
Xnroff(1), col(1), man(7)
X.SH BUGS
XProblems will occur if the command name plus the man page suffix exceed
Xthe allowable file name length.
X.PP
X.I Man
Xdoes not particularly care about filename suffixes -- you can call it
X"pathalias.1" or "pathalias.1L".  However, if you call it both,
X.I man
Xwill ignore all but one of them.
X.PP
XAlternate description:  R'sTFM.
X.SH AUTHOR
XChip Rosenthal (chip@vector.uucp)
END_OF_FILE_man.man
    size="`wc -c < man.man`"
    if test 5651 -ne "$size" ; then
	echo "man.man: extraction error - got $size chars"
    fi
fi
if test -f catman -a "$1" != "-c" ; then
    echo "catman: file exists - will not be overwritten"
else
    echo "x - catman (file 9 of 11, 852 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_catman' > catman
X: '@(#) catman 1.1 88/12/30 20:42:29'
X#
X# catman - search for and format manual pages
X#
X# Mon Dec 26 17:10:06 CST 1988 - C. Rosenthal (chip@vector.UUCP)
X#	Original composition.
X
X
X# list of directories in which to look for man pages
XDIRLIST="/usr/man/local"
X
Xecho "$0: checking for man pages which need to be formatted . . ." 1>&2
Xfor dir in $DIRLIST ; do
X    cd $dir
X    for d in man* ; do
X	ls $d | \
X	    sed -e "s!\(.*\)\.\(.*\)\.*[zZ]*!man -U $* \2 \1!" | \
X	    sh -$-
X    done
Xdone
X
Xecho "$0: checking for man pages with missing source . . ." 1>&2
Xfor dir in $DIRLIST ; do
X    cd $dir
X    for d in cat* ; do
X	m=`echo "$d" | sed -e 's/^cat/man/'`
X	ls $d |								\
X	    sed								\
X		-e 's!\.*[zZ]$!!'					\
X		-e "s!.*!$dir/$m/&!"					\
X		-e 's!.*!test \! -f & \&\& echo "&: file not found"!' |	\
X	    sh -$-
X    done
Xdone
X
Xecho "$0: done"
Xexit 0
END_OF_FILE_catman
    size="`wc -c < catman`"
    if test 852 -ne "$size" ; then
	echo "catman: extraction error - got $size chars"
    fi
fi
if test -f Install -a "$1" != "-c" ; then
    echo "Install: file exists - will not be overwritten"
else
    echo "x - Install (file 10 of 11, 84 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_Install' > Install
X# @(#) Install 1.1 88/12/30 20:42:15
X$B/man		man
X$B/catman	catman
X$M1/man.1	man.man
END_OF_FILE_Install
    size="`wc -c < Install`"
    if test 84 -ne "$size" ; then
	echo "Install: extraction error - got $size chars"
    fi
fi
if test -f Makefile -a "$1" != "-c" ; then
    echo "Makefile: file exists - will not be overwritten"
else
    echo "x - Makefile (file 11 of 11, 1539 chars)"
    sed -e 's/^X//' << 'END_OF_FILE_Makefile' > Makefile
X
X# @(#) Makefile 1.1 88/12/30 20:42:20
X# Makefile for "man" (generated by makemake version 1.00.02)
X# Created by bin@vector on Fri Dec 30 20:40:10 CST 1988
X
XSHELL = /bin/sh
XCC = cc
XDEFS = 
XLIBS = -lx
XDEBUG = 
XCOPTS = -O
XLOPTS = 
XLINTFLAGS = -DLINT
XSHAR1 = README man.h patchlevel.h
XSHAR2 = man.man catman Install Makefile
X
XCMD = man
X
XSRCS = man.c lookup.c index.c manpage.c
X
XOBJS = man.o lookup.o index.o manpage.o
X
X# Any edits below this line will be lost if "makemake" is rerun!
X
XCFLAGS = $(COPTS) $(DEFS) $(DEBUG)
XLFLAGS = $(LOPTS) $(DEBUG)
X
Xall:		$(CMD)
Xinstall:	all		; inst Install
Xclean:				; rm -f $(CMD) $(OBJS) a.out core $(CMD).lint
Xclobber:	clean		; inst -u Install
Xlint:		$(CMD).lint
X
X$(CMD):		$(OBJS)
X		$(CC) $(LFLAGS) -o $@ $(OBJS) $(LIBS)
X
X$(CMD).lint:	$(CMD)
X		lint $(LINTFLAGS) $(DEFS) $(SRCS) $(LIBS) > $@
X
Xman.o: /usr/include/stdio.h man.c man.h patchlevel.h
Xlookup.o: /usr/include/stdio.h /usr/include/sys/ndir.h \
X        /usr/include/sys/stat.h /usr/include/sys/types.h lookup.c \
X        man.h
Xindex.o: /usr/include/ctype.h /usr/include/stdio.h index.c man.h
Xmanpage.o: /usr/include/stdio.h /usr/include/sys/signal.h man.h manpage.c
X
Xshar:		;
X		shar $(SHAR1) $(SRCS) $(SHAR2) > $(CMD).shar
X
X
Xmake:		;
X		makemake -i -v1.00.02 \
X		    -DSHELL='$(SHELL)' \
X		    -DCC='$(CC)' \
X		    -DDEFS='$(DEFS)' \
X		    -DLIBS='$(LIBS)' \
X		    -DDEBUG='$(DEBUG)' \
X		    -DCOPTS='$(COPTS)' \
X		    -DLOPTS='$(LOPTS)' \
X		    -DLINTFLAGS='$(LINTFLAGS)' \
X		    -DSHAR1='$(SHAR1)' \
X		    -DSHAR2='$(SHAR2)' \
X		    $(CMD) $(SRCS)
END_OF_FILE_Makefile
    size="`wc -c < Makefile`"
    if test 1539 -ne "$size" ; then
	echo "Makefile: extraction error - got $size chars"
    fi
fi
echo "done - 11 files extracted"
exit 0
--- cut here -----------------------------------------------------------------
-- 
Chip Rosenthal     chip@vector.UUCP    |      Choke me in the shallow water
Dallas Semiconductor   214-450-5337    |         before I get too deep.