[comp.sources.misc] v06i067: CPR a pretty printer for lots of C sources

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

Posting-number: Volume 6, Issue 67
Submitted-by: dvadura@watdragon.waterloo.edu (Dennis Vadura)
Archive-name: cpr


# This is a listing program for C sources, but handles other stuff as well.  It
# pretty prints the specified files, and creates a table of contents.
# We use it arround here a lot.
#
# I posted this program to comp.sources about 3 years ago and it was quite
# popular.  I have since improved the function finding ability, fixed up the
# handling of tabs and added a bunch of new features.  So I decided to submit
# it again.  It now compiles under DOS as well.  There is no makefile, but
# the first two lines of cpr.c give the command lines to use for compiling it.
#
#	This shar file contains:
#		cpr.c		- the C source for cpr
#		cpr.t 		- the troff source for the man page
#		cpr.p		- preformatted version of the manpage.
#------------------------------------------------------------------------------
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by watdragon!dvadura on Tue Feb  7 17:05:23 EST 1989
# Contents:  cpr.c cpr.p cpr.t
 
echo x - cpr.c
sed 's/^@//' > "cpr.c" <<'@//E*O*F cpr.c//'
/*	if UNIX:	cc -O cpr.c
 *	if MSDOS:	cc -O -DMSDOS cpr.c
 *
 *	This program prints the files named in its argument list, preceding
 *	the output with a table of contents. Each file is assumed to be C
 *	source code (but doesn't have to be) in that the program searches
 *	for the beginning and end of functions. Function names are added to
 *	the table of contents, provided the name starts at the beginning of
 *	a line. The function name in the output is double striken.
 *
 *	By default blank space is inserted after every closing '}'
 *	character. Thus functions and structure declarations are nicely
 *	isolated in the output. The only drawback to this is that structure
 *	initialization tables sometimes produce lots of white space.
 *	The "-r" option removes this space, or changes it to the indicated
 *	length.
 *
 *	The option "-l" indicates that the following argument is to be
 *	the page length used for output (changing the page length hasn't been
 *	tested much).
 *
 *	The option "-s" indicates that the table of contents should be sorted
 *	by function name within each file.
 *
 *	The option "-n" indicates that output lines should be numbered with
 *	the corresponding line number from the input file.
 *
 *	The option "-p" indicates what proportion of the page in steps of 16
 *	should be used for deciding if a new function needs a new page.
 *	That is -p12 (the default) indicates that if a function starts
 *	within the top 12/16 (3/4) of the page then do it, otherwise put it
 *	on a new page.  Thus the higher the number (upto 16) the closer to
 *	the bottom of the page will functions be started. -p0 says put each
 *	func on a new page.
 *
 *	Try it! You'll like it. (I call it cpr.c)
 *
 *	Written by:
 *		Paul Breslin
 *		Human Computing Resources Corp.
 *		10 St. Mary St.
 *		Toronto, Ontario
 *		Canada, M4Y 1P9
 *
 *		-- ...!decvax!utcsrgv!hcr!phb
 *
 *      Sorting and standard input reading from:
 *		Rick Wise, CALCULON Corp., Rockville, MD.
 *		-- ...!decvax!harpo!seismo!rlgvax!cvl!umcp-cs!cal-unix!wise
 *
 *	File modified time,
 *	numbered output,
 *	optional white space,
 *	improved function start tests from:
 *		David Wasley, U.C.Berkeley
 *		-- ...!ucbvax!topaz.dlw
 *	Modified the -r to leave variable amounts of space
 *		Patrick Powell, U. Waterloo
 *
 *      Changed handling of form feeds to start a new page AND print heading:
 *		Terry Doner, U of Waterloo
 *
 *	Fixed up to locate more functions, and added -p option
 *		Dennis Vadura, U of Waterloo
 *
 *		It will find things like  struct foo *f()...
 *		but not things like 	int
 *					f
 *					()...
 *		ie. the constraint is that the () must appear on the same line
 *		as the function name.
 *
 *  Clean up a bit for 80286 machines (lints a bit cleaner, too) 
 *      Dan Frank, Prairie Computing
 *
 *  Fixed a whole bunch of stuff and added lots of new flags.
 *      -S       sort and be case insensitive.
 *      -N       start numbering pages at 1 for each new file
 *      -T title cat the file title before the table of contents.
 *      -C       print only the table of contents
 *      -c       only try to look for function names in files whose suffix ends
 *	         in .c
 *      -f file  to handle file containing list of files to print. (for MSDOS)
 *      Dennis Vadura
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <string.h>
extern int errno; /* system error number */
extern char *sys_errlist[]; /* error message */
extern char *malloc() ; /* important for 8086-like systems */

