[mod.sources] cpg and mdep

sources-request@genrad.UUCP (06/12/85)

From: bene!luke!steven <Steven List @ Benetics Corporation>

The following shar contains two programs and their documentation:

	cpg - a C source file formatter
	mdep - a make dependency list generator

[ moderator's notes:  cpg.c did not extract properly (I got 23652 rather
  than the 23488 characters expected, yet it seems to compile fine.
  Also, cpg uses getopt, and mdep does NOT use the directory library
  routines, rather parses directories itself.
]

CPG is a little tool developed locally to enable us to produce listings
that had both line numbers and nesting level indication for our code.
My incentive was due to the lack of any such facility.  Some of the code
in cpg is borrowed from cpr (came accross the net a while back), but
most of it is completely original.  Those of you who have seen other
postings of mine, or see some more, will find that they include cpg
triggers throughout.

MDEP provides programatically what Larry Wall and others have done in
their makefiles (makedepend and make depend).  It will search out and
list all include files needed to make a module.  Hopefully, this will
find some legitimate use out there.  We use it regularly here.

Please forgive the fact that these (and all my programs) are System III
specific.  It's the only system that I have access to.  If anyone out
there modifies them so that they are selectable (with ifdefs or
whatever) by version, please send them back to me.

Comments, improvements, and whatever are more than welcome.

Steven
***
*  Steven List @ Benetics Corporation  *  (415) 940-6300
*  {cdp,greipa,idi,oliveb,sun,tolerant}!bene!luke!steven
***
======================== Cut Here ======================================
#! /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:
#	cpg.1
#	mdep.1
#	cpg.c
#	mdep.c
# This archive created: Mon Jun 10 12:31:30 1985
export PATH; PATH=/bin:$PATH
echo shar: extracting "'cpg.1'" '(4945 characters)'
if test -f 'cpg.1'
then
	echo shar: will not over-write existing file "'cpg.1'"
else
sed 's/^	X//' << \SHAR_EOF > 'cpg.1'
	X.so /b/doc/nroffmacros/manmac
	X.TH "cpg" "1" "Benetics Local"
	X.ds C \fIcpg\fR
	X.tr ~  
	X.fi
	X.ad b
	X.SH NAME
	Xcpg - C source listing formatter
	X.SH SYNOPSIS
	Xcpg [ -t tabstop ] [ file... ]
	X.SH DESCRIPTION
	X\*C is a C language source listing formatter.  It employs certain
	Xtriggers to perform its formatting.  Those same triggers may be used to
	Xextract in-line documentation to create documentation.  At the end of
	Xthe listing produced by \*C is a table of contents of all files and
	Xfunctions contained in the current listing.  The table of contents is
	Xsorted alphabetically by function and file.
	X.P
	XThe listing produced by \*C includes on each line a line number.  On each
	Xline containing any braces ({}), there will also be a
	Xnesting level indicator.  The nesting level indicator includes a number
	X(the current nesting level) and a directional character.  The
	Xdirectional characters are:
	X.IP > 6
	XThe nesting level increased on this line
	X.IP < 6
	XThe nesting level decreased on this line
	X.IP * 6
	XThe nesting level changed both ways, with a net change of zero
	X.P
	XThe triggers that \*C recognizes are itemized below.  Each must appear
	Xin column 1.
	X.TP
	X<formfeed>
	XA formfeed will cause a new page to be started with a full header.
	X.TP
	X/*F filename *<anything>
	XThe file name may be specified in a comment preceding a descriptive
	Xheader block.  The filename argument must be delimited by asterisks in
	Xthe trigger.  The filename will appear in all page headings up to the
	Xnext filename trigger or the next file.  A filename comment block
	X\fBmust\fR be terminated by the endofblock trigger (see below).
	XThis trigger will print as a line in the listing.  This trigger causes
	Xthe start of a new page (form feed) in the listing, with printing of the
	Xpage header including the current file name.
	X.TP
	X/*H funcname *<anything>
	XThe function name may be specified in a comment preceding a descriptive
	Xheader block.  The funcname argument must be delimited by asterisks in
	Xthe trigger.  The funcname will appear in all page headings up to the
	Xnext funcname trigger or the next file.  A funcname comment block
	X\fBmust\fR be terminated by the endofblock trigger (see below).
	XThis trigger will print as a line in the listing.  This trigger causes
	Xthe start of a new page (form feed) in the listing, with printing of the
	Xpage header including the current function name.
	X.TP
	X/*E*/
	XThis is the endofblock trigger.  Everything between the last filename or
	Xfuncname trigger and the endofblock trigger will be passed straight
	Xthrough by \*C without evaluation of nesting levels, comments, or quoted
	Xstrings.  Thus, a header block is treated as one long comment by \*C.
	XThis trigger will print as a line in the listing.
	X.TP
	X/*P*/
	XThis is a page eject trigger.  It will not print in the listing, but
	Xwill be counted for line numbering purposes.  This trigger causes the
	Xpage heading, title, and subtitle to be reprinted based on their current
	Xvalues (see title and subtitle below).
	X.TP
	X/*S <text> */
	XThis is the subtitle trigger.  It determines the contents of the second
	Xtitle line on the page header.  All characters after the initial space
	Xand up to but not including the following asterisk (required) are
	Xincluded as part of the subtitle.  This trigger will not print in the
	Xlisting but will be counted for line numbering purposes.
	X.TP
	X/*T <text> */
	XThis is the title trigger.  It determines the contents of the first
	Xtitle line on the page header.  All characters after the initial space
	Xand up to but not including the following asterisk (required) are
	Xincluded as part of the title.  This trigger will not print in the
	Xlisting but will be counted for line numbering purposes.
	X.SS Options
	X.IP "-t tabstop" 12
	XThe tabstop argument to the -t option specifies how to expand tabs.  The
	Xexpansion is performed automatically with a tabstop of 8 if none is
	Xspecified.
	X.SS Arguments
	X.IP file 12
	XAny number of file names may be specified on the command line (within
	Xlimits set by whichever shell is used).  Each file will be formatted and
	Xits name added to the table of contents.  If no file names are
	Xspecified, \*C will read the standard input.
	X.SH FILES
	X.IP "/tmp/toc_XXXXXX" 20
	Xtemporary file for building the table of contents.
	X.SH "SEE ALSO"
	Xdtab(1), nl(1), pr(1), sort(1)
	X.SH NOTES
	XThis tool was developed at Benetics Corporation.
	X.P
	XA side note: \*C also properly processes comments in shell scripts and
	Xmakefiles.  These comments are correctly handled when the comment
	Xcharacter (# or :) is the first nonblank character on a line.  In order
	Xto facilitate documentation of shell scripts, \*C recognizes the
	Xsequences #{ and #} as the beginning and ending of nesting, and treats
	Xthem as it does in C program sources.  Thus lengthy for, if, while, and
	Xcase statements may be more clearly documented as to nesting levels,
	Xparticulary in shell scripts.
	X.SH AUTHOR
	X.na
	X.nf
	XSteven M. List
	XBenetics Corporation
	XMountain View, CA.
	X{cdp,idi,greipa,oliveb,sun,tolerant}!bene!luke!steven
SHAR_EOF
if test 4945 -ne "`wc -c < 'cpg.1'`"
then
	echo shar: error transmitting "'cpg.1'" '(should have been 4945 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'mdep.1'" '(2641 characters)'
if test -f 'mdep.1'
then
	echo shar: will not over-write existing file "'mdep.1'"
else
sed 's/^	X//' << \SHAR_EOF > 'mdep.1'
	X.TH "mdep" "1" "Benetics Local"
	X.fi
	X.ad b
	X.SH NAME
	Xmdep - generate the dependency list for C sources
	X.SH SYNOPSIS
	Xmdep [ -D symbol ] [ -I searchpath ] [ -r ] [ -x \fIabc\fR ]
	X.br
	X     sourcefiles
	X.SH DESCRIPTION
	XThe purpose of \fImdep\fR is to generate the list of include file
	Xdependencies for some source file.  The source files are expected to be
	XC language source files, and may include either .c or .h files (or any
	Xother file, for that matter).  The source files are examined for lines
	Xcontaining the `#include' statement (also `$include' for those of us who
	Xuse UNIFY), and those file names are included in the list of dependencies.
	X.P
	XAdditional features are provided by command line options: recursive
	Xexpansion of include files (includes that include includes), suppression
	Xof expansion of specific include files, and Defining symbols so that the
	Xappropriate dependencies are generated.
	X.SS Options
	X.IP "-D symbol" 16
	XDefine a symbol (as you would to the C preprocessor) to cause the
	Xrecognition of the appropriate sections of code.  Since \fImdep\fR does
	Xnot read #define statements in the source files, this is the only way of
	Xcausing symbols to be defined.  Conversely, symbols are #undef by
	Xdefault.  Multiple occurrences of the -D option, with argument, may
	Xappear in the command line.
	X.IP "-I searchpath" 16
	XDefine a directory to be searched for include files, as is done for the
	XC preprocessor.  Multiple occurrences of the -I option, with argument,
	Xmay appear in the command line.
	X.IP "-r" 16
	XPerform recursive expansion of include files.  Thus, if an include file
	Xincludes other files, include those file names (and so on) in the
	Xdependency list.  This option is moderated by the -x option.
	X.IP "-x filename" 16
	XExclude a file from recursive expansion.  The filename associated with
	Xthis option may omit the .h suffix, and \fImdep\fR will append the
	Xsuffix.
	X.SS Arguments
	X.IP sourcefile 16
	XOne or more C source files to be processed.  The files may actually be
	Xany ascii file.
	X.SH EXAMPLES
	XThe following example shows the command to process mdep.c and the output
	Xfrom the command:
	X.nf
	X.RS 6
	X.P
	X% mdep -r mdep.c
	X.sp
	Xmdep.o: \\
	X        /usr/include/sys/types.h \\
	X        /usr/include/sys/dir.h \\
	X        /usr/include/stdio.h 
	X.RE
	X.fi
	X.P
	XTo generate the dependency list for file `foo.c' that includes `foo.h'
	Xwhich includes some standard files:
	X.nf
	X.RS 6
	X.P
	X% mdep -r -I/usr/local/include foo.c
	X.sp
	Xfoo.o: \\
	X        ./foo.h \\
	X        /usr/include/stdio.h 
	X.RE
	X.fi
	X.SH "SEE ALSO"
	Xmake(1)
	X.SH AUTHOR
	X.nf
	X.na
	XSteven M. List
	XBenetics Corporation
	XMountain View, CA.
	X{cdp,idi,greipa,oliveb,sun,tolerant}!bene!luke!steven
	X.ad b
