[comp.sources.misc] v09i010: New version of CPR - C Pretty-printer

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

Posting-number: Volume 9, Issue 10
Submitted-by: dmt@pegasus.ATT.COM (Dave Tutelman)
Archive-name: cpr_dt

: This is a shar archive.  Extract with sh, not csh.
: The rest of this file will extract:
: readme cpr.c parsargs.c list.c fold.c report.c wildfile.c cpr.h makefile
echo extracting - readme
sed 's/^X//' > readme << '!EOR!'
X
X                README FILE FOR CPR
X                ^^^^^^^^^^^^^^^^^^^
X
XOK, we gotta have a README file, so you can tell what this does and
Xwhere it came from.  Well, I pulled it off the net myself early this
Xyear (1989), and found it sort of useful.  It's a pretty-printer for
XC programs.
X
XWHAT IT DOES:
X   -    Paginates, with meaningful page headers.
X   -    Makes a table of contents for files and functions.
X   -    Won't start a function at the bottom of a page.  (In fact,
X        has an option to print only one function per page.)
X
XWHAT IT DOESN'T DO:
X   -    Indent.
X   -    Put brackets on separate lines.
X   -    Other stuff that "C beautifiers" do.
X
XWhen I inherited a couple of pretty big C programs to maintain, the
Xfirst thing I did was to try to get a bunch of listings with CPR.  I
Xfound that CPR as I received it wasn't up to the job.  It certainly
Xwas after I added a few enhancements.  Here's the enhanced version,
Xcast back upon the waters of the net.  The enhancements are:
X
X   -    Any arguments can appear in a file rather than on the command
X        line, and in pretty free form.  (As received, you could only have
X        filename arguments in a file, one name per line.)
X   -    The table of contents can contain a single sorted index of
X        all functions across all files.
X   -    The option "-?" will give a help screen for the options
X        (more like the PC idiom than the usual UNIX utility).
X   -    Lines can be "intelligently" folded if they go beyond the
X        width of a page.  (You wouldn't believe this program I
X        inherited, and its 160-column lines.)
X
XThis remains public domain, which is as I found it.  (It's free, and
Xworth every penny  :-)
X
X                            Dave Tutelman
XPHYSICAL:       16 Tilton Drive         AT&T Bell Labs
X                Wayside, NJ 07712       Lincroft, NJ 07738
XAUDIBLE:        (201) 922-9576          (201) 576-2194
XLOGICAL:                   att!pegasus!dmt
X
XContributors to the code include:
X *	Written by:
X *		Paul Breslin
X *		Human Computing Resources Corp.
X *		10 St. Mary St.
X *		Toronto, Ontario
X *		Canada, M4Y 1P9
X *
X *		-- ...!decvax!utcsrgv!hcr!phb
X *
X *      Sorting and standard input reading from:
X *		Rick Wise, CALCULON Corp., Rockville, MD.
X *		-- ...!decvax!harpo!seismo!rlgvax!cvl!umcp-cs!cal-unix!wise
X *
X *	File modified time,
X *	numbered output,
X *	optional white space,
X *	improved function start tests from:
X *		David Wasley, U.C.Berkeley
X *		-- ...!ucbvax!topaz.dlw
X *
X *	Modified the -r to leave variable amounts of space
X *		Patrick Powell, U. Waterloo
X *
X *      Changed handling of form feeds to start a new page AND print heading:
X *		Terry Doner, U of Waterloo
X *
X *	Fixed up to locate more functions, and added -p option
X *		Dennis Vadura, U of Waterloo
X *
X *		It will find things like  struct foo *f()...
X *		but not things like 	int
X *					f
X *					()...
X *		ie. the constraint is that the () must appear on the same line
X *		as the function name.
X *
X *  Clean up a bit for 80286 machines (lints a bit cleaner, too)
X *      Dan Frank, Prairie Computing
X *
X *  Fixed a whole bunch of stuff and added lots of new flags.
X *      -S       sort and be case insensitive.
X *      -N       start numbering pages at 1 for each new file
X *      -T title cat the file title before the table of contents.
X *      -C       print only the table of contents
X *      -c       only try to look for function names in files whose suffix ends
X *	         in .c
X *      -f file  to handle file containing list of files to print. (for MSDOS)
X *      Dennis Vadura
X *
X *  Set to work better in MS-DOS (and Turbo C).
X *	Ported to Turbo C on MS-DOS.
X *	Enabled wildcard expansion for systems that don't support it.
X *	Broke BIG source file into several C files plus header.
X *	Fixed argument parsing to be more forgiving.
X *	Changed -f option to handle all args in a free-form file,
X *		not just filenames.
X *	Added options:
X *      -?	Help screen.
X *	-x,-X	Sort TOC across files, giving function index (xref-like?).
X *	-w (n)	Fold lines to a page width (fairly good-looking line folding).
X *	    Dave Tutelman  - att!pegasus!dmt -  10/89
X
X
!EOR!
echo extracting - cpr.c
sed 's/^X//' > cpr.c << '!EOR!'
X/*	CPR   -   Pretty-Printer for C programs
X *
X *	This program prints the files named in its argument list, preceding
X *	the output with a table of contents. Each file is assumed to be C
X *	source code (but doesn't have to be) in that the program searches
X *	for the beginning and end of functions. Function names are added to
X *	the table of contents, provided the name starts at the beginning of
X *	a line. The function name in the output is double striken.
X *
X *    PAGE SIZE
X *	The option "-l" indicates that the following argument is to be
X *	the page length used for output (changing the page length hasn't been
X *	tested much).
X *	The option "-w" indicates that the following argument is to be
X *	the page width (and lines are folded to that width, using a
X *	reasonably aesthetic folding algorithm).  The default, in the
X *	absence of "-w" is not to fold lines.
X *
X *    NUMBERING OF LINES & PAGES
X *	The option "-n" indicates that output lines should be numbered with
X *	the corresponding line number from the input file.
X *	The option "-N" indicates that page numbers start at 1 within each
X *	file.
X *
X *    FORMATTING THE PROGRAM
X *	The option "-p" indicates what proportion of the page in steps of 16
X *	should be used for deciding if a new function needs a new page.
X *	That is -p12 (the default) indicates that if a function starts
X *	within the top 12/16 (3/4) of the page then do it, otherwise put it
X *	on a new page.  Thus the higher the number (upto 16) the closer to
X *	the bottom of the page will functions be started. -p0 says put each
X *	func on a new page.
X *
X *	By default blank space is inserted after every closing '}'
X *	character. Thus functions and structure declarations are nicely
X *	isolated in the output. The only drawback to this is that structure
X *	initialization tables sometimes produce lots of white space.
X *	The "-r" option removes this space, or changes it to the indicated
X *	length.
X *
X *    TABLE OF CONTENTS OPTIONS
X *	The option "-s" indicates that the table of contents should be sorted
X *	by function name within each file.
X *	The option "-S" also calls for a sorted table of contents, but with
X *	a case-insensitive sort.
X *	The option "-x" indicates that the table of contents should include
X *	a sorted index of functions across all files.
X *	The option "-X" also calls for a sorted index of functions, but with
X *	a case-insensitive sort.
X *
X *	The option "-C" indicates that ONLY the table of contents is to
X *	be printed, not the source files themselves.
X *
X *	The option "-c" indicates that only files with the extension ".c"
X *	should be examined for files to list in the table of contents.
X *
X *	The option "-T" indicates that the following argument is a file
X *	name; the contents of that file is to be printed verbatim in the
X *	output before the table of contents, as a Title Paragraph.
X *
X *    MISCELLANEOUS OPTIONS
X *	The option "-?" indicates that a help screen for CPR be sent
X *	to stderr (generally the screen), but no processing done.
X *	The help screen is more verbose than the usage message that's
X *	printed on error, and summarizes all options of CPR.
X *
X *	The option "-f" indicates that the following argument is a file
X *	name; the contents of that file are to be treated just as command
X *	line arguments.  (Thus you can, for example,  make a ".cprrc" file
X *	with the right options and source files, in each of your
X *	source directories.)
X *
X *  HISTORY
X *
X *	Written by:
X *		Paul Breslin
X *		Human Computing Resources Corp.
X *		10 St. Mary St.
X *		Toronto, Ontario
X *		Canada, M4Y 1P9
X *
X *		-- ...!decvax!utcsrgv!hcr!phb
X *
X *      Sorting and standard input reading from:
X *		Rick Wise, CALCULON Corp., Rockville, MD.
X *		-- ...!decvax!harpo!seismo!rlgvax!cvl!umcp-cs!cal-unix!wise
X *
X *	File modified time,
X *	numbered output,
X *	optional white space,
X *	improved function start tests from:
X *		David Wasley, U.C.Berkeley
X *		-- ...!ucbvax!topaz.dlw
X *	Modified the -r to leave variable amounts of space
X *		Patrick Powell, U. Waterloo
X *
X *      Changed handling of form feeds to start a new page AND print heading:
X *		Terry Doner, U of Waterloo
X *
X *	Fixed up to locate more functions, and added -p option
X *		Dennis Vadura, U of Waterloo
X *
X *		It will find things like  struct foo *f()...
X *		but not things like 	int
X *					f
X *					()...
X *		ie. the constraint is that the () must appear on the same line
X *		as the function name.
X *
X *  Clean up a bit for 80286 machines (lints a bit cleaner, too)
X *      Dan Frank, Prairie Computing
X *
X *  Fixed a whole bunch of stuff and added lots of new flags.
X *      -S       sort and be case insensitive.
X *      -N       start numbering pages at 1 for each new file
X *      -T title cat the file title before the table of contents.
X *      -C       print only the table of contents
X *      -c       only try to look for function names in files whose suffix ends
X *	         in .c
X *      -f file  to handle file containing list of files to print. (for MSDOS)
X *      Dennis Vadura
X *
X *  Set to work better in MS-DOS (and Turbo C).
X *	Ported to Turbo C on MS-DOS.
X *	Enabled wildcard expansion for systems that don't support it.
X *	Broke BIG source file into several C files plus header.
X *	Fixed argument parsing to be more forgiving.
X *	Changed -f option to handle all args in a free-form file,
X *		not just filenames.
X *	Added options:
X *      -?	Help screen.
X *	-x,-X	Sort TOC across files, giving function index (xref-like?).
X *	-w (n)	Fold lines to a page width (fairly good-looking line folding).
X *	    Dave Tutelman  - att!pegasus!dmt -  10/89
X */
X
X#include <sys/types.h>
X#include <ctype.h>
X#include <stdio.h>
X#include <signal.h>
X#include <string.h>
X
Xchar *synopsis [] = {
X"OPTIONS:",
X"-c	Look for functions only if file is a '.c' file.",
X"-C	Produce ONLY table of contents, no listing.",
X"-n	Number lines in the listing.",
X"-N	Start each file listing on page 1.",
X"-s	Sort table of contents by function name (in each file).",
X"-S	Like -s, but case-insensitive.",
X"-x,-X	Like -s, -S, but sorts across files (Xref-like function index).",
X"-l n	Page length.  (Default = 66)",
X"-w n	Page width, at which to fold lines.  (Default = don't fold lines)",
X"-p n	How many 16ths of a page can be used, and still start a new function",
X"	on this page?  (-p0 puts a new function on each page.  Default = 12)",
X"-r n	How many blank lines to leave after a '}'.  (Default = 5)",
X"-t n	Width of a tab stop.  (Default = 8)",
X"-T title	Print contents of file 'title' before table of contents.",
X"-f argfile	Take next few arguments from file 'argfile'.",
X"-	File name for the Standard Input.",
X'\0'
X};
X
X#define MAIN
X#include "cpr.h"
X
X/* Some macros for parsing parameters from the argument list */
X#define NEXPARM		NexParm (&i,&parm, argc,argv)
X#define	NUMPARM		NumParm (&i,&parm, argc,argv)
X#define	STRPARM		StrParm (&i,&parm, argc,argv)
X
X#ifdef NOWILD
Xint NextName=0;		/* Use next_file function to expand wildcard */
Xchar *first_file(), *next_file();
X#endif
X
Xchar *GetProgName();
Xchar *StrParm();
X
Xmain(argc, argv)
Xchar **argv;
X{
X   int i;
X   char *ctime();
X   time_t thetime, time();
X   char *parm;		/* points to next thing to do in an arg */
X   int  num;
X   int	FirstFile=1;
X
X   ProgName = GetProgName (argv[0]);
X   thetime = time((time_t *)0);
X   strcpy(Today,ctime(&thetime));
X
X   if (argc < 2)  Synop();
X
X   i = 0;
X   while ((i = NEXPARM) >0)	/* get next argument if there is one */
X   {
X      if( arg[0] == '?'
X	 && arg[1] == '\0' ) Synop();
X
X      if( arg[0] != '-'	|| arg[1] == '\0' ) {		/* file name */
X		parm--;		/* back off to get whole name */
X		Name = STRPARM;
X		if (NULLSTR( Name ))  Usage();
X		if (FirstFile) {
X			FirstFile=0;
X			StartTempFile();
X		}
X		DoFile (Name);
X      }
X
X      else {			/* this arg is options */
X	    switch( *parm ) {
X	      case '-':
X		 break;		/* skip. just leading - for options */
X
X	      case '\0':	/* check for end of this argument */
X	      case ' ':		/* just for safety.		  */
X	      case '\t':
X	      case '\n':
X	      case '\r':
X		 break;
X
X	      case '?': Synop();
X
X	      case 'f':		/* get next args from a file */
X		 listn = STRPARM;	/* get next string parameter */
X		 if (NULLSTR( listn ))  Usage();
X		 if ((listf = fopen (listn, "r")) == NULL) {
X		    fprintf(stderr,"%s: list file '%s' not found\n",
X				ProgName, listn);
X		    exit (1);
X		 }
X		 InArgFile = 1;
X		 break;
X
X	      case 't':
X		 TabWidth = NUMPARM;
X		 if( TabWidth == -1) TabWidth = 0;
X		 if( TabWidth < 0 )  TabWidth = 0;
X		 break;
X
X	      case 'T':
X		 TitleFile = STRPARM;
X		 if (NULLSTR( TitleFile ))   Usage();
X		 if ((Tfile = fopen (TitleFile, "r")) == NULL) {
X		    fprintf(stderr,"%s: title file '%s' not found\n",
X				ProgName, TitleFile);
X		    exit (1);
X		 }
X		 ++Title;
X		 break;
X
X	      case 'l':
X		 PageLength = NUMPARM;
X		 if( PageLength == -1)  Usage();
X		 if( PageLength < 10) PageLength = 10;
X		 PageEnd = PageLength - ((PageLength > 30) ? 7 : 1);
X		 break;
X
X	      case 'w':
X		 PageWidth = NUMPARM;
X		 if( PageWidth == -1 ) Usage();
X		 if( PageWidth < 0 ) PageWidth = 0;
X		 break;
X
X	      case 'S':
X		 ++CaseInsensitive;
X	      case 's':
X		 ++SortFlag;
X		 break;
X
X	      case 'X':
X		 ++CaseInsensitive;
X	      case 'x':
X		 ++SortFlag;
X		 ++XrefFlag;
X		 if (ResetPage) {
X		    fprintf(stderr,"%s: options -X and -N are incompatible\n",
X			ProgName);
X		    exit (1);
X		 }
X		 break;
X
X	      case 'C':
X		 ++ContentsOnly;
X		 break;
X
X	      case 'c':
X		 ++OnlyCFiles;
X		 break;
X
X	      case 'n':
X		 ++NumberFlag;
X		 FirstCol = FORMATWIDTH;	/* leave room for line numbering */
X		 break;
X
X	      case 'N':
X		 ++ResetPage;
X		 if (XrefFlag) {
X		    fprintf(stderr,"%s: options -X and -N are incompatible\n",
X			ProgName);
X		    exit (1);
X		 }
X		 break;
X
X	      case 'r':
X		 Space_to_leave = NUMPARM;
X		 if (Space_to_leave == -1)  Space_to_leave = 0;
X		 if (Space_to_leave < 0)    Space_to_leave = 0;
X		 break;
X
X	      case 'p':
X		 PagePart = NUMPARM;
X		 if ( PagePart == -1)  Usage();
X		 if ( PagePart < 0)  PagePart = 0;
X		 if ( PagePart > 16) PagePart = 16;
X		 break;
X
X	      default:
X		 Usage();
X		 break;
X	    }  /* end 'switch' */
X      }	/* end 'else' */
X   }  /* end 'while' */
X
X   /* All files processed.  Print the listings. */
X   if( PageNumber > 1 || LineNumber > 0 )
X      putchar(BP);
X   EndTempFile();
X
X   DumpTableOfContents();
X   DumpTempFiles();
X   Done();
X}
X
XUsage()
X{
X   fprintf(stderr, "%s: Problem with argument %s", ProgName, arg);
X   if (InArgFile) fprintf(stderr, " in argument file\n");
X      else	  fprintf(stderr, "\n");	/* yeah, I know ... */
X   fprintf(stderr, "Usage: %s [-?cCnNsSxX] [-t tabwidth] [-l pagelength] ",ProgName);
X   fprintf(stderr, "[-w pagewidth]\n\t[-p[num]] [-r[num]] [-T title] [[-f] file] ...");
X   exit(1);
X}
X
XSynop()
X{
X   int i;
X
X	fprintf(stderr,"Synopsis:\n%s   [options]  [filenames]\n\n", ProgName);
X	for (i=0; *synopsis[i] != '\0'; i++)
X		fprintf (stderr,"%s\n",synopsis[i]);
X   exit(1);
X}
X
Xchar *
XGetProgName (s)		/* We need to strip off path information, if there */
Xchar *s;
X{
X   char *p;
X
X	for (p=s; *p!='\0'; p++);	/* get end of string */
X	while (--p >= s) {
X#ifdef MSDOS
X		if (*p == '.')
X			*p='\0';	/* strip off .EXE extension */
X#endif
X		if ((*p=='/') || (*p=='\\'))
X			break;
X	}
X	return (++p);
X}
X
X
X/*  Do the processing necessary to format one file  */
XDoFile (fname)
X  char *fname;
X{
X    if (*fname=='-' && *(fname+1)=='\0') {
X         File = stdin;
X         Name = "Standard Input";
X	 List();
X	 return;
X    }
X#ifndef NOWILD
X	 if( (File = fopen( fname, "r" )) == NULL )
X         {
X            fprintf(stderr,"%s: Can't open file '%s': %s\n",
X            ProgName, Name, sys_errlist[errno] );
X         }
X         List();
X	 fclose(File);
X
X#else		/* expand wildcards explicitly */
X	Name = first_file (fname);
X	while ((Name != NULL) && (*Name != '\0')) {
X		if( (File = fopen( Name, "r" )) == NULL )
X		{
X		    fprintf(stderr,"%s: Can't open file '%s': %s\n",
X		    ProgName, Name, sys_errlist[errno] );
X		    continue;
X		}
X		List();
X		fclose(File);
X
X		Name = next_file ();
X	}
X#endif
X}
X
X
Xint SaveOut;
Xchar *TempName;
Xchar *Temp2Name;
X
XStartTempFile()
X{
X   int Done();
X   extern char *mktemp();
X
X   CatchSignalsPlease(Done);
X
X   SaveOut = dup(1);
X#ifdef MSDOS
X   TempName = "cpr0001.tmp";
X#else
X   TempName = mktemp("/tmp/cprXXXXXX");
X#endif
X   if( freopen(TempName, "w", stdout) == NULL )
X   {
X      fprintf(stderr, "%s: Can't open temp file '%s': %s\n", ProgName,
X      TempName, sys_errlist[errno]);
X      exit(1);
X   }
X}
X
XEndTempFile()
X{
X#ifdef MSDOS
X   Temp2Name = "cpr0002.tmp";
X#else
X   Temp2Name = mktemp("/tmp/cprXXXXXX");
X#endif
X   if( freopen(Temp2Name, "w", stdout) == NULL )
X   {
X      fprintf(stderr, "%s: Can't open temp file '%s': %s\n", ProgName,
X      Temp2Name, sys_errlist[errno]);
X      exit(1);
X   }
X}
X
XDumpTempFiles()
X{
X   FILE *f;
X   char b[256];
X   register int pid, w;
X
X   fclose(stdout);
X
X#ifndef MSDOS
X   dup(SaveOut);
X   while( (pid = fork()) < 0 ) sleep(1);
X   if( pid )
X      while ((w = wait((int *)0)) != pid && w != -1);
X   else
X      {
X      CatchSignalsPlease(SIG_DFL);
X
X      if( ContentsOnly )
X         execl( "/bin/cat", "cat", Temp2Name, (char *)0 );
X      else
X         execl( "/bin/cat", "cat", Temp2Name, TempName, (char *)0 );
X      fprintf(stderr, "%s: exec of /bin/cat failed: %s\n", ProgName,
X      sys_errlist[errno]);
X      exit(0);
X   }
X#else
X   CatchSignalsPlease(SIG_DFL);
X   if( (f=fopen(Temp2Name,"r")) == NULL )
X      fprintf(stderr,"%s: Can't open file '%s': %s\n",
X      ProgName, TitleFile, sys_errlist[errno] );
X   else
X   {
X      while( fgets(b, 256, f) != NULL )
X         write(SaveOut,b,strlen(b));
X
X      fclose(f);
X   }
X
X   if( !ContentsOnly )
X      if( (f=fopen(TempName,"r")) == NULL )
X         fprintf(stderr,"%s: Can't open file '%s': %s\n",
X         ProgName, TitleFile, sys_errlist[errno] );
X      else
X      {
X         while( fgets(b, 256, f) != NULL )
X            write(SaveOut,b,strlen(b));
X
X         fclose(f);
X      }
X#endif
X}
X
XDone()
X{
X   CatchSignalsPlease(SIG_DFL);
X
X   fclose( stdout );
X   if( TempName ) unlink( TempName );
X   if( Temp2Name ) unlink( Temp2Name );
X
X   exit(0);
X}
X
XCatchSignalsPlease(action)
Xvoid (*action)();
X{
X#ifndef TURBOC
X   if( signal(SIGINT, SIG_IGN) != SIG_IGN ) signal(SIGINT, action);
X#else	/* TURBOC */
X   signal (SIGINT, action);
X#endif
X#ifndef MSDOS
X   if( signal(SIGQUIT, SIG_IGN) != SIG_IGN ) signal(SIGQUIT, action);
X   if( signal(SIGHUP, SIG_IGN) != SIG_IGN ) signal(SIGHUP, action);
X#endif
X}
X
!EOR!
echo extracting - parsargs.c
sed 's/^X//' > parsargs.c << '!EOR!'
X/*		PARSARGS
X *
X *	Functions to get parameters from:
X *	   -	The command line.
X *	   -	The argument file (if -f option is used).
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include "cpr.h"
X
X
X/* Get the next parameter, and point to it with *pp.
X * Return current index into argv[], or -1 if no more parameters.
X * Put NEW argument into arg[], but just bump *pp if there's still
X *	more to do in arg[].
X * Get NEW argument from argv[] or list file, depending on InArgFile.
X */
X
Xint
XNexParm (ip,pp, argc,argv)
X  int	*ip;		/* pointer to arg[] index */
X  char	**pp;		/* pointer to parm, which is (char *) */
X  int	argc;
X  char	*argv[];
X{
X	int	i = *ip;
X	char	*p = *pp;
X	int	c;
X	int	InArg = 0;	/* state variable */
X	int	GotArg = 0;
X
X	if (i==0) {	/* need to initialize */
X		strcpy (arg, argv[1]);
X		*pp = arg;
X		*ip = 1;
X		return (1);
X	}
X
X	p++;		/* bump the parameter pointer */
X
X	if (WHITESPACE( *p )) {		/* need a new arg */
X		arg[0] = '\0';	/* blank the beginning of the arg[] array */
X		if (InArgFile) {	/* get the new arg from listf */
X		    p = arg;
X		    while (!GotArg) {
X			c=getc (listf);
X			if (!InArg) {
X			    if (c == EOF) {	/* no more in listf */
X				InArgFile = 0;
X				GotArg++;
X			    }
X			    else if (!WHITESPACE( (char)c ))  InArg++;
X			}
X			if (InArg) {
X			    if (WHITESPACE( (char)c ) || c==EOF) {
X				*p = '\0';
X				GotArg++;
X			    }
X			    else if (!WHITESPACE( (char)c ))  *p++ = c;
X			}
X		    }  /* end while (!GotArg) */
X		}  /* end if (InArgFile)  */
X
X		if (arg[0]=='\0') {	/* get the new arg from command line */
X			if (++i >= argc) return (-1);
X			strcpy (arg, argv[i]);
X			*ip = i;
X			GotArg++;
X		}
X		*pp = arg;
X	}  /* end of "need new arg" */
X
X	else if (!GotArg)	/* not a new arg, just bump pointer */
X		*pp = p;
X
X	return ( i );
X}
X
Xint
XNumParm (ip, pp, argc,argv)	/* Returns next parameter as an integer if it
X				 * is a number.  Otherwise returns -1.	*/
X  int  *ip;	/* pointer to argument counter in main program */
X  char **pp;	/* pointer to "parm" pointer in main program */
X  int  argc;
X  char *argv[];
X{
X	int	num=0;		/* number accumulator */
X	int	i;
X	char	*p;
X
X	/* Bump to next parm, if there is one */
X	i = NexParm( ip, pp, argc, argv );
X	if (i <= 0)  return (-1);
X
X	p = *pp;	/* use updated parm pointer */
X
X	/* is there at least one digit? */
X	if (!isdigit( *p )) {
X		*pp = p-1;	/* back off to previous position */
X		return (-1);
X	}
X
X        /* accumulate a decimal number */
X	while (isdigit( *p ))
X		num = 10*num + (int)(*p++ - '0');
X
X	/* fix up pointers before returning */
X	*pp = p-1;	/* back off to end of number */
X	return (num);
X}
X
X
Xchar *
XStrParm (ip, pp, argc,argv)	/* Returns next string parameter if there
X				 * is one.  Otherwise returns -1.	*/
X  int  *ip;	/* pointer to argument counter in main program */
X  char **pp;	/* pointer to "parm" pointer in main program */
X  int  argc;
X  char *argv[];
X{
X	int	i;
X	char	*p, *s;
X
X	/* Bump to next parm, if there is one */
X	i = NexParm( ip, pp, argc, argv );
X	if (i <= 0)  return (NULL);
X
X	s = p = *pp;	/* use updated parm pointer */
X	if (WHITESPACE( *p ))  return (NULL);
X
X	/* Find end of string and null it out */
X	while (! WHITESPACE( *p ))  p++;
X	*p = '\0';	/* now null-terminate the string */
X
X	/* fix up pointers before returning */
X	*pp = p-1;	/* back off to end of string */
X	return (s);
X}
X
!EOR!
echo extracting - list.c
sed 's/^X//' > list.c << '!EOR!'
X/*			LIST.C
X *
X *	Functions that go through the .C files,
X *	parse them, and make entries in Table of Contents.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include "cpr.h"
X
Xint SawFunction;
Xint Braces;
X
X
XList()
X{
X   register int bp;
X   register char *bufp;
X   char buffer[256];
X
X   NewFile();
X   bp = Braces = 0;
X   InString = InComment = 0; /* reset for new file -DV */
X   SawFunction = 0;
X   bufp = buffer;
X   while( fgets(bufp, sizeof(buffer), File) != NULL )
X   {
X      ++FileLineNumber;
X      if( bp ) NewFunction();
X
X      if( ++LineNumber >= PageEnd ) NewPage();
X
X      if( bufp[0] == '\f'
X         && bufp[1] == '\n'
X         && bufp[2] == '\0' )
X      {
X         NewPage(); /* was strcpy(bufp, "^L\n");*/
X         continue;
X      }
X
X      if( NumberFlag )
X      {
X         if( *bufp == '\n' )
X	    printf(BLANKFORMAT);
X         else
X	    printf(NUMFORMAT, FileLineNumber);
X      }
X      if( (Braces == 0) && LooksLikeFunction(bufp) )
X         AddToTableOfContents(NEWFUNCTION);
X
X      bp = ScanLine(buffer);
X   }
X}
X
XScanLine(l)
Xregister char *l;
X{
X   extern char *EndComment();
X   extern char *EndString();
X   register char c;
X   int bp;
X   char *save;
X
X   /* initialize line-checking variables */
X   bp = 0;
X
X   /* Now scan the line */
X   for( save = l; c = *l; ++l )
X      if( InComment )
X         l = EndComment(l);
X      else if( InString )
X         l = EndString(l);
X      else
X         switch(c)
X         {
X         case '{':
X            ++Braces;
X            break;
X
X         case '}':
X            if( --Braces == 0 )
X               bp = 1;
X            break;
X
X         case '\'':
X	    for( ++l; *l && *l != '\''; ++l )
X	       if( *l == '\\' && *(l+1) )  ++l;
X            break;
X
X         case '"':
X            InString = 1;
X            break;
X
X         case '/':
X            if( *(l+1) == '*' )
X            {
X               InComment = 1;
X		++l;
X            }
X            break;
X	 }
X   if (PageWidth)  FoldLine( save );
X   OutputLine( save );
X   return(bp);
X}
X
Xchar *
XEndComment(p)
Xregister char *p;
X{
X   register char c;
X
X   /*
X       	 * Always return pointer to last non-null char looked at.
X       	 */
X   while( c = *p++ ) {
X      if( c == '*' && *p == '/' )
X      {
X         InComment = 0;
X         return(p);
X      }
X   }
X   return(p-2);
X}
X
Xchar *
XEndString(p)
Xregister char *p;
X{
X   register char c;
X
X   /*
X       	 * Always return pointer to last non-null char looked at.
X       	 */
X   while( c = *p++ ) {
X      if( c == '\\' && *p )
X      {
X         ++p;
X         continue;
X      }
X      else if( c == '"' )
X      {
X         InString = 0;
X         return(p-1);
X      }
X   }
X   return(p-2);
X}
X
XNewFunction()
X{
X   register int i;
X
X   if( Space_to_leave <= 0 || !SawFunction ) return;
X   if( LineNumber + Space_to_leave > (PageLength * PagePart /16) )
X      NewPage();
X   else
X      {
X      for( i=0; i < (Space_to_leave); ++i ) putchar('\n');
X      LineNumber += Space_to_leave;
X   }
X
X   SawFunction = 0;
X}
X
X#define isidchr(c)	(isalnum(c) || (c == '_'))
X
X/* This used to incorrectly identify a declaration such as
X *     int (*name[])() = { initializers ... }
X * as a function.  It also picked up this in an assembler file:
X *     #define MACRO(x) stuff
X *     MACRO(x):
X * Fixed both of these.   -IAN!
X */
XLooksLikeFunction(s)
Xregister char *s;
X{
X   register char *p;
X   register int i;
X   char *save;
X   int t = TabWidth;
X
X   if( InComment || InString ) return(0);
X   if( OnlyCFiles )
X   {
X      char *e = Name+strlen(Name)-1;
X      if(( *e != 'c'
X#ifdef MSDOS
X		&& *e != 'C'
X#endif
X	      ) || e[-1] != '.' ) return(0);
X   }
X
X   if( !t ) t = 8;
X   save = s;
X
X   i = 0;
X   do
X      {
X      p = FunctionName;
X
X      while( *s && (*s == ' ') || (*s == '\t') ) ++s;
X      if( *s == '*' ) ++s;
X      if( *s && (*s == ' ') || (*s == '\t') ) continue;
X      if( !*s || ((*s != '_') && !isalpha(*s)) ) return(0);
X
X      while( isidchr(*s) )
X         *p++ = *s++;
X      *p = '\0';
X
X      while( *s && (*s == ' ') || (*s == '\t') ) ++s;
X      i++;
X   }
X   while ( *s && *s != '(' && i < 4 );
X
X   if( *s != '(' || *(s+1) == '*' ) return(0);
X
X   for (i = 0; *s; s++)
X   {
X      switch( *s )
X      {
X      case '(':
X         ++i;
X         continue;
X
X      case ')':
X         --i;
X         break;
X
X      default:
X         break;
X      }
X      if( i == 0 ) break;
X   }
X   if( !*s ) return(0);
X
X   while( *s )
X   {
X      if( *s == '{') break;
X      if( *s == ';' || *s == ':' ) return(0);
X      ++s;
X   }
X
X   /*
X       	 * This will cause the function name part of the line to
X       	 * be double striken.  Note that this assumes the name and the opening
X       	 * parentheses are on the same line...
X       	 */
X
X   if( p = strchr( save, '(' ) )
X   {
X      p--;
X      while( p != save && isidchr( *(p-1) ) ) p--;
X      for( i=0; save != p; save++ )
X         if( *save == '\t' )
X         {
X            putchar('\t');
X            i = ((i+t)/t)*t;
X         }
X         else
X         {
X            putchar(' ');
X            i++;
X         }
X
X      for( ; *p != '('; p++ )
X         if( *p == '\t' )
X         {
X            putchar('\t');
X            i = ((i+t)/t)*t;
X         }
X         else
X         {
X            putchar(*p);
X            i++;
X         }
X   }
X   else
X      for( i=0; *save && (*save == '*' || isidchr(*save)); ++save)
X         if( *save == '*' )
X         {
X            putchar(' ');
X            i++;
X         }
X         else
X         {
X            if( *save == '\t' )
X               i = ((i+t)/t)*t;
X            else
X               i++;
X            putchar(*save);
X         }
X
X   while( i --> 0 ) putchar('\b');
X
X   SawFunction = 1;
X   return(1);
X}
!EOR!
echo extracting - fold.c
sed 's/^X//' > fold.c << '!EOR!'
X/*			FOLD
X *
X *	Functions to fold an output line.
X */
X
X#include <stdio.h>
X#include <string.h>
X#include "cpr.h"
X
X/* The criteria for folding a line are, in order of aethetic desirability: */
X#define	COMMENT		0	/* Comment starts here */
X#define	BRACKET		1	/* Curly open bracket */
X#define	SEMICOLON	2	/* First non-blank after semicolon */
X#define	BLANK		3	/* First non-blank after whitespace */
X#define	PAREN		4	/* Open parenthesis */
X#define	N_CRIT		5	/* Number of criteria for folding a line */
X#define	CLEAR_CRIT	{ int i; for(i=0;i<N_CRIT;i++) crit[i]=NULL; }
X
Xint NeedFold = 0;	/* Number of folds needed for this line */
Xint FoldCol = -1;	/* Proposed left edge of folded line */
Xchar *folds [64];	/* Places to fold the current line */
X
Xchar *FoldHeuristic ();
X
X
XFoldLine (s)	/* Put Fold Marks in the right place in the line */
X  char *s;
X{
X	char *p;
X	int i;
X	int col = 0;		/* Current column in output line */
X	char *NonBlank = NULL;	/* First non-blank character */
X	int CantFold = 0;	/* Set it if we have trouble folding */
X
X	/* Set up array of pointers into the line of possible places to fold,
X	 * in order of aesthetic desirability. */
X	char *crit [N_CRIT];
X	char *SemiWait = NULL, *BlankWait = NULL;
X
X	CLEAR_CRIT;
X	FoldCol = -1;
X	NeedFold = 0;	/* assume we won't need to fold line */
X
X	if (! PageWidth) return;	/* Don't bother folding lines */
X
X	/* Step through line, looking for good places to fold */
X	for (p=s; *p; p++) {
X		switch (*p) {
X		  case '\n':	/* ignore */
X			break;
X
X		  case ' ':	/* Whitespace is harmless */
X			col++;
X			BlankWait = p;	/* remember we've seen a blank */
X			break;
X
X		  case '\t':	/* Space out a tab's worth */
X			while ((++col) % TabWidth);
X			col++;
X			BlankWait = p;	/* remember we've seen a blank */
X			break;
X
X		  case '/':
X			if (*(p+1) == '*')	/* beginning of a comment */
X				crit [COMMENT] = p;
X			col++;
X			break;
X
X		  case '{':
X			if (*(p-1) != '\'')
X				crit [BRACKET] = p;
X			col++;
X			break;
X
X		  case ';':	/* Remember we've seen a semicolon */
X			col++;
X			if (*(p-1) != '\'')
X				SemiWait = p;
X			break;
X
X		  case '(':
X			if (*(p-1) != '\'')
X				crit [PAREN] = p;
X			col++;
X			break;
X
X		  default:
X			col++;
X			break;
X		}
X
X		/* If non-blank, do a few housekeeping things */
X		if (*p!=' ' && *p!='\t' && *p!='\n') {
X			if (FoldCol == -1) {
X				NonBlank = p;
X				FoldCol = col + 1;
X			}
X			if (BlankWait) {	/* waiting after blank */
X				crit [BLANK] = p;
X				BlankWait = 0;
X			}
X			if (SemiWait && SemiWait!=p) {
X				crit [SEMICOLON] = p;
X				if (*p!=';')	SemiWait = 0;
X			}
X		}
X
X		/* Do we need to fold yet ? */
X		if (col+FirstCol >= PageWidth  &&  *p!=' '  &&  *p!='\t') {
X			/* Can we fold?  We can tell by checking our pointers
X			 * in order of decreasing aesthetic result of fold.
X			 */
X			char *FoldHere;
X
X			FoldHere = FoldHeuristic (s, NonBlank, crit);
X			if (FoldHere)
X				folds [NeedFold++] = FoldHere;
X			else
X				CantFold++;
X
X			/* Do some cleaning up after folding */
X			if (FoldHere) {
X				col = FoldCol;
X				p = FoldHere;
X
X				CLEAR_CRIT;
X				BlankWait = SemiWait = NULL;
X			}
X		}
X	}
X	if (CantFold)	/* complain, but print anyway and continue */
X		fprintf(stderr,"%s: trouble folding line %ld of file %s\n",
X			ProgName, FileLineNumber, Name);
X}
X
X/*	Output the line, folding where indicated in folds[] */
X
XOutputLine (p)
X  char *p;
X{
X	int i = 0;
X
X	if (! NeedFold)		/* don't bother folding lines */
X		printf ("%s",p);
X
X	else {			/* gotta fold lines */
X	    for (; *p; p++) {
X		if (p==folds[i] && i<NeedFold) {    /* fold to a new line */
X			putchar ('\n');
X			if (++LineNumber >= PageEnd)  NewPage();
X			if (NumberFlag)
X				printf (BLANKFORMAT);
X			GoToColumn (FirstCol, FoldCol+FirstCol);
X			i++;
X		}
X		putchar (*p);
X	    }
X	}
X}
X
X/*  Heuristic for determining where to fold  */
X
X#define	MAX( x, y )	((x) > (y)) ? x : y
X#define	MIN( x, y )	((x) < (y)) ? x : y
X#define	MAXC( c, j )	for(i=j=0;i<N_CRIT;i++) if(c[i]>c[j]) j=i
X
Xchar *
XFoldHeuristic (s, NonBlank, crit)
X  char *s;		/* pointer to line */
X  char *NonBlank;	/* pointer to first non-blank character */
X  char *crit[];		/* pointers to likely places to fold, based on
X			 * aesthetic criteria */
X{
X	int	i,j;
X	int	score [N_CRIT];		/* keep some "scores" here */
X	int	credit;	/* score value increments (in columns) */
X	char	*lptr;		/* points to start of partial line */
X	char	*p;
X
X	/* For each crit[] pointer, it's worthless as a folding point if it's
X	 * the first non-blank in the line. */
X	for (i=0; i<N_CRIT; i++)
X		if (crit[i]==NonBlank)  crit[i] = NULL;
X
X	/* Fold on a comment, if we've got one */
X	if (crit [COMMENT])  return (crit [COMMENT]);
X
X	/* For the rest, we'll compute some heuristic "scores".
X	 * Start by seeing how much of the partial line each crit picks up. */
X	score [COMMENT] = 0;
X	if (NeedFold)		/* line already folded */
X		lptr = folds [NeedFold-1];
X	else
X		lptr =  NonBlank;
X	for (i=1; i<N_CRIT; i++)
X		if (crit [i])
X			score [i] = crit [i] - lptr;
X		else	score [i] = 0;
X
X	/* Adjust the scores according to some "feel for aesthetics".
X	 * Start by giving each criterion credit for its order in the array;
X	 * "credit" is measured by the number of columns it's worth.
X	 * We'll estimate a unit of "credit" as a fraction of the line
X	 * that we're trying to fill.
X	 */
X
X	credit = PageWidth - (lptr - s);	/* width of current partial */
X	credit = credit / 10;		/* "arbitrary" fraction of line */
X	for (i=1; i<N_CRIT; i++)
X		if (score [i])
X			score [i] += (N_CRIT - i - 1) * credit;
X
X	/* Next, see how "valuable" a paren is from its context. */
X	if (p = crit [PAREN]) {
X		char *pp;
X		pp = p-1;
X		if (*pp==' ' || *pp=='\t')
X			score[PAREN] += 2 * credit;
X		else if (*pp=='(') {
X		    /* Find the left edge of string of parens */
X		    while (--pp) {
X			if (pp < lptr) {
X				/* Parens all the way left. Quit */
X				score[PAREN] -= credit;
X				break;
X			}
X			else if (*pp==' ' || *pp=='\t') {
X				/* Isolated! Point to it & give bonus */
X				crit [PAREN] = pp+1;
X				score[PAREN] = (pp - lptr) + 1 + 2*credit;
X				break;
X			}
X			else if (*pp!='(') {
X				/* Nothing special. Point & give small bonus */
X				crit [PAREN] = pp+1;
X				score[PAREN] = (pp - lptr) + credit;
X				break;
X			}
X			/* If we got here, keep searching */
X		    }
X		}
X		else	/* Nothing special.  Small bonus */
X			score [PAREN] += credit - 1;
X	}
X
X	/* Now, just return the highest score. */
X	MAXC( score, j );
X	return ( crit[j] );
X}
X
!EOR!
echo extracting - report.c
sed 's/^X//' > report.c << '!EOR!'
X/*			REPORT.C
X *
X *	Prints out the table of contents and listed .C files.
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X
X#include "cpr.h"
X
X#define HEADER_SIZE	3
X#define TOC_SIZE	4096
X
Xstatic char *Toc[TOC_SIZE];	/* array of pointers to malloc-ed TOC strings */
Xstatic int TocPages[TOC_SIZE];	/* page on which the item occurs */
Xstatic int TocCount;		/* how many TOC lines so far */
X
Xchar FileDate[24]; /* Last modified time of file	*/
X
X
XNewPage()
X	/* Note that PageNumber is -1 during TableOfCont processing */
X{
X   static int CountNewPage=0;	/* suppress blank pre-page */
X
X   if( PageNumber >= 0 ) {
X	++PageNumber;
X	putchar(BP);
X   }
X   else			/* we're doing TOC */
X	if( CountNewPage++ ) putchar(BP);	/* don't put first BP */
X   LineNumber = 0;
X
X   PutHeader();
X}
X
XPutHeader()
X{
X   register int i, l, j;
X
X   putchar('\n');
X   ++LineNumber;
X   l = strlen(Name);
X   for( j=0; j < l; ++j )
X      printf("%c\b%c\b%c", Name[j], Name[j], Name[j]);
X
X   if( PageNumber > 0 )
X   {
X      printf("  %.17s", FileDate);
X      GoToColumn(l+19, 70);
X      printf("Page:%4d\n\n", PageNumber);
X      ++LineNumber;
X      ++LineNumber;
X   }
X   else
X      {
X      GoToColumn(l, 55);
X      printf("%s\n\n", Today);
X      ++LineNumber;
X      ++LineNumber;
X   }
X}
X
XGoToColumn(from, to)
Xregister int from, to;
X{
X   if( from < to)
X   {
X      if( TabWidth > 0 ){
X         from &= ~(TabWidth-1);
X         for( ; (from + TabWidth) <= to; from += TabWidth )
X            putchar('\t');
X      }
X      for( ; from < to; from++ )
X         putchar(' ');
X   }
X}
X
X
XAddToTableOfContents(type)
X{
X   if( TocCount > TOC_SIZE )
X      return;
X   if( TocCount == TOC_SIZE )
X   {
X      fprintf(stderr, "%s: More than %d Table of contents entries; others ignored.\n",
X      ProgName, TOC_SIZE);
X      ++TocCount;
X      return;
X   }
X
X   if( type == NEWFILE )
X      AddFile();
X   else
X      AddFunction();
X}
X
XAddFunction()
X{
X   register int l;
X   register char *p;
X
X   /* This heuristic stops multiple occurrences of a function,
X       	 * selected by #ifdefs, to all end up many times over in the
X       	 * Table of Contents.  One only needs to see it once.  -IAN!
X       	 */
X   if( TocCount > 0 && TocPages[TocCount-1] == PageNumber
X      && strcmp(Toc[TocCount-1],FunctionName) == 0 )
X      return;
X   l = strlen(FunctionName);
X   p = Toc[TocCount] = (char *)malloc(l+1);
X   strcpy(p, FunctionName);
X   TocPages[TocCount] = PageNumber;
X   ++TocCount;
X}
X
XAddFile()
X{
X   register int i, l;
X   register int len;
X   char temp[20];
X
X   len = strlen(Name) + 20;
X   len = (len < 130) ? 130 : len;
X   Toc[TocCount] = (char *)malloc(len);
X   sprintf(Toc[TocCount], "\n    File: %s ", Name);
X   l = strlen(Toc[TocCount]);
X   if( l < 64 )
X   {
X      if( TabWidth > 0 ){
X         i = ((64 - l) /TabWidth) + 1;
X         while( i-- > 0 )
X            Toc[TocCount][l++] = '\t';
X      }
X      else{
X         while( l < 64 )
X            Toc[TocCount][l++] = ' ';
X      }
X      Toc[TocCount][l++] = '\0';
X   }
X   sprintf(temp, "  Page %4d\n", PageNumber);
X   strcat(Toc[TocCount], temp);
X   ++TocCount;
X}
X
XNewFile()
X{
X   GetFileTime();
X   if( ResetPage ) PageNumber=0;
X   NewPage();
X   AddToTableOfContents(NEWFILE);
X   FileLineNumber = 0;
X}
X
XGetFileTime()
X{
X   struct stat st;
X   extern char *ctime();
X
X   if( File == stdin )
X      strncpy(FileDate, &Today[4], 20);
X   else
X      {
X      fstat(fileno(File), &st);
X      strncpy(FileDate, ctime((time_t *)&st.st_mtime) + 4, 20);
X   }
X   strncpy(&FileDate[12], &FileDate[15], 5);
X   FileDate[18] = '\0';
X}
X
XDumpTableOfContents()
X{
X   register int i, j;
X   int TocIncr = 0;
X   int index[TOC_SIZE];
X   int Files = 0;	/* How many files reported so far */
X   int Functions = 0;	/* How many functions reported so far? */
X   int EveryFourth;
X
X   if( TocCount == 0 ) return;
X
X   for (i = 0; i < TocCount; i++) index[i] = i;
X
X   if( XrefFlag ) {	/* XREF - put files as first entries.
X			 *   SortTable() will do the rest.	*/
X      FilesFirst ();
X      TocIncr = 1;	/* start printing AFTER the \n */
X   }
X
X   if( SortFlag )
X      SortTable(index);
X
X   Name = "Table of  Contents";
X
X   PageNumber = -1;
X   LineNumber = 0;
X
X   if( Title )
X   {
X      FILE *f;
X      int n;
X      char b[256];
X
X      if( (f=fopen(TitleFile,"r")) == NULL )
X         fprintf(stderr,"%s: Can't open file '%s': %s\n",
X         ProgName, TitleFile, sys_errlist[errno] );
X      else
X      {
X         while( fgets(b, 256, f) != NULL )
X         {
X            if( strlen(b) ) b[strlen(b)-1]=0;
X            puts(b);
X            LineNumber++;
X            if( ++LineNumber >= PageEnd ) NewPage();
X         }
X
X         fclose(f);
X      }
X   }
X   else
X      NewPage();
X
X   for( i=0; i < TocCount; ++i )
X   {
X      if( Toc[index[i]][0] == '\n' )		/* File entry */
X      {
X         if( (LineNumber + 5) >= PageEnd ) NewPage();
X
X	 /* Play with the leading \n in file entry */
X	 EveryFourth = ( !(Files++ & 3) && XrefFlag );
X	 printf("%s", Toc[index[i]]+TocIncr-EveryFourth);
X	 LineNumber += 2 - TocIncr + EveryFourth;
X         continue;
X      }
X      else				/* Function entry */
X      {
X	 if (! Functions++ && XrefFlag) {
X		printf( "\nFunction Index:\n");
X		LineNumber += 2;
X	 }
X      }
X      if( ++LineNumber >= PageEnd ) NewPage();
X
X      printf("        %s ", Toc[index[i]]);
X      for( j=strlen(Toc[index[i]]); j < 48; ++j ) putchar('.');
X      printf(" %4d\n", TocPages[index[i]]);
X   }
X
X   if( ContentsOnly ) NewPage();
X}
X
XFilesFirst ()
X{
X	int	i;
X	int	FirstNonFile = 0;
X	char	*Ctemp;
X	int	Itemp;
X
X	for (i=0; i<TocCount; i++)
X		if (Toc [i][0] == '\n') {	/* swap file entry down */
X			Ctemp = Toc [i];
X			Toc [i] = Toc [FirstNonFile];
X			Toc [FirstNonFile] = Ctemp;
X
X			Itemp = TocPages [i];
X			TocPages [i] = TocPages [FirstNonFile];
X			TocPages [FirstNonFile] = Itemp;
X
X			FirstNonFile++;
X		}
X}
X
XSortTable(index)
Xregister int *index;
X{
X   register int i, temp, flag;
X   char name1[256];
X   char name2[256];
X
X   do {
X      flag = 0;
X      for (i = 0; i < TocCount - 1; i++)
X      {
X         if( Toc[index[i]][0] == '\n' || Toc[index[i+1]][0] == '\n' )
X            continue; /* don't sort across file names */
X         strcpy( name1, Toc[index[i]] );
X         strcpy( name2, Toc[index[i+1]] );
X
X         if( CaseInsensitive )
X         {
X            char *p;
X            char c;
X            for(p=name1; c=*p; p++ )
X               if( islower(c) ) *p=toupper(c);
X            for(p=name2; c=*p; p++ )
X               if( islower(c) ) *p=toupper(c);
X         }
X
X         if( strcmp(name1, name2) > 0)
X         {
X            temp = index[i];
X            index[i] = index[i+1];
X            index[i+1] = temp;
X            flag = 1;
X         }
X      }
X   }
X   while( flag );
X}
X
!EOR!
echo extracting - wildfile.c
sed 's/^X//' > wildfile.c << '!EOR!'
X/*	Expand wildcards (e.g., for MSDOS, which doesn't do it for you).
X *	Note that the MSDOS wildcard conventions are used, not the
X *	UNIX conventions.
X *
X *	The following code is a prototype of the use of these functions,
X *	if 'fname' points to the [wildcarded] name of the file:
X *
X *	#ifdef NOWILD
X *		strncpy (fname, first_file (fname), MAXNAME);
X *		while ((fname!=NULL) && (*fname!='\0')) {
X *			process_file (fname);
X *			strncpy (fname, next_file (fname), MAXNAME);
X *		}
X *	#else
X *		process_file (fname);
X *	#endif
X *
X *      This file is an example of these functions for Turbo C.
X *	(It isn't needed for Turbo C 2.0, but may be for earlier ones.)
X */
X
X#include <stdio.h>
X
X#ifdef NOWILD
X#ifdef TURBOC
X
X#include <dos.h>
X#include <dir.h>
X
Xstruct ffblk fb;
Xchar	fullname[MAXPATH];
Xint	dirlen;
X
X/* Find the first file meeting the wildcard spec, and return its name */
Xchar *
Xfirst_file (fn)
X  char	*fn;		/* filename (perhaps complete pathname */
X{
X	int	ffflag;
X	int	splitflag;
X	char	drive[MAXDRIVE], dir[MAXDIR],
X		name[MAXFILE], ext[MAXEXT];
X
X	/* Get path part, if any */
X	splitflag = fnsplit (fn, drive, dir, name, ext);
X	strcpy (fullname, drive);
X	strcat (fullname, dir);
X	dirlen = strlen (fullname);
X
X	ffflag = findfirst (fn, &fb, FA_RDONLY+FA_ARCH);
X	if (ffflag) {		/* No files match */
X		if (splitflag & WILDCARDS)	/* done if wildcard */
X			return (NULL);
X		else				/* complain if not wild */
X			return (fn);
X	}
X	else {
X		if (dirlen) {
X			strcpy (fullname+dirlen, fb.ff_name);
X			return (fullname);
X		}
X		else
X			return (fb.ff_name);
X	}
X}
X
X/* Find the next file meeting the wildcard spec, and return its name */
Xchar *
Xnext_file ()
X{
X	int	ffflag;
X
X	ffflag = findnext (&fb);
X	if (ffflag)		/* No more matching files */
X		return (NULL);
X	else {
X		if (dirlen) {
X			strcpy (fullname+dirlen, fb.ff_name);
X			return (fullname);
X		}
X		else
X			return (fb.ff_name);
X	}
X}
X
X#endif
X#endif
!EOR!
echo extracting - cpr.h
sed 's/^X//' > cpr.h << '!EOR!'
X/**************  Header File For CPR  ************************/
X
X#ifdef MAIN
X#  define EXTERN
X#  define INIT(x)	=x
X#else
X#  define EXTERN	extern
X#  define INIT(x)
X#endif
X
Xextern int errno; /* system error number */
Xextern char *sys_errlist[]; /* error message */
Xextern char *malloc() ; /* important for 8086-like systems */
X
X#define BP		0xC		/* Form feed			*/
X
X#define	NEWFILE		1
X#define NEWFUNCTION	2
X
X/* Define formats for beginning of line */
X#define	NUMFORMAT	"%6ld  "
X#define	BLANKFORMAT	"        "
X#define	FORMATWIDTH	8
X
X#define	NULLSTR( x )	((x == NULL) || (*x == '\0'))
X#define	WHITESPACE(x)	(strchr (" \n\r\t", x))
X
X/* Option flag variables */
XEXTERN	int PageLength INIT( 66 );	/* -l, <len> Page length */
XEXTERN	int PageWidth INIT( 0 );	/* -w, page width for line folding */
XEXTERN	int PagePart INIT( 12 );	/* -p, Decision on paging for new fn*/
XEXTERN	int PageEnd INIT( 59 );		/* Accounts for space at bottom (7 lines) */
XEXTERN	int Title INIT( 0 );		/* -T, print a title file */
XEXTERN	int ResetPage INIT( 0 );	/* -N, each file resets page # */
XEXTERN	int ContentsOnly INIT( 0 );	/* -C, only ToC, no listings */
XEXTERN	int SortFlag INIT( 0 );		/* -s, sort table of contents	*/
XEXTERN	int CaseInsensitive INIT( 0 );	/* -S, case-insens sort */
XEXTERN	int XrefFlag INIT( 0 );		/* -x, cross-reference */
XEXTERN	int NumberFlag INIT( 0 );	/* -n, line numbers in output */
XEXTERN	int FirstCol INIT( 0 );		/* starting column for listing (-n) */
XEXTERN	int Space_to_leave INIT( 5 );	/* -r<number> space to leave */
XEXTERN	int TabWidth INIT( 8 );		/* -t <number> width of tabs */
XEXTERN	int OnlyCFiles INIT( 0 );	/* -c, only look in C files */
X
X/* State variables for the program */
XEXTERN	long FileLineNumber;	/* Input file line number	*/
XEXTERN	int LineNumber;		/* Output line	on this page */
XEXTERN	int PageNumber INIT( 0 ); /* You figure this one out	*/
XEXTERN	int InComment;
XEXTERN	int InString;
X
XEXTERN	char *TitleFile;
XEXTERN	char *ProgName;
XEXTERN	char Today[30];
XEXTERN	char *Name;	 /* Current file name */
XEXTERN	char FunctionName[80];
X
X/* Help with parsing the command line and argument file */
XEXTERN	int InArgFile INIT( 0 );
XEXTERN	char arg[1024];		/* buffer for current argument */
XEXTERN	char *listn;		/* argument file name */
XEXTERN	FILE *listf;		/* argument file */
XEXTERN	FILE *File;
XEXTERN	FILE *Tfile;		/* title file */
X
!EOR!
echo extracting - makefile
sed 's/^X//' > makefile << '!EOR!'
X# MAKEFILES FOR CPR:
X# Pick out your system, extract the sub-makefile, and go.
X# Note: this makefile is untested, and probably won't work as is;
X# use it as a guide.
X
X# For UNIX System V.
XSRC=cpr.c parsargs.c list.c fold.c report.c
XOBJ=cpr.o parsargs.o list.o fold.o report.o
XHDR=cpr.h
XTARGET=cpr
XCC=cc -c -O
XLINK=cc -o cpr
X
X# For MSDOS using Turbo C 2.0 or later
XSRC=cpr.c parsargs.c list.c fold.c report.c
XOBJ=cpr.obj parsargs.obj list.obj fold.obj report.obj \tc\lib\wildargs.obj
XHDR=cpr.h
XTARGET=cpr.exe
XCC=tcc -O -DMSDOS -DTURBOC
XLINK=tcc
X
X# For MSDOS using Microsoft C 5.0 or later
X# (Note: in the "rules" section, end each command line with ';')
XSRC=cpr.c parsargs.c list.c fold.c report.c
XOBJ=cpr.obj parsargs.obj list.obj fold.obj report.obj \msc\lib\setargv.obj
XHDR=cpr.h
XTARGET=CPR.EXE
XCC=msc -O -DMSDOS
XLINK=link
X
X# For systems that don't expand wildcards on command line
X# (including earlier MS C and Turbo C),
X# replace the "special" .obj with "wildfile.obj", which you will write
X# yourself.  A sample wildfile.c is given for early Turbo C.
X# Also, compile with the additional flag NOWILD.
X
X# Generic Makefile section
X
X.c.o:
X        $(CC) $*.c
X
X$(TARGET) : $(OBJ)
X        $(LINK) $(OBJ)
X
X$(OBJ) : $(HDR)
X
X# Make a listing using cpr.  This "bootstraps" from a good cpr.
Xlisting : cpr.cpr
Xcpr.cpr : $(SRC) $(HDR)
X        cpr -Xp9w83 $(SRC) $(HDR) > cpr.cpr
X
!EOR!