#define BP		0xC		/* Form feed			*/

#define TOC_SIZE	4096

#define	NEWFILE		1
#define NEWFUNCTION	2

FILE *File;

int Braces; /* Keeps track of brace depth	*/
int LineNumber; /* Count output lines		*/
int PageNumber = 0; /* You figure this one out	*/
int PageLength = 66; /* -l <len> Normal paper length	*/
int PagePart = 12; /* Decision on paging for new fn*/
int PageEnd; /* Accounts for space at bottom	*/
int SawFunction;
int InComment;
int InString;
int Title=0;
int ResetPage=0;
int ContentsOnly=0;
int CaseInsensitive=0;
int OnlyCFiles=0;

long FileLineNumber; /* Input file line number	*/

char *TitleFile;
char *ProgName;
char Today[30];
char *Name; /* Current file name		*/

char FunctionName[80];
char FileDate[24]; /* Last modified time of file	*/

char SortFlag; /* -s == sort table of contents	*/
char NumberFlag; /* -n == output line numbers	*/
int Space_to_leave = 5; /* -r<number> space to leave	*/
int TabWidth = 0; /* -t <number> width of tabs 	*/

main(argc, argv)
char **argv;
{
   register int i;
   char *ctime();
   time_t thetime, time();
   char *parm;
   int c;

   ProgName = argv[0];
   thetime = time((time_t *)0);
   strcpy(Today,ctime(&thetime));

   for( i=1; argc > i; ++i )
   {
      if( argv[i][0] != '-' 
         || argv[i][1] == '\0' ) break;

      parm = argv[i];
      while( c = *++parm ) switch( c ){
      case 'f': goto endofoptions;
      case 't':
         if( argc < 3 ) Usage();
         TabWidth = atoi(argv[++i]);
         if( TabWidth < 0 )
            TabWidth = 0;
         break;

      case 'T':
         if( argc < 3 ) Usage();
         TitleFile = argv[++i];
         ++Title;
         break;

      case 'l':
         if( argc < 3 ) Usage();
         PageLength = atoi(argv[++i]);
         if( PageLength < 10) PageLength = 10;
         break;

      case 'S':
         ++CaseInsensitive;
      case 's':
         ++SortFlag;
         break;

      case 'C':
         ++ContentsOnly;
         break;

      case 'c':
         ++OnlyCFiles;
         break;

      case 'n':
         ++NumberFlag;
         break;

      case 'N':
         ++ResetPage;
         break;

      case 'r':
         if( (c = parm[1]) && isdigit( c )
            &&( c = atoi( parm+1 )) > 0 ){
            Space_to_leave = c;
         }
         else {
            Space_to_leave = 0;
         }
         while( *parm ){
            ++parm;
         }
         --parm;
         break;

      case 'p':
         if( (c = parm[1]) && isdigit( c )
            &&( c = atoi( parm+1 )) >= 0 ){
            PagePart = (c <= 16) ? c: 16;
         }
         while( *parm ){
            ++parm;
         }
         --parm;
         break;

      default:
         Usage();
         break;
      }
   }

endofoptions:
   PageEnd = PageLength - ((PageLength > 30) ? 7 : 1);

   StartTempFile();

   if( i == argc )
   { /* no file names */
      File = stdin;
      Name = "Standard Input";
      List();
   }

   for(; i < argc; ++i )
   {
      if( strcmp(argv[i], "-") == 0 )
      {
         File = stdin;
         Name = "Standard Input";
         List();
      }
      else if( strcmp(argv[i], "-f") == 0 )
      {
         char b[1024];
	 FILE *listf;

	 i++;
	 if( i == argc )
	 {
	    fprintf(stderr,"%s: missing file name for -f option\n", ProgName );
	    exit(1);
	 }

	 if( (listf = fopen( argv[i], "r" )) == NULL )
	 {
	    fprintf(stderr,"%s: list file '%s', not found\n", ProgName,
		    argv[i] );
	    exit(1);
	 }

         while( fgets(b, 1024, listf) != NULL )
         {
            if( strlen(b) ) b[strlen(b)-1]=0;

	    if( strcmp(b, "-") != 0 )
	    {
	       if( (File = fopen( Name = b, "r" )) == NULL )
	       {
		  fprintf(stderr,"%s: Can't open file '%s': %s\n",
		  ProgName, Name, sys_errlist[errno] );
		  continue;
	       }
	    }
	    else
	       File = stdin;

            List();
            if( File != stdin ) fclose(File);
         }
      }
      else {
         if( (File = fopen( Name = argv[i], "r" )) == NULL )
         {
            fprintf(stderr,"%s: Can't open file '%s': %s\n",
            ProgName, Name, sys_errlist[errno] );
            continue;
         }
         List();
         if( File != stdin ) fclose(File);
      }
   }

   if( PageNumber > 1 || LineNumber > 0 )
      putchar(BP);
   EndTempFile();

   DumpTableOfContents();
   DumpTempFiles();
   Done();
}