SHAR_EOF
if test 2641 -ne "`wc -c < 'mdep.1'`"
then
	echo shar: error transmitting "'mdep.1'" '(should have been 2641 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'cpg.c'" '(23488 characters)'
if test -f 'cpg.c'
then
	echo shar: will not over-write existing file "'cpg.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'cpg.c'
	X/*Tcpg - c program source listing formatter */
	X/*F cpg.c **********************************************************
	X *
	X *                           cpg.c
	X *
	X *    DESCRIPTION OF FILE CONTENTS:
	X *      C source program listing formatter source.
	X *
	X *  Cpg provides the facility to print out a C language source file
	X *  with headers, nesting level indicators, and table of contents.
	X *  It makes use of "triggers" for page headings, titles and
	X *  subtitles, and pagination.  It also recognizes function
	X *	declarations and form feeds and treats them appropriately.
	X *
	X *  (c) 1985  Steven List
	X *            Benetics Corporation
	X *            Mountain View, CA
	X *            {cdp,greipa,idi,oliveb,sun,tolerant}!bene!luke!steven
	X *
	X *******************************************************************/
	X/*E*/
	X/*S includes, defines, and globals */
	X/*P*/
	X#include <stdio.h>
	X#include    <ctype.h>
	X#include    <time.h>
	X
	X#define EQ ==
	X#define NE !=
	X#define GT >
	X#define GE >=
	X#define LT <
	X#define LE <=
	X#define OR ||
	X#define AND &&
	X
	X#define TRUE 1
	X#define FALSE 0
	X#define YES 1
	X#define NO 0
	X
	X#define SPACE ' '
	X#define NUL '\0'
	X
	Xtypedef short   BOOL;
	X
	X#define INULL -32768
	X#define LNULL -2147483648
	X
	X#define MAX(a,b) ((a) > (b) ? (a) : (b))
	X#define MIN(a,b) ((a) < (b) ? (a) : (b))
	X#define ABS(a) ((a) >= 0 ? (a) : -(a))
	X
	X#define LINESINHEAD 6
	X#define LPP 60
	X#define MAXWIDTH    130
	X
	X#define notend(ll) ((ll[0] EQ SLASH AND ll[1] EQ STAR AND ll[2] EQ 'E') ? FALSE : TRUE)
	X#define SLASH   '/'
	X#define STAR    '*'
	X#define DQUOTE '"'
	X#define SQUOTE '\''
	X#define BSLASH '\\'
	X
	Xchar    tim_lin[40];
	Xchar    *file_name;
	Xchar    fh_name[50] = "";
	Xchar    fnc_name[40] = "";
	Xchar    subttl[70] = "";
	Xchar    title[70] = "";
	Xchar    tocname[] = "/tmp/toc_XXXXXX";
	X
	Xint     nlvl = 0;
	X
	Xint     page_line = LPP+1;
	Xint     pageno = 1;
	X
	Xint     tabstop = 8;
	X
	Xint		infunc = FALSE;
	Xint     logging = 0;
	X
	Xint     incomment = FALSE;
	Xint     insquote = FALSE;
	Xint     indquote = FALSE;
	X
	Xchar    specline = FALSE;
	X
	XFILE    *tocfile;
	XFILE    *fd;
	X
	Xchar    *pgm;
	X
	Xchar    *ReservedWord[]  = { 
	X	 "auto", "bool", "break", "case", "char", "continue",
	X	 "default", "do", "double", "else", "entry", "enum",
	X	 "extern", "float", "for", "goto", "if",
	X	 "int", "long", "register", "return", "short",
	X	 "sizeof", "static", "struct", "switch",
	X	 "typedef", "union", "unsigned", "void", "while",
	X	 NULL };
	X
	X/*S main function */
	X/*Hmain */
	X/*E*/
	X
	Xmain (ac, av)
	Xint     ac;
	Xchar    **av;
	X{
	X    char    *std_input = "standard input";	/* input file name		*/
	X
	X    long    cur_time;				/* place for current raw time	*/
	X
	X    long    *time();				/* return raw time from system	*/
	X
	X    register int i;					/* temporary for indexes, etc.	*/
	X
	X    struct tm *tim;					/* return from localtime		*/
	X    struct tm *localtime ();
	X
	X    char    cmdbuf[40];				/* place to format sort command	*/
	X
	X    char    *strrchr ();			/* find char from end - rindex	*/
	X
	X    extern char *optarg;			/* option argument pointer		*/
	X    extern int   optind;			/* option index					*/
	X
	X    if (pgm = strrchr (pgm, "/")) pgm++;	/* set program name		*/
	X    else pgm = pgm;
	X
	X    while ((i = getopt (ac, av, "l:t:")) NE EOF)
	X    {
	X        switch (i)
	X        {
	X            case    'l':
	X                logging = atoi (optarg);
	X                break;
	X            case    't':
	X                tabstop = atoi (optarg);
	X                break;
	X            default:
	X                fprintf (stderr,
	X                    "usage: %s [ -t <tabstop> ] [ files... ]\n",
	X                        pgm);
	X        }
	X    }
	X
	X	/* ------------------------------------------------------------ */
	X	/* set up the date/time portion of page headings                */
	X	/* ------------------------------------------------------------ */
	X
	X    time(&cur_time);
	X
	X    tim = localtime (&cur_time);
	X    sprintf (tim_lin, "Printed: %02d/%02d/%02d at %2d:%02d %s",
	X        tim->tm_mon + 1, tim->tm_mday, tim->tm_year,
	X        tim->tm_hour GT 12 ? tim->tm_hour - 12 : tim->tm_hour,
	X        tim->tm_min,
	X        tim->tm_hour GE 12 ? "PM" : "AM" );
	X
	X	/* ------------------------------------------------------------ */
	X	/* create the temporary file for the table of contents          */
	X	/*   don't bother if output is to a terminal                    */
	X	/* ------------------------------------------------------------ */
	X
	X    mktemp (tocname);
	X    if (!isatty (1))
	X    {
	X        tocfile = fopen (tocname, "w");
	X        if (!tocfile)
	X        {
	X            fprintf (stderr, "%s: unable to create tocfile %s\n",
	X                pgm, tocname);
	X            exit (2);
	X        }
	X    }
	X
	X	/* ------------------------------------------------------------ */
	X	/* if no file names, read standard input                        */
	X	/* ------------------------------------------------------------ */
	X
	X    if (optind EQ ac)
	X    {
	X        fd = stdin;
	X        file_name = std_input;
	X        dofile (fd);
	X    }
	X    else
	X    {
	X	/* ------------------------------------------------------------ */
	X	/* process each file named on the command line                  */
	X	/* ------------------------------------------------------------ */
	X
	X        for (i = optind; i LT ac; i++)
	X        {
	X	/* ------------------------------------------------------------ */
	X	/* special file name `-' is standard input                      */
	X	/* ------------------------------------------------------------ */
	X
	X            if (strcmp (av[i], "-") EQ 0)
	X            {
	X                fd = stdin;
	X                file_name = std_input;
	X            }
	X            else
	X            {
	X                fd = fopen (av[i], "r");
	X                if (fd EQ NULL)
	X                {
	X                    fprintf (stderr,
	X                        "cpg: unable to open %s\n", av[i]);
	X                }
	X            }
	X            if (fd NE NULL)
	X            {
	X                strcpy (fh_name, av[i]);
	X                file_name = av[i];
	X                dofile (fd);
	X                fclose (fd);
	X            }
	X        }
	X    }
	X
	X    fflush (stdout);
	X
	X	/* ------------------------------------------------------------ */
	X	/* sort and print the table of contents - straight alpha order  */
	X	/* on function and file name                                    */
	X	/* ------------------------------------------------------------ */
	X
	X    if (!isatty (1))
	X    {
	X        fclose (tocfile);
	X        sprintf (cmdbuf, "sort +1 -2 +0 -1 -u -o %s %s", tocname, tocname);
	X        system (cmdbuf);
	X        tocfile = fopen (tocname, "r");
	X        if (!tocfile)
	X        {
	X            fprintf (stderr, "%s: unable to read tocfile\n", pgm);
	X            exit (2);
	X        }
	X        else
	X        {
	X            tocout (tocfile);
	X            fclose (tocfile);
	X            if (!logging) unlink (tocname);
	X        }
	X    }
	X
	X    fprintf (stdout, "\f");
	X
	X    exit (0);
	X}
	X/*Sdofile - process an input file */
	X/*Hdofile*/
	X/*E*/
	Xdofile (fd)
	XFILE    *fd;
	X{
	X    register int i;					/* temporary					*/
	X
	X    int     lineno = 1;				/* line number in current file	*/
	X
	X    register char *line;			/* current line pointer			*/
	X
	X    char    ibuf[MAXWIDTH];			/* original input line			*/
	X    char    ebuf[MAXWIDTH];			/* line with tabs expanded		*/
	X
	X    char    *strrchr ();			/* find char from start - index	*/
	X
	X    register char *p;				/* temporary char pointer		*/
	X
	X	/* ------------------------------------------------------------ */
	X	/* initialize the function name to `.' - unknown                */
	X	/* retrieve the basename portion of the file name               */
	X	/* ------------------------------------------------------------ */
	X
	X    strcpy (fnc_name, ".");
	X    if (p = strrchr (fh_name, '/')) p++;
	X    else p = fh_name;
	X
	X	/* ------------------------------------------------------------ */
	X	/* if building TOC, add this entry                              */
	X	/* ------------------------------------------------------------ */
	X
	X    if (!isatty (1))
	X        fprintf (tocfile,
	X            "%s %s %d %d\n", p, fnc_name, pageno, lineno);
	X
	X	/* ------------------------------------------------------------ */
	X	/* if tabs are to be expanded, use the expansion buffer         */
	X	/* ------------------------------------------------------------ */
	X
	X    if (tabstop) line = ebuf;
	X    else         line = ibuf;
	X
	X	/* ------------------------------------------------------------ */
	X	/* process each line in the file, looking for triggers          */
	X	/* ------------------------------------------------------------ */
	X
	X    while (fgets (ibuf, MAXWIDTH, fd) NE NULL)
	X    {
	X        if (logging GE 9) fprintf (stderr, "%s: LOG: %s", pgm, line);
	X	/* ------------------------------------------------------------ */
	X	/* expand the input line                                        */
	X	/* ------------------------------------------------------------ */
	X
	X        expand (ebuf, ibuf);
	X
	X        if (line[0] EQ SLASH AND line[1] EQ STAR)
	X        {
	X	/* ------------------------------------------------------------ */
	X	/* comment found - could be a trigger                           */
	X	/* ------------------------------------------------------------ */
	X
	X            switch (line[2])
	X            {
	X                case 'F':
	X                case 'H':
	X                {
	X                    if (logging GE 9) fprintf (stderr, "F/H header\n");
	X                    header (&lineno, line, fd);
	X                    break;
	X                }
	X                case 'P':
	X                {
	X                    if (logging GE 9) fprintf (stderr, "page break\n");
	X                    print_head ();
	X                    lineno++;
	X                    break;
	X                }
	X                case 'S':
	X                {
	X                    if (logging GE 9) fprintf (stderr, "subtitle\n");
	X                    getname (line, subttl);
	X                    lineno++;
	X                    break;
	X                }
	X                case 'T':
	X                {
	X                    if (logging GE 9) fprintf (stderr, "title\n");
	X                    getname (line, title);
	X                    /* print_head (); */
	X                    lineno++;
	X                    break;
	X                }
	X                default:
	X                {
	X                    if (logging GE 9) fprintf (stderr, "other comment\n");
	X                    print (&lineno, line);
	X                    break;
	X                }
	X            }
	X        }
	X        else
	X        {
	X	/* ------------------------------------------------------------ */
	X	/* not a comment - check for function declaration               */
	X	/* if a form feed is found, start a new page with header        */
	X	/* ------------------------------------------------------------ */
	X
	X            if (logging GE 9) fprintf (stderr, "not a comment\n");
	X            if (!nlvl AND !isatty (1)) infunc = ckfunc (lineno, line);
	X			if (*line EQ '\f') print_head ();
	X            else print (&lineno, line);
	X        }
	X    }
	X
	X    page_line = LPP+1;		/* force new page after file			*/
	X    title[0] = NUL;			/* clear title and subtitle				*/
	X    subttl[0] = NUL;
	X
	X    return;
	X}
	X/*Sheader - construct and print header box */
	X/*Hheader*/
	X/*E*/
	Xheader  (lineno, line, fd)
	Xregister int     *lineno;
	Xregister char    *line;
	Xregister FILE    *fd;
	X{
	X    register char *p;
	X
	X    char    *strrchr ();
	X
	X    if (line[2] EQ 'F')
	X    {
	X        getname (line, fh_name);
	X        strcpy (fnc_name, ".");
	X    }
	X    else if (line[2] EQ 'H')
	X    {
	X        getname (line, fnc_name);
	X    }
	X
	X    if (p = strrchr (fh_name, '/')) p++;
	X    else p = fh_name;
	X    if (!isatty (1))
	X        fprintf (tocfile,
	X            "%s %s %d %d\n", p, fnc_name, pageno, *lineno);
	X
	X    print_head ();
	X
	X    print (lineno, line);
	X
	X    while (fgets (line, MAXWIDTH, fd) NE NULL AND
	X            notend (line))
	X    {
	X        if (line[0] EQ SLASH AND line[1] EQ STAR AND line[2] EQ 'P')
	X        {
	X            print_head ();
	X            (*lineno)++;
	X        }
	X        else
	X        {
	X            print (lineno, line);
	X        }
	X    }
	X
	X    print (lineno, line);
	X
	X    return;
	X}
	X/*Sgetname - get a string from a signal line */
	X/*Hgetname */
	X/*E*/
	Xgetname (line, name)
	Xregister char    *line;
	Xregister char    *name;
	X{
	X    register int     i;
	X    register int     j;
	X
	X	/* ------------------------------------------------------------ */
	X	/* skip leading spaces in the trigger line                      */
	X	/* copy up to trailing asterisk or end-of-line                  */
	X	/* strip trailing spaces                                        */
	X	/* ------------------------------------------------------------ */
	X
	X    for (i = 3; isspace(line[i]) AND i LT MAXWIDTH; i++);
	X
	X    for (j = 0; line[i] AND line[i] NE '*'; i++, j++)
	X    {
	X        name[j] = line[i];
	X    }
	X
	X    while (j-- GT 0 AND isspace (name[j]));
	X
	X    name[++j] = NUL;
	X
	X    return;
	X}
	X/*Sprint - print a line with line number */
	X/*Hprint */
	X/*E*/
	Xprint (lineno, line)
	Xregister int     *lineno;
	Xregister char    *line;
	X{
	X    register int llen = strlen (line);
	X    register int i;
	X
	X    register char sc = specline ? '*' : ' ';
	X
	X    int     j = 0;
	X
	X    register char    dc = NUL;
	X    char    *strchr();
	X
	X	/* ------------------------------------------------------------ */
	X	/* new page with header if page length is exceeded              */
	X	/* ------------------------------------------------------------ */
	X
	X    if (page_line GT LPP)
	X    {
	X        print_head ();
	X    }
	X
	X	/* ------------------------------------------------------------ */
	X	/* if brace(s) found,                                           */
	X	/*   modify the nesting level by the net nesting delta          */
	X	/*   select the indicator according to the net delta            */
	X	/*   if nexting is back to zero (none), clear function name     */
	X	/* ------------------------------------------------------------ */
	X
	X    if (fnd (line, &j))
	X    {
	X        nlvl += j;
	X
	X        if (j LT 0) dc = '<';
	X        else if (j EQ 0) dc = '*';
	X        else dc = '>';
	X
	X        i = nlvl;
	X        if (j LT 0) i++;
	X        fprintf (stdout, "%4d%c%2d%c ",
	X            (*lineno)++, sc, i, dc);
	X        if (nlvl EQ 0) strcpy (fnc_name, ".");
	X    }
	X    else
	X    {
	X        fprintf (stdout, "%4d%c    ", (*lineno)++, sc);
	X    }
	X
	X	/* ------------------------------------------------------------ */
	X	/* break up long lines by finding the first space form the end  */
	X	/* ------------------------------------------------------------ */
	X
	X    if (llen GT 71)
	X    {
	X        for (i = 70; i GE 0; i--)
	X        {
	X            if (line[i] EQ SPACE)
	X            {
	X                fprintf (stdout, "%*.*s \\\n", i, i, line);
	X                page_line++;
	X                break;
	X            }
	X        }
	X
	X        j = 79 - (llen - i);
	X
	X        for (j; j GE 0; j--) putc (SPACE, stdout);
	X
	X        fprintf (stdout, "%s", &line[i+1]);
	X    }
	X    else
	X    {
	X        fprintf (stdout, "%s", line);
	X    }
	X
	X    page_line++;
	X
	X    specline = FALSE;		/* true if function declaration		*/
	X
	X    return;
	X}
	X/*Sprint_head - print the page heading with page number */
	X/*Hprint_head */
	X/*E*/
	Xprint_head ()
	X{
	X    char    headbuf[80];
	X    register int len;
	X
	X    sprintf (headbuf, "[ %s | %s <- %s",
	X        tim_lin, fh_name, fnc_name);
	X
	X    for (len = strlen (headbuf); len LT 68; len++) headbuf[len] = SPACE;
	X
	X    sprintf (&headbuf[68], "Page %-4d ]", pageno++);
	X    fprintf (stdout, "\f\n");
	X    if (!isatty (1))
	X        fprintf (stdout, "_______________________________________\
	X________________________________________");
	X    fprintf (stdout, "\n%s\n", headbuf);
	X    fprintf (stdout, "[-------------------------------+------\
	X---------------------------------------]\n");
	X
	X    if (*title)
	X    {
	X        sprintf (headbuf, "[    %s", title);
	X    }
	X    else
	X    {
	X        sprintf (headbuf, "[    %s", fh_name);
	X    }
	X    for (len = strlen (headbuf); len LT 78; len++) headbuf[len] = SPACE;
	X    headbuf[78] = ']';
	X    fprintf (stdout, "%s\n", headbuf);
	X
	X    if (*subttl)
	X    {
	X        sprintf (headbuf, "[    %s", subttl);
	X    }
	X    else
	X    {
	X        sprintf (headbuf, "[    %s", fnc_name);
	X    }
	X    for (len = strlen (headbuf); len LT 78; len++) headbuf[len] = SPACE;
	X    headbuf[78] = ']';
	X    fprintf (stdout, "%s", headbuf);
	X
	X    if (!isatty (1))
	X        fprintf (stdout, "\r_______________________________________\
	X________________________________________");
	X    fprintf (stdout, "\n\n");
	X
	X    page_line = LINESINHEAD;
	X
	X    return;
	X}
	X/*S fnd - return true if a brace is found */
	X/*H fnd */
	X/*E*/
	Xfnd (in, nchg)
	Xregister char *in;
	Xregister int    *nchg;
	X{
	X#   define LBRACE   '{'
	X#   define RBRACE   '}'
	X#   define SHARP    '#'
	X#   define COLON    ':'
	X
	X    register found = FALSE;			/* true if keyword found		*/
	X
	X    register char blank = TRUE;		/* used to check for shell/make	*/
	X									/* comments beginning with #/:	*/
	X    register int inshcomment = FALSE;	/* true if in shell comment	*/
	X
	X    *nchg = 0;				/* initialize net change to zero		*/
	X
	X	/* ------------------------------------------------------------ */
	X	/* check each character of the line                             */
	X	/* ------------------------------------------------------------ */
	X
	X    for (in; *in; in++)
	X    {
	X        if (!incomment AND !inshcomment AND !indquote AND !insquote)
	X        {
	X            if (logging GE 9) fprintf (stderr, "not in comment or quote\n");
	X            if (*in EQ SLASH AND *(in+1) EQ STAR)
	X            {
	X                incomment = TRUE;
	X                blank = FALSE;
	X                if (logging GE 9) fprintf (stderr, "new comment\n");
	X            }
	X            else if (blank AND
	X                     ((*in EQ SHARP OR *in EQ COLON) AND
	X                     (*(in+1) NE LBRACE AND *(in+1) NE RBRACE))
	X                    )
	X            {
	X                inshcomment = TRUE;
	X                blank = FALSE;
	X                if (logging GE 9) fprintf (stderr, "new shell comment\n");
	X            }
	X            else if (*in EQ DQUOTE AND
	X                    (*(in-1) NE BSLASH OR *(in-2) EQ BSLASH))
	X            {
	X                indquote = TRUE;
	X                blank = FALSE;
	X                if (logging GE 9) fprintf (stderr, "new dquote\n");
	X            }
	X            else if (*in EQ SQUOTE AND
	X                    (*(in-1) NE BSLASH OR *(in-2) EQ BSLASH))
	X            {
	X                insquote = TRUE;
	X                blank = FALSE;
	X                if (logging GE 9) fprintf (stderr, "new squote\n");
	X            }
	X            else if (*in EQ LBRACE)
	X            {
	X                (*nchg)++;
	X                found = TRUE;
	X                blank = FALSE;
	X                if (logging GE 9) fprintf (stderr, "nest in\n");
	X            }
	X            else if (*in EQ RBRACE)
	X            {
	X                (*nchg)--;
	X                found = TRUE;
	X                blank = FALSE;
	X                if (logging GE 9) fprintf (stderr, "nest out\n");
	X            }
	X            else if (!isspace (*in))
	X            {
	X                blank = FALSE;
	X            }
	X        }
	X        else if (incomment AND *in EQ STAR AND *(in+1) EQ SLASH)
	X        {
	X            incomment = FALSE;
	X            if (logging GE 9) fprintf (stderr, "end comment\n");
	X        }
	X        else if (indquote AND *in EQ DQUOTE AND
	X                (*(in-1) NE BSLASH OR *(in-2) EQ BSLASH))
	X        {
	X            indquote = FALSE;
	X            if (logging GE 9) fprintf (stderr, "end dquote\n");
	X        }
	X        else if (insquote AND *in EQ SQUOTE AND
	X                (*(in-1) NE BSLASH OR *(in-2) EQ BSLASH))
	X        {
	X            insquote = FALSE;
	X            if (logging GE 9) fprintf (stderr, "end squote\n");
	X        }
	X    }
	X    
	X    return found;
	X}
	X/*Stocout - print out the table of contents */
	X/*Htocout */
	X/*E*/
	Xtocout (toc)
	XFILE    *toc;
	X{
	X    char    buf[80];
	X    char    filenam[80];
	X    char    fncnam[80];
	X    int     page;
	X    int     line;
	X
	X    char    outline[80];
	X
	X    register int toclines = 99;
	X
	X    while (fscanf (toc, "%s%s%d%d", filenam, fncnam, &page, &line) EQ 4)
	X    {
	X        if (toclines GT 54)
	X        {
	X            printf ("\f\n\
	X                             _____________________\n\
	X                             [ TABLE OF CONTENTS ]\r\
	X                             _____________________\n\n\
	X                File -> Function                     Page    Line\r\
	X________________________________________\
	X________________________________________\n\n");
	X            toclines = 0;
	X        }
	X
	X        toclines++;
	X
	X        printf ("\
	X    %16s -> %-16.16s ............ %3d   %5d\n",
	X            filenam, *fncnam EQ '.' ? "START" : fncnam, page, line);
	X    }
	X    return;
	X}
	X/*S expand - expand tabs to tabstop */
	X/*H expand */
	X/*E*/
	Xexpand (to, from)
	Xregister char *to;
	Xregister char *from;
	X{
	X    register int i;
	X    register int tofill;
	X
	X#   define BACKSPACE '\b'
	X#   define FORMFEED '\f'
	X#   define NEWLINE '\n'
	X#   define RETURN '\r'
	X#   define TAB '\t'
	X    
	X    i = 0;
	X
	X    while (*from)
	X    {
	X        switch (*from)
	X        {
	X            case    TAB:
	X                tofill = tabstop - (i % tabstop);
	X                i += tofill;
	X                while (tofill--) *(to++) = SPACE;
	X                break;
	X            case    NEWLINE:
	X            case    RETURN:
	X                i = 0;
	X            case    FORMFEED:
	X                *(to++) = *from;
	X                break;
	X            case    BACKSPACE:
	X                i--;
	X                *(to++) = *from;
	X                break;
	X            default:
	X                i++;
	X                *(to++) = *from;
	X                break;
	X        }
	X
	X        from++;
	X    }
	X
	X    *to = NUL;
	X
	X    return;
	X}
	X/*S ckfunc - check line for function declaration */
	X/*H ckfunc */
	X/*E*/
	X
	X#define isidchr(c) (isalnum(c) || (c == '_'))
	X
	Xckfunc (lineno, s)
	Xregister int lineno;
	Xregister char   *s;
	X{
	X    register char *p;
	X    register int  Cnt;
	X    register int  i;
	X    register int  result;
	X    register char found = FALSE;
	X
	X    static char *_fnm = "ckfunc";
	X
	X    char FunctionName[40];
	X
	X	if (logging GE 3)
	X	{
	X		fprintf (stderr,
	X			"%s<%s>: LOG: ckfunc called - line = %s",
	X			pgm, _fnm, s);
	X	}
	X
	X    if(!strcmp (fnc_name, ".") AND !incomment && !indquote && !insquote)
	X    {
	X        found = TRUE;
	X
	X        while (found)
	X        {
	X            found = FALSE;
	X            p = FunctionName;
	X            for (s; isascii (*s) && isspace (*s) && *s; s++);
	X            if( *s == '*' )
	X            {
	X                for (++s; isascii (*s) && isspace (*s) && *s; s++);
	X            }
	X
	X            if ((*s == '_') || isalpha(*s))
	X            {
	X                while (isidchr (*s)) *p++ = *s++;
	X
	X                *p = '\0';
	X
	X                for (found = FALSE, i = 0;
	X                     !found AND ReservedWord[i]; i++)
	X                {
	X                    if (!(result = strcmp (FunctionName, ReservedWord[i])))
	X                        found = TRUE;
	X
	X                    if  (result < 0) break;
	X                }
	X
	X                if (logging GE 3 AND found)
	X                {
	X                    fprintf (stderr,
	X                        "%s<%s>: LOG: reserved word = %s\n",
	X                        pgm, _fnm, FunctionName);
	X                }
	X            }
	X        }
	X
	X        if (logging GE 3)
	X        {
	X            fprintf (stderr,
	X                "%s<%s>: LOG: last word = %s\n",
	X                pgm, _fnm, FunctionName);
	X        }
	X        
	X        for (s; isascii (*s) && isspace (*s) && *s; s++);
	X
	X        if (*s EQ '(')
	X        {
	X            for (found = FALSE; *s AND !found; s++)
	X                found = *s EQ ')';
	X			
	X            if (found)
	X            {
	X				for (; *s AND isspace (*s); s++);
	X
	X				found = *s NE ';';
	X				
	X				if (found)
	X				{
	X					strcpy (fnc_name, FunctionName);
	X					fprintf (tocfile,
	X						"%s %s %d %d\n",
	X						fh_name, fnc_name, pageno-1, lineno);
	X					specline = TRUE;
	X				}
	X            }
	X        }
	X    }
	X
	X	if (logging GE 3)
	X	{
	X		fprintf (stderr,
	X	"%s<%s>: LOG: this line does%s contain a function declaration\n",
	X			pgm, _fnm, found ? "" : " not");
	X	}
	X
	X    return found;
	X}