Usage()
{
   fprintf(stderr, "Usage: %s [-cCnNsS] [-T title] [-t tabwidth] [-p[num]] [-r[num]] [-l pagelength] [[-f] file] ...\n",
   ProgName);
   exit(1);
}

int SaveOut;
char *TempName;
char *Temp2Name;

StartTempFile()
{
   int Done();
   extern char *mktemp();

   CatchSignalsPlease(Done);

   SaveOut = dup(1);
#ifdef MSDOS
   TempName = "cpr0001.tmp";
#else
   TempName = mktemp("/tmp/cprXXXXXX");
#endif
   if( freopen(TempName, "w", stdout) == NULL )
   {
      fprintf(stderr, "%s: Can't open temp file '%s': %s\n", ProgName,
      TempName, sys_errlist[errno]);
      exit(1);
   }
}

EndTempFile()
{
#ifdef MSDOS
   Temp2Name = "cpr0002.tmp";
#else
   Temp2Name = mktemp("/tmp/cprXXXXXX");
#endif
   if( freopen(Temp2Name, "w", stdout) == NULL )
   {
      fprintf(stderr, "%s: Can't open temp file '%s': %s\n", ProgName,
      Temp2Name, sys_errlist[errno]);
      exit(1);
   }
}

DumpTempFiles()
{
   FILE *f;
   char b[256];
   register int pid, w;

   fclose(stdout);

#ifndef MSDOS
   dup(SaveOut);
   while( (pid = fork()) < 0 ) sleep(1);
   if( pid )
      while ((w = wait((int *)0)) != pid && w != -1);
   else
      {
      CatchSignalsPlease(SIG_DFL);

      if( ContentsOnly )
         execl( "/bin/cat", "cat", Temp2Name, (char *)0 );
      else
         execl( "/bin/cat", "cat", Temp2Name, TempName, (char *)0 );
      fprintf(stderr, "%s: exec of /bin/cat failed: %s\n", ProgName,
      sys_errlist[errno]);
      exit(0);
   }
#else
   CatchSignalsPlease(SIG_DFL);
   if( (f=fopen(Temp2Name,"r")) == NULL )
      fprintf(stderr,"%s: Can't open file '%s': %s\n",
      ProgName, TitleFile, sys_errlist[errno] );
   else
   {
      while( fgets(b, 256, f) != NULL )
         write(SaveOut,b,strlen(b));

      fclose(f);
   }

   if( !ContentsOnly )
      if( (f=fopen(TempName,"r")) == NULL )
         fprintf(stderr,"%s: Can't open file '%s': %s\n",
         ProgName, TitleFile, sys_errlist[errno] );
      else
      {
         while( fgets(b, 256, f) != NULL )
            write(SaveOut,b,strlen(b));

         fclose(f);
      }
#endif
}

Done()
{
   CatchSignalsPlease(SIG_DFL);

   fclose( stdout );
   if( TempName ) unlink( TempName );
   if( Temp2Name ) unlink( Temp2Name );

   exit(0);
}

CatchSignalsPlease(action)
int (*action)();
{
   if( signal(SIGINT, SIG_IGN) != SIG_IGN ) signal(SIGINT, action);
#ifndef MSDOS
   if( signal(SIGQUIT, SIG_IGN) != SIG_IGN ) signal(SIGQUIT, action);
   if( signal(SIGHUP, SIG_IGN) != SIG_IGN ) signal(SIGHUP, action);
#endif
}

List()
{
   register int bp;
   register char *bufp;
   char buffer[256];

   NewFile();
   bp = Braces = 0;
   InString = InComment = 0; /* reset for new file -DV */
   SawFunction = 0;
   bufp = buffer;
   while( fgets(bufp, sizeof(buffer), File) != NULL )
   {
      ++FileLineNumber;
      if( bp ) NewFunction();

      if( ++LineNumber >= PageEnd ) NewPage();

      if( bufp[0] == '\f'
         && bufp[1] == '\n'
         && bufp[2] == '\0' )
      {
         NewPage(); /* was strcpy(bufp, "^L\n");*/
         continue;
      }

      if( NumberFlag )
      {
         if( *bufp == '\n' )
            printf("        ");
         else
            printf("%6ld  ", FileLineNumber);
      }
      if( (Braces == 0) && LooksLikeFunction(bufp) )
         AddToTableOfContents(NEWFUNCTION);

      bp = PutLine(buffer);
   }
}

PutLine(l)
register char *l;
{
   extern char *EndComment();
   extern char *EndString();
   register char c;
   int bp;
   char *save;

   bp = 0;
   for( save = l; c = *l; ++l )
      if( InComment ) 
         l = EndComment(l);
      else if( InString )
         l = EndString(l);
      else
         switch(c)
         {
         case '{':
            ++Braces;
            break;

         case '}':
            if( --Braces == 0 )
               bp = 1;
            break;

         case '\'':
            for( ++l; *l && *l != '\''; ++l )
               if( *l == '\\' && *(l+1) ) ++l;
            break;

         case '"':
            InString = 1;
            break;

         case '/':
            if( *(l+1) == '*' )
            {
               InComment = 1;
               ++l;
            }
            break;
         }
   printf("%s", save);
   return(bp);
}

char *
EndComment(p)
register char *p;
{
   register char c;

   /*
       	 * Always return pointer to last non-null char looked at.
       	 */
   while( c = *p++ )
      if( c == '*' && *p == '/' )
      {
         InComment = 0;
         return(p);
      }
   return(p-2);
}

char *
EndString(p)
register char *p;
{
   register char c;

   /*
       	 * Always return pointer to last non-null char looked at.
       	 */
   while( c = *p++ )
      if( c == '\\' && *p )
      {
         ++p;
         continue;
      }
      else if( c == '"' )
      {
         InString = 0;
         return(p-1);
      }
   return(p-2);
}

NewFunction()
{
   register int i;

   if( Space_to_leave <= 0 || !SawFunction ) return;
   if( LineNumber + Space_to_leave > (PageLength * PagePart /16) )
      NewPage();
   else
      {
      for( i=0; i < (Space_to_leave); ++i ) putchar('\n');
      LineNumber += Space_to_leave;
   }

   SawFunction = 0;
}

#define HEADER_SIZE 3

NewPage()
{
   if( PageNumber >= 0 ) ++PageNumber;
   putchar(BP);
   LineNumber = 0;

   PutHeader();
}

PutHeader()
{
   register int i, l, j;

   putchar('\n');
   ++LineNumber;
   l = strlen(Name);
   for( j=0; j < l; ++j )
      printf("%c\b%c\b%c", Name[j], Name[j], Name[j]);

   if( PageNumber > 0 )
   {
      printf("  %.17s", FileDate);
      GoToColumn(l+19, 70);
      printf("Page:%4d\n\n", PageNumber);
      ++LineNumber;
      ++LineNumber;
   }
   else
      {
      GoToColumn(l, 55);
      printf("%s\n\n", Today);
      ++LineNumber;
      ++LineNumber;
   }
}

GoToColumn(from, to)
register int from, to;
{
   if( from < to)
   {
      if( TabWidth > 0 ){
         from &= ~(TabWidth-1);
         for( ; (from + TabWidth) <= to; from += TabWidth )
            putchar('\t');
      }
      for( ; from < to; from++ )
         putchar(' ');
   }
}

#define isidchr(c)	(isalnum(c) || (c == '_'))