SHAR_EOF
if test 23488 -ne "`wc -c < 'cpg.c'`"
then
	echo shar: error transmitting "'cpg.c'" '(should have been 23488 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'mdep.c'" '(19947 characters)'
if test -f 'mdep.c'
then
	echo shar: will not over-write existing file "'mdep.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'mdep.c'
	X/*T mdep - generate a list of make dependencies */
	X/*F mdep.c ***********************************************************
	X*
	X*                                  mdep.c
	X*
	X*  generate the list of make dependencies for a source file.  The
	X*  program can optionally do recursive expansions (for includes that
	X*  include includes) and suppress expansion of specific files.
	X*
	X*  This program was written for and tested ONLY on SYSTEM III.  While
	X*  there is the possibility that it will work on other systems, it
	X*  is not assured.
	X*
	X*  Permission to use, modify, and pass along this program is granted
	X*  as long as this notice is included.
	X*
	X*  (c) 1985		Steven List
	X*               Benetics Corporation
	X*               Mountain View, CA
	X*               {cdp,greipa,idi,oliveb,sun,tolerant}!bene!luke!steven
	X*
	X*********************************************************************/
	X/*E*/
	X/*S some global declarations and stuff */
	X/*Page Eject */
	X#ifdef BSD
	X#	define	strchr	index
	X#	define	strrchr	rindex
	X#endif BSD
	X
	Xchar	*Allocate ();
	Xchar	*ReAllocate ();
	X
	Xint		mstrcmp ();
	Xint		pstrcmp ();
	X
	X#include    <sys/types.h>
	X#include    <sys/dir.h>
	X#include    <stdio.h>
	X
	X/* ------------------------------------------------------------ */
	X/* some standard defines - easier to include than change        */
	X/* ------------------------------------------------------------ */
	X
	X#define EQ ==
	X#define NE !=
	X#define GT >
	X#define GE >=
	X#define LT <
	X#define LE <=
	X#define OR ||
	X#define AND &&
	X
	X#define TRUE 1
	X#define FALSE 0
	X#define YES 1
	X#define NO 0
	X
	X#define SPACE ' '
	X#define NUL '\0'
	X
	Xtypedef unsigned char   BOOL;
	X
	X#define INULL -32768
	X#define LNULL -2147483648
	X
	X#define MAX(a,b) ((a) > (b) ? (a) : (b))
	X#define MIN(a,b) ((a) < (b) ? (a) : (b))
	X#define ABS(a) ((a) >= 0 ? (a) : -(a))
	X
	Xint		MAXDIRS = 10;
	Xint		MAXNOEXP = 10;
	Xint		MAXFILES = 128;
	X
	X	/* ------------------------------------------------------------ */
	X	/* a description of each file in the search path                */
	X	/* ------------------------------------------------------------ */
	X
	Xstruct  file
	X{
	X    char    name[DIRSIZ+1];
	X    int     dirind;
	X}	*file;
	X
	X	/* ------------------------------------------------------------ */
	X	/* counts of directories and files under consideration          */
	X	/* ------------------------------------------------------------ */
	X
	Xint		nfil = 0;
	Xint		ndir = 0;
	X
	X	/* ------------------------------------------------------------ */
	X	/* the list of directories searched                             */
	X	/* ------------------------------------------------------------ */
	X
	Xchar	**dirs;
	X
	X	/* ------------------------------------------------------------ */
	X	/* exclusion table and counter                                  */
	X	/* ------------------------------------------------------------ */
	X
	Xchar	**noexp;				/* exclusion list				*/
	Xint		nx = 0;					/* number of exclusions			*/
	X
	X	/* ------------------------------------------------------------ */
	X	/* some stuff to handle #ifdef/#else/#endif                     */
	X	/* ------------------------------------------------------------ */
	X
	Xchar	**deftab;			/* list of objects defined				*/
	Xint		ndef = 0;			/* number of objects defined			*/
	X
	XBOOL    recursion = FALSE;
	X
	Xchar	*pgm;
	X
	X/*S main - control all processing, and do a lot of it */
	X/*H main *************************************************************
	X*
	X*                                   main
	X*
	X*  process the command line, set up the lists of files, and then 
	X*  process the input file(s).
	X*
	X*********************************************************************/
	X/*E*/
	Xmain (ac, av)
	Xregister int     ac;
	Xchar    *av[];
	X{
	X    int     		fcmp ();		/* compare two file entries		*/
	X    register int	i;				/* general purpose stuff		*/
	X    int    			strcmp ();		/* compare two strings			*/
	X
	X    char    *strchr ();
	X    char    *strrchr ();
	X
	X    /* getopt stuff */
	X
	X    extern char *optarg;
	X    extern int  optind;
	X
	X	/* ------------------------------------------------------------ */
	X	/* for logging and stuff, set up program name (basename only)   */
	X	/* ------------------------------------------------------------ */
	X
	X	if (pgm = strrchr (av[0], '/')) pgm++;
	X	else pgm = av[0];
	X
	X	/* ------------------------------------------------------------ */
	X	/* provide initial allocations of space for tables/lists        */
	X	/* ------------------------------------------------------------ */
	X
	X	dirs = (char **) Allocate (MAXDIRS, sizeof (char *));
	X	file = (struct file *) Allocate (MAXFILES, sizeof (struct file));
	X	noexp = (char **) Allocate (MAXNOEXP, sizeof (char *));
	X	deftab = (char **) Allocate (1, sizeof (char *));
	X
	X	/* ------------------------------------------------------------ */
	X	/* put the current directory in first - same as C compiler      */
	X	/* ------------------------------------------------------------ */
	X
	X	dirs[ndir] = (char *) Allocate (1, 2);
	X    strcpy (dirs[ndir], ".");      /* first is always current directory    */
	X    dirlist (dirs[ndir++]);
	X/*Page Eject*/
	X	/* ------------------------------------------------------------ */
	X	/* process the command line options                             */
	X	/* ------------------------------------------------------------ */
	X
	X    while ( (i = getopt (ac, av, "D:I:x:r")) NE EOF)
	X    {
	X        switch (i)
	X        {
	X			case	'D':			/* define objects				*/
	X				deftab[ndef] = (char *)
	X					Allocate (1, strlen (optarg) + 1);
	X				strcpy (deftab[ndef], optarg);
	X				deftab = (char **)
	X					ReAllocate (deftab, (++ndef) * sizeof (char *));
	X				break;
	X            case    'I':			/* search directory - like cc	*/
	X				ndir++;
	X				if (!dirlist (optarg)) 
	X				{
	X					dirs[ndir-1] = (char *)
	X						Allocate (1, strlen (optarg) + 1);
	X					strcpy (dirs[ndir-1], optarg);
	X					if (ndir GE MAXDIRS)
	X					{
	X						MAXDIRS += 10;
	X						dirs = (char **) ReAllocate (dirs,
	X										MAXDIRS * sizeof (char *));
	X					}
	X				}
	X				else ndir--;
	X                break;
	X            case    'x':			/* a file to exclude			*/
	X				noexp[nx] = (char *) Allocate (1, strlen (optarg) + 3);
	X                strcpy (noexp[nx], optarg);
	X				if (!strrchr (optarg, '.')) strcat (noexp[nx], ".h");
	X				nx++;
	X				if (nx GE MAXNOEXP)
	X				{
	X					MAXNOEXP += 10;
	X					noexp = (char **) ReAllocate (noexp,
	X										MAXNOEXP * sizeof (char *));
	X				}
	X                break;
	X            case    'r':			/* turn on recursive search		*/
	X                recursion = TRUE;
	X                break;
	X            default:
	X                fprintf (stderr,
	X                    "<%s> unknown argument - %c\n", pgm, i);
	X                break;
	X        }
	X    }
	X/*Page Eject*/
	X	/* ------------------------------------------------------------ */
	X	/* add /usr/include as the last of the directories - as cc      */
	X	/* ------------------------------------------------------------ */
	X
	X	dirs[ndir] = (char *) Allocate (1, strlen ("/usr/include") + 1);
	X    strcpy (dirs[ndir], "/usr/include");
	X    dirlist (dirs[ndir++]);
	X
	X	/* ------------------------------------------------------------ */
	X	/* sort the include file list for use with bsearch              */
	X	/* ------------------------------------------------------------ */
	X
	X    qsort (file, nfil, sizeof(struct file), fcmp);
	X
	X	/* ------------------------------------------------------------ */
	X	/* if we are doing recursive searches, also sort the exclusions */
	X	/* ------------------------------------------------------------ */
	X
	X    if (recursion) qsort (noexp, nx, sizeof noexp[0], pstrcmp);
	X
	X	/* ------------------------------------------------------------ */
	X	/* if there are any definitions, sort the define table          */
	X	/* ------------------------------------------------------------ */
	X
	X	if (ndef) qsort (deftab, ndef, sizeof (char *), pstrcmp);
	X
	X	/* ------------------------------------------------------------ */
	X	/* Now that we've complete the tedious job of setting up,       */
	X	/*  process each remaining command line argument (they are      */
	X	/*  expected to be C source file names)                         */
	X	/* ------------------------------------------------------------ */
	X
	X    for (i = optind; i LT ac; i++)
	X    {
	X        dofile (av[i], FALSE);
	X    }
	X
	X    exit (0);
	X}
	X/*S dirlist - expand a directory name into a list of include files */
	X/*H dirlist **********************************************************
	X*
	X*                                   dirlist
	X*
	X*  Examine each entry in a directory.  If a file is an include file
	X*  (name ends with .h), include it and the directory index in the
	X*  file list.
	X*
	X*********************************************************************/
	X/*E*/
	Xdirlist (dnam)
	Xregister char    *dnam;			/* directory path name				*/
	X{
	X    register int    i;			/* general purpose stuff			*/
	X
	X    register char   c;			/* ditto							*/
	X    register char   *ptr;		/* again							*/
	X
	X    char    *strrchr ();		/* find char from end				*/
	X
	X    static char   *fn = "dirlist";	/* function name for logging	*/
	X
	X    register FILE    *dir;		/* directory file stream			*/
	X
	X	struct direct direct;		/* place to read entries into		*/
	X
	X	/* ------------------------------------------------------------ */
	X	/* attempt to open the directory file - exit on error           */
	X	/* ------------------------------------------------------------ */
	X
	X    if ( (dir = fopen (dnam, "r")) EQ NULL)
	X    {
	X        fprintf (stderr,
	X            "dirlist: unable to open directory %s for read\n", dnam);
	X        return (1);
	X    }
	X    else
	X    {
	X	/* ------------------------------------------------------------ */
	X	/* read each directory entry                                    */
	X	/* if the entry is active                                       */
	X	/*  if the file is an include file (*.h)                        */
	X	/*   copy the name and directory index into the file list       */
	X	/* ------------------------------------------------------------ */
	X
	X        while (fread (&direct, sizeof direct, 1, dir) EQ 1)
	X        {
	X			if (direct.d_ino)
	X			{
	X				for (ptr = &direct.d_name[DIRSIZ-1]; !*ptr; ptr--);
	X
	X				if (*ptr EQ 'h' AND *(ptr-1) EQ '.')
	X				{
	X					strncpy (file[nfil].name, direct.d_name, DIRSIZ+1);
	X					file[nfil].dirind = ndir - 1;
	X					nfil++;
	X
	X	/* ------------------------------------------------------------ */
	X	/* if we're out of space in the list, allocate some more        */
	X	/* ------------------------------------------------------------ */
	X
	X					if (nfil GE MAXFILES)
	X					{
	X						MAXFILES += 50;
	X						file = (struct file *) ReAllocate (file,
	X									MAXFILES * sizeof (struct file));
	X					}
	X				}
	X			}
	X		}
	X        fclose (dir);
	X    }
	X
	X    return (0);
	X}
	X/*S dofile - process an input (C source) file */
	X/*H dofile ***********************************************************
	X*
	X*                                   dofile
	X*
	X*  examine each line of the input file.  If the first char is either
	X*  # or $ (UNIFY includes, for those of us who use it) and the next
	X*  word is include, look for the named file.  If the input file name
	X*  is `-', read from standard input and provide a default dependency
	X*  name.
	X*
	X*********************************************************************/
	X/*E*/
	Xdofile (fnam, suppress)
	Xchar    *fnam;					/* input file name					*/
	Xregister BOOL    suppress;		/* true if this is called for		*/
	X								/* recursive expansion and file name*/
	X								/* has already been printed			*/
	X{
	X    register FILE    *curfile;	/* current input file stream		*/
	X
	X    char    dep[80];			/* place for dependency object name	*/
	X	register char *c;			/* temp pointer						*/
	X	register char *cd;			/* temp pointer						*/
	X    static char *fn = "dofile";	/* function name for logging		*/
	X    char    lbuf[120];			/* input line buffer				*/
	X    register char    *suffix;	/* pointer to file name suffix		*/
	X    char    tname[80];			/* place to build full name			*/
	X
	X	register int count = 0;		/* number of things matched - sscanf*/
	X
	X    register struct  file *iname;	/* pointer to matching file		*/
	X
	X    struct  file *bsearch ();
	X
	X    register int     i;			/* general purpose stuff			*/
	X	register BOOL skip = FALSE;	/* true if skipping because of DEF	*/
	X
	X    int     strcmp ();
	X
	X    BOOL    first = TRUE;		/* true for initial condition		*/
	X
	X	/* ------------------------------------------------------------ */
	X	/* open the current file if it is not stdin                     */
	X	/* ------------------------------------------------------------ */
	X
	X	if (strcmp (fnam, "-") EQ 0)
	X	{
	X		curfile = stdin;
	X		fnam = "standardin.c";
	X	}
	X	else
	X	{
	X		curfile = fopen (fnam, "r");
	X	}
	X
	X    if (curfile EQ NULL)
	X    {
	X        fprintf (stderr, "<%s> _error_ cannot open %s\n", fn, fnam);
	X    }
	X    else
	X    {
	X	/* ------------------------------------------------------------ */
	X	/* look at each line in the file and process those beginning    */
	X	/*  with a legal include statement                              */
	X	/* ------------------------------------------------------------ */
	X
	X        while (fgets (lbuf, sizeof lbuf, curfile) EQ lbuf)
	X        {
	X			skip = ckdef (lbuf, skip);
	X			if (skip) continue;
	X			count = sscanf (lbuf, "%*[#$]%*[ \t]include%s", dep);
	X            if (count EQ 1)
	X            {
	X	/* ------------------------------------------------------------ */
	X	/* if this is the first time in, print out the file name        */
	X	/* ------------------------------------------------------------ */
	X
	X                if (first AND !suppress)
	X                {
	X                    suffix = &fnam[strlen(fnam)-1];
	X                    if (*suffix EQ 'c') *suffix = 'o';
	X                    printf ("%s: ", fnam);
	X                    first = FALSE;
	X                }
	X	/* ------------------------------------------------------------ */
	X	/* clean up the dependency name                                 */
	X	/* ------------------------------------------------------------ */
	X
	X				c = cd = dep;
	X				while ((*c = *(++cd)) NE '>' AND *c NE '"') c++;
	X				*c = NUL;
	X
	X	/* ------------------------------------------------------------ */
	X	/* if the include is sys/something.h, assume that it's from     */
	X	/*   /usr/include/sys, since this is the 99.9% case             */
	X	/* ------------------------------------------------------------ */
	X
	X				if (strncmp (dep, "sys/", 4) EQ 0)
	X				{
	X					printf ("\\\n\t\t/usr/include/%s ", dep);
	X				}
	X				else if (strchr (dep, '/'))
	X				{
	X					printf ("\\\n\t\t%s ", dep);
	X				}
	X				else
	X				{
	X	/* ------------------------------------------------------------ */
	X	/* look for the include file name in the list of known files    */
	X	/* ------------------------------------------------------------ */
	X
	X					iname = bsearch (dep, file, nfil,
	X								sizeof(struct file), strcmp);
	X					if (iname)
	X					{
	X	/* ------------------------------------------------------------ */
	X	/* since there might be more than one copy of the include file  */
	X	/*  back up to the first (bsearch will just find one)           */
	X	/* ------------------------------------------------------------ */
	X
	X						while (iname GT file)
	X						{
	X							if (strcmp (iname, iname - 1) EQ 0)
	X								iname--;
	X							else
	X								break;
	X						}
	X						printf ("\\\n\t\t%s/%s ",
	X							dirs[iname->dirind], dep);
	X	/* ------------------------------------------------------------ */
	X	/* if recursive search was requested and the file is not        */
	X	/*  in the exclusion list, then look for its includes           */
	X	/* ------------------------------------------------------------ */
	X
	X						if (recursion AND
	X							!bsearch (dep, noexp, nx,
	X									sizeof (char *), mstrcmp))
	X						{
	X							sprintf (tname,
	X								"%s/%s", dirs[iname->dirind], dep);
	X							dofile (tname, TRUE);
	X						}
	X					}
	X	/* ------------------------------------------------------------ */
	X	/* things that have paths in them, either relative or absolute, */
	X	/*   will be passed through as is.  since this is generally     */
	X	/*   contrary to standard coding practice, it should be ok for  */
	X	/*   the majority of the cases                                  */
	X	/* ------------------------------------------------------------ */
	X
	X					else
	X					{
	X						printf ("\\\n\t\t%s ", dep);
	X					}
	X				}
	X            }
	X        }
	X        if (!suppress) printf ("\n");
	X        fclose (curfile);
	X    }
	X}
	X/*S fcmp - compare two file list entries */
	X/*H fcmp *************************************************************
	X*
	X*                                   fcmp
	X*
	X*  a comparison function for qsort to call
	X*
	X*********************************************************************/
	X/*E*/
	Xfcmp (f1, f2)
	Xstruct file *f1;
	Xstruct file *f2;
	X{
	X	register int i;
	X
	X	if (i = strncmp (f1->name, f2->name, sizeof f1->name))
	X		return i;
	X	else
	X		return f1->dirind - f2->dirind;
	X}
	X/*S Allocate - call calloc and process return */
	X/*H Allocate *********************************************************
	X*
	X*                                   Allocate
	X*
	X*  veneer over calloc to handle bad returns
	X*
	X*********************************************************************/
	X/*E*/
	Xchar *
	XAllocate (nelem, size)
	Xregister int nelem;
	Xregister int size;
	X{
	X	extern char *calloc ();
	X
	X	register char *to;
	X
	X	if (!(to = calloc (nelem, size)))
	X	{
	X		fprintf (stderr,
	X			"%s: allocation failure - %d * %d\n",
	X			pgm, nelem, size);
	X		exit (99);
	X	}
	X
	X	return to;
	X}
	X/*S ReAllocate - call calloc and process return */
	X/*H ReAllocate *******************************************************
	X*
	X*                                   ReAllocate
	X*
	X*  veneer over realloc to handle bad returns
	X*
	X*********************************************************************/
	X/*E*/
	Xchar *
	XReAllocate (oldp, size)
	Xregister char *oldp;
	Xregister int size;
	X{
	X	extern char *realloc ();
	X
	X	register char *to;
	X
	X	if (!(to = realloc (oldp, size)))
	X	{
	X		fprintf (stderr,
	X			"%s: reallocation failure - %d\n",
	X			pgm, size);
	X		exit (99);
	X	}
	X
	X	return to;
	X}
	X/*S ckdef - check for #ifdef/ifndef/else/endif line */
	X/*H ckdef ************************************************************
	X*
	X*                                   ckdef
	X*
	X*  Look at the line and return the appropriate status depending on
	X*  whether or not a preprocessor symbol is defined or not.
	X*
	X*********************************************************************/
	X/*E*/
	Xckdef (buf, skip)
	Xregister char *buf;				/* line to check					*/
	Xregister BOOL skip;				/* current state of skip			*/
	X{
	X	char	sym[40];			/* defined symbol if found			*/
	X
	X	char	lbuf[120];			/* local buffer						*/
	X
	X	register int count = 0;		/* return from sscanf				*/
	X
	X	count = sscanf (buf, "%*[#$]%s", lbuf);
	X
	X	if (count EQ 1)
	X	{
	X		if (!skip AND !strcmp (lbuf, "ifdef"))
	X		{
	X			sscanf (buf, "%*[#$]%*s%s", sym);
	X			skip = !(BOOL)bsearch (sym, deftab, ndef,
	X					sizeof(char *), mstrcmp);
	X		}
	X		else if (!skip AND !strcmp (lbuf, "ifndef"))
	X		{
	X			sscanf (buf, "%*[#$]%*s%s", sym);
	X			skip = (BOOL)bsearch (sym, deftab,
	X					ndef, sizeof(char *), mstrcmp);
	X		}
	X		else if (!strcmp (lbuf, "else"))
	X		{
	X			skip = !skip;
	X		}
	X		else if (skip AND !strcmp (lbuf, "endif"))
	X		{
	X			skip = !skip;
	X		}
	X	}
	X
	X	return skip;
	X}
	X/*S mstrcmp - compare two strings given one direct and one indirect */
	X/*H mstrcmp **********************************************************
	X*
	X*                                   mstrcmp
	X*
	X*  for use with bsearch, this assumes that the arguments are a
	X*  string address and a pointer to a string address.  This is
	X*  used to allow the comparison of a string to a string pointed
	X*  to by an element of `noexp'.
	X*
	X*********************************************************************/
	X/*E*/
	Xmstrcmp (s1, s2)
	Xregister char *s1;
	Xregister char **s2;
	X{
	X	return strcmp (s1, *s2);
	X}
	X/*S pstrcmp - compare two strings given pointers to pointers */
	X/*H pstrcmp **********************************************************
	X*
	X*                                   pstrcmp
	X*
	X*  for use with qsort and bsearch, this assumes that the arguments
	X*  passed are pointers to the string addresses rather than the
	X*  addresses of the strings
	X*
	X*********************************************************************/
	X/*E*/
	Xpstrcmp (s1, s2)
	Xregister char **s1;
	Xregister char **s2;
	X{
	X	return strcmp (*s1, *s2);
	X}
SHAR_EOF
if test 19947 -ne "`wc -c < 'mdep.c'`"
then
	echo shar: error transmitting "'mdep.c'" '(should have been 19947 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0