/* This used to incorrectly identify a declaration such as
 *     int (*name[])() = { initializers ... }
 * as a function.  It also picked up this in an assembler file:
 *     #define MACRO(x) stuff
 *     MACRO(x):
 * Fixed both of these.   -IAN!
 */
LooksLikeFunction(s)
register char *s;
{
   register char *p;
   register int i;
   char *save;
   int t = TabWidth;

   if( InComment || InString ) return(0);
   if( OnlyCFiles )
   {
      char *e = Name+strlen(Name)-1;
      if( *e != 'c' || e[-1] != '.' ) return(0);
   }

   if( !t ) t = 8;
   save = s;

   i = 0;
   do
      {
      p = FunctionName;

      while( *s && (*s == ' ') || (*s == '\t') ) ++s;
      if( *s == '*' ) ++s;
      if( *s && (*s == ' ') || (*s == '\t') ) continue;
      if( !*s || ((*s != '_') && !isalpha(*s)) ) return(0);

      while( isidchr(*s) )
         *p++ = *s++;
      *p = '\0';

      while( *s && (*s == ' ') || (*s == '\t') ) ++s;
      i++;
   }
   while ( *s && *s != '(' && i < 4 );

   if( *s != '(' || *(s+1) == '*' ) return(0);

   for (i = 0; *s; s++)
   {
      switch( *s )
      {
      case '(':
         ++i;
         continue;

      case ')':
         --i;
         break;

      default:
         break;
      }
      if( i == 0 ) break;
   }
   if( !*s ) return(0);

   while( *s )
   {
      if( *s == '{') break;
      if( *s == ';' || *s == ':' ) return(0);
      ++s;
   }

   /*
       	 * This will cause the function name part of the line to
       	 * be double striken.  Note that this assumes the name and the opening
       	 * parentheses are on the same line...
       	 */

   if( p = strchr( save, '(' ) )
   {
      p--;
      while( p != save && isidchr( *(p-1) ) ) p--;
      for( i=0; save != p; save++ )
         if( *save == '\t' )
         {
            putchar('\t');
            i = ((i+t)/t)*t;
         }
         else
         {
            putchar(' ');
            i++;
         }

      for( ; *p != '('; p++ )
         if( *p == '\t' )
         {
            putchar('\t');
            i = ((i+t)/t)*t;
         }
         else
         {
            putchar(*p);
            i++;
         }
   }
   else
      for( i=0; *save && (*save == '*' || isidchr(*save)); ++save)
         if( *save == '*' )
         {
            putchar(' ');
            i++;
         }
         else
         {
            if( *save == '\t' )
               i = ((i+t)/t)*t;
            else
               i++;
            putchar(*save);
         }

   while( i --> 0 ) putchar('\b');

   SawFunction = 1;
   return(1);
}

static char *Toc[TOC_SIZE];
static int TocPages[TOC_SIZE];
static int TocCount;

AddToTableOfContents(type)
{
   if( TocCount > TOC_SIZE )
      return;
   if( TocCount == TOC_SIZE )
   {
      fprintf(stderr, "%s: More than %d Table of contents entries; others ignored.\n",
      ProgName, TOC_SIZE);
      ++TocCount;
      return;
   }

   if( type == NEWFILE )
      AddFile();
   else
      AddFunction();
}

AddFunction()
{
   register int l;
   register char *p;

   /* This heuristic stops multiple occurrences of a function,
       	 * selected by #ifdefs, to all end up many times over in the
       	 * Table of Contents.  One only needs to see it once.  -IAN!
       	 */
   if( TocCount > 0 && TocPages[TocCount-1] == PageNumber
      && strcmp(Toc[TocCount-1],FunctionName) == 0 )
      return;
   l = strlen(FunctionName);
   p = Toc[TocCount] = (char *)malloc(l+1);
   strcpy(p, FunctionName);
   TocPages[TocCount] = PageNumber;
   ++TocCount;
}

AddFile()
{
   register int i, l;
   register int len;
   char temp[20];

   len = strlen(Name) + 20;
   len = (len < 130) ? 130 : len;
   Toc[TocCount] = (char *)malloc(len);
   sprintf(Toc[TocCount], "\n    File: %s ", Name);
   l = strlen(Toc[TocCount]);
   if( l < 64 )
   {
      if( TabWidth > 0 ){
         i = ((64 - l) /TabWidth) + 1;
         while( i-- > 0 )
            Toc[TocCount][l++] = '\t';
      }
      else{
         while( l < 64 )
            Toc[TocCount][l++] = ' ';
      }
      Toc[TocCount][l++] = '\0';
   }
   sprintf(temp, "  Page %4d\n", PageNumber);
   strcat(Toc[TocCount], temp);
   ++TocCount;
}

NewFile()
{
   GetFileTime();
   if( ResetPage ) PageNumber=0;
   NewPage();
   AddToTableOfContents(NEWFILE);
   FileLineNumber = 0;
}

GetFileTime()
{
   struct stat st;
   extern char *ctime();

   if( File == stdin )
      strncpy(FileDate, &Today[4], 20);
   else
      {
      fstat(fileno(File), &st);
      strncpy(FileDate, ctime((time_t *)&st.st_mtime) + 4, 20);
   }
   strncpy(&FileDate[12], &FileDate[15], 5);
   FileDate[18] = '\0';
}

DumpTableOfContents()
{
   register int i, j;
   int index[TOC_SIZE];

   if( TocCount == 0 ) return;

   for (i = 0; i < TocCount; i++) index[i] = i;
   if( SortFlag )
      SortTable(index);

   Name = "Table of  Contents";

   PageNumber = -1;
   LineNumber = 0;

   if( Title )
   {
      FILE *f;
      int n;
      char b[256];

      if( (f=fopen(TitleFile,"r")) == NULL )
         fprintf(stderr,"%s: Can't open file '%s': %s\n",
         ProgName, TitleFile, sys_errlist[errno] );
      else
      {
         while( fgets(b, 256, f) != NULL )
         {
            if( strlen(b) ) b[strlen(b)-1]=0;
            puts(b);
            LineNumber++;
            if( ++LineNumber >= PageEnd ) NewPage();
         }

         fclose(f);
      }
   }
   else
      NewPage();

   for( i=0; i < TocCount; ++i )
   {
      if( Toc[index[i]][0] == '\n' )
      {
         if( (LineNumber + 5) >= PageEnd ) NewPage();

         printf("%s", Toc[index[i]]);
         LineNumber += 2;
         continue;
      }
      if( ++LineNumber >= PageEnd ) NewPage();

      printf("        %s ", Toc[index[i]]);
      for( j=strlen(Toc[index[i]]); j < 48; ++j ) putchar('.');
      printf(" %4d\n", TocPages[index[i]]);
   }

   if( ContentsOnly ) NewPage();
}

SortTable(index)
register int *index;
{
   register int i, temp, flag;
   char name1[256];
   char name2[256];

   do {
      flag = 0;
      for (i = 0; i < TocCount - 1; i++)
      {
         if( Toc[index[i]][0] == '\n' || Toc[index[i+1]][0] == '\n' )
            continue; /* don't sort across file names */
         strcpy( name1, Toc[index[i]] );
         strcpy( name2, Toc[index[i+1]] );

         if( CaseInsensitive )
         {
            char *p;
            char c;
            for(p=name1; c=*p; p++ )
               if( islower(c) ) *p=toupper(c);
            for(p=name2; c=*p; p++ )
               if( islower(c) ) *p=toupper(c);
         }

         if( strcmp(name1, name2) > 0)
         {
            temp = index[i];
            index[i] = index[i+1];
            index[i+1] = temp;
            flag = 1;
         }
      }
   }
   while( flag );
}
@//E*O*F cpr.c//
chmod u=rw,g=,o= cpr.c
 
echo x - cpr.p
sed 's/^@//' > "cpr.p" <<'@//E*O*F cpr.p//'




CPR(P)                 Unsupported Software                 CPR(P)



NNAAMMEE
     cpr  -  print 'C' files

SSYYNNOOPPSSIISS
     ppuubblliicc ccpprr [-cCnNsS] [-T title] [-t tabwidth] [-p[num]]
     [-r[num]] [-l pagelength] [[-f] file] ...

DDEESSCCRRIIPPTTIIOONN
     _c_p_r prints the files named in its argument list, preceding
     the output with a table of contents.  If a filename is pre-
     ceded by --ff then the specified file is assumed to contain a
     list of files to be printed.  The filename "-" specifies
     standard input.  Each file printed is assumed to be C source
     code (but doesn't have to be see -c option below) in that
     the program searches for the beginning and end of functions.
     Function names are added to the table of contents, provided
     the name starts at the beginning of a line. The function
     name in the output is double struck.

     By default, blank lines are inserted after every closing '}'
     character. Thus functions and structure declarations are
     nicely isolated in the output. The only drawback to this is
     that structure initialization tables sometimes produce lots
     of white space.  The --rr[n] option changes the space left to
     the specified number of lines.  If no number is specified,
     no space is left.

     The option --ll indicates that the following argument is to be
     the page length used for output, rather than the default 66
     lines.

     The option --cc forces cpr to "look" for functions only in
     files whose suffix ends in '.c'.

     The option --CC forces cpr to produce only a table of con-
     tents, the file contents themselves are not printed.

     The option --TT ttiittllee causes cpr to print the contents of the
     file ttiittllee before printing the table of contents.

     The option --ss indicates that the table of contents should be
     sorted by function name within each file.  Specifying --SS
     performs the sort in a case-insensitive manner.

     The option --nn indicates that output lines should be numbered
     with the corresponding line number from the input file.

     The option --NN forces page numbering to start with page 1 for
     each file processed.

     The option --tt _t_a_b_w_i_d_t_h causes output to be produced that
     will look correct with tabs expanded every _t_a_b_w_i_d_t_h columns.



Formatted 89/02/07              UW                              1




CPR(P)                 Unsupported Software                 CPR(P)



     (The default is every 8 columns.) A _t_a_b_w_i_d_t_h of zero
     suppresses use of tabs; all output will be spaced using
     blanks.

     The option --pp pprrooppoorrttiioonn indicates what proportion of the
     page in steps of 16 should be used for deciding if a new
     function needs a new page.  That is -p12 (the default) indi-
     cates that if a function starts within the top 12/16 (3/4)
     of the page then do it, otherwise put it on a new page.
     Thus the higher the number (up to 16) the closer to the bot-
     tom of the page will functions be started.  --pp00 says put
     each function on a new page.

FFIILLEESS
     /tmp/cpr$$          - temp files holding text

SSEEEE AALLSSOO
     cb(1), cat(1), fold(1), num(1), pr(1)

DDIIAAGGNNOOSSTTIICCSS
     Various messages about being unable to open files.  Self
     explanatory.

BBUUGGSS
     This program sometimes thinks some declarations are func-
     tions.  Functions declarations whose opening ( is not found
     on the same line as the function name will not be recognized
     as functions.  Use of macros to define functions will also
     confuse it.  Comments are not recognized, and #ifdef's are
     not processed, so stuff inside them gets interpreted.  If
     the same function definition appears multiple times on the
     same page, only one entry is made in the table of contents,
     to reduce the number of redundant entries.

AAUUTTHHOORR
     Paul Breslin        original, Human Computing Resources
                         Corp.

     Rick Wise           sorting and use of standard input, CAL-
                         CULON Corp.

     David Wasley        numbering, times, etc., U. C. Berkley.

     Patrick Powell      variable number of lines between func-
                         tions, University of Waterloo

     Ian! D. Allen       variable tabs; redundant TOC suppres-
                         sion, University of Waterloo

     Dennis Vadura       more options; better function recogni-
                         tion, University of Waterloo




Formatted 89/02/07              UW                              2




CPR(P)                 Unsupported Software                 CPR(P)



SSUUPPPPOORRTT
     This software is _n_o_t supported by MFCF.

     Send complaints or suggestions to dvadura@dragon.



















































Formatted 89/02/07              UW                              3
@//E*O*F cpr.p//
chmod u=rw,g=,o= cpr.p
 
echo x - cpr.t
sed 's/^@//' > "cpr.t" <<'@//E*O*F cpr.t//'
@.\" to produce the man page.
@.\" troff -man -Tdumb cpr.tf | ddumb >cpr.p
@.\"
@.TH CPR P UW 
@.SH "NAME"
cpr  \-  print 'C' files
@.SH "SYNOPSIS"
@.B public cpr
[-cCnNsS] [-T title] [-t tabwidth] [-p[num]] [-r[num]] [-l pagelength]
[[-f] file] ...
@.SH "DESCRIPTION"
@.I cpr
prints the files named in its argument list, preceding
the output with a table of contents.
If a filename is preceded by
@.B -f
then the specified file is assumed to contain a list of files to be
printed.  The filename "-" specifies standard input.
Each file printed is assumed to be C
source code (but doesn't have to be see -c option below)
in that the program searches
for the beginning and end of functions.
Function names are added to
the table of contents, provided the name starts at the beginning of
a line. The function name in the output is double struck.
@.PP
By default, blank lines are inserted after every closing '}'
character. Thus functions and structure declarations are nicely
isolated in the output. The only drawback to this is that structure
initialization tables sometimes produce lots of white space.
The \fB\-r\fP[n] option changes the space left to the specified
number of lines.  If no number is specified, no space is left.
@.PP
The option \fB\-l\fP indicates that the following argument is to be
the page length used for output, rather
than the default 66 lines.
@.PP
The option \fB\-c\fP forces cpr to "look" for functions only in files
whose suffix ends in '.c'.
@.PP
The option \fB\-C\fP forces cpr to produce only a table of contents, the
file contents themselves are not printed.
@.PP
The option \fB\-T title\fP causes cpr to print the contents of the file
@.B title
before printing the table of contents.
@.PP
The option \fB\-s\fP indicates that the table of contents should be sorted
by function name within each file.
Specifying \fB\-S\fP performs the sort in a case-insensitive manner.
@.PP
The option \fB\-n\fP indicates that output lines should be numbered with
the corresponding line number from the input file.
@.PP
The option \fB\-N\fP forces page numbering to start with page 1 for each
file processed.
@.PP
The option \fB\-t\fI\ tabwidth\fR
causes output to be produced that will look correct with tabs expanded every
@.I tabwidth
columns.
(The default is every 8 columns.)
A
@.I tabwidth
of zero suppresses use of tabs; all output will be spaced using blanks.
@.PP
The option
@.B -p proportion
indicates what proportion of the page in steps of 16
should be used for deciding if a new function needs a new page.
That is -p12 (the default) indicates that if a function starts
within the top 12/16 (3/4) of the page then do it, otherwise put it
on a new page.
Thus the higher the number (up to 16) the closer to
the bottom of the page will functions be started.
@.B -p0
says put each function on a new page.
@.SH "FILES"
@.nf
/tmp/cpr$$		\- temp files holding text
@.fi
@.SH "SEE ALSO"
cb(1), cat(1), fold(1), num(1), pr(1)
@.SH "DIAGNOSTICS"
Various messages about being unable to open files.
Self explanatory.
@.SH "BUGS"
This program sometimes thinks some declarations are functions.
Functions declarations whose opening ( is not found on the same line
as the function name will not be recognized as functions.
Use of macros to define functions will also confuse it.
Comments are not recognized, and #ifdef's are not processed,
so stuff inside them gets interpreted.
If the same function definition appears multiple times on the same page,
only one entry is made in the table of contents, to reduce the number
of redundant entries.
@.SH "AUTHOR"
@.IP "Paul Breslin" 2.0i
original, Human Computing Resources Corp.
@.IP "Rick Wise" 2.0i
sorting and use of standard input, CALCULON Corp.
@.IP "David Wasley" 2.0i
numbering, times, etc., U. C. Berkley.
@.IP "Patrick Powell" 2.0i
variable number of lines between functions, University of Waterloo
@.IP "Ian! D. Allen" 2.0i
variable tabs; redundant TOC suppression, University of Waterloo
@.IP "Dennis Vadura" 2.0i
more options; better function recognition,
University of Waterloo
@.SH SUPPORT
This software is
@.I not
supported by
@.SM MFCF.
@.PP
Send complaints or suggestions to dvadura@dragon.
@//E*O*F cpr.t//
chmod u=rw,g=,o= cpr.t
 
exit 0
-- 
--------------------------------------------------------------------------------
Dennis Vadura, Computer Science Dept.,          UUCP,BITNET:    dvadura@water
University of Waterloo, Waterloo, Ont.	        EDU,CDN,CSNET:  dvadura@waterloo
================================================================================

-- 
--------------------------------------------------------------------------------
Dennis Vadura, Computer Science Dept.,          UUCP,BITNET:    dvadura@water
University of Waterloo, Waterloo, Ont.	        EDU,CDN,CSNET:  dvadura@waterloo
================================================================================