program to create output with a table of contents

Paul Breslin phb at hcr.UUCP
Thu Aug 4 07:08:07 AEST 1983


/*
 *	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. White space
 *	is inserted after every terminating '}' character. Thus functions
 *	and structure declarations are nicely isolated in the output. The only
 *	drawback to this is that structure initialization tables sometimes
 *	produce large quantities of white space.
 *
 *	The single 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).
 *
 *	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
 */

#include <stdio.h>
#include <ctype.h>
#include <signal.h>

#define BP		0xC		/* Form feed			*/

FILE	*File;
int	Braces;				/* Keeps track of brace depth	*/
int	LineNumber;			/* Count output lines		*/
int	PageNumber = 1;			/* You figure this one out	*/
int	PageLength = 66;		/* Normal paper length		*/
int	PageEnd;			/* Accounts for space at bottom	*/
int	InComment;
int	InString;
char	*Name;				/* Current file name		*/
char	FunctionName[40];
char	*ProgName;
char	*Today;

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

	ProgName = argv[0];
	thetime	 = time(0);
	Today	 = ctime(&thetime);
	if( argv[1][0] == '-' && argv[1][1] == 'l' && argv[1][2] == '\0' )
	  {
		PageLength = atoi(argv[2]);
		i = 3;
		if( argc <= 3 ) Usage();
	  }
	else
	  {
		i = 1;
		if( argc <= 1 ) Usage();
	  }
	PageEnd = PageLength - (PageLength / 20);

	StartTempFile();

	for(; i < argc; ++i )
	  {
		if( (File = fopen( Name = argv[i], "r" )) == NULL )
		  {
			fprintf(stderr, "%s: Can't open file \"%s\"\n",
				ProgName, Name );
			continue;
		  }
		List();
		fclose(File);
	  }

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

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

Usage()
  {
	fprintf(stderr, "Usage: %s [-l pagelength] file ...\n", ProgName);
	exit(1);
  }

int	SaveOut;
char	*TempName;
char	*Temp2Name;

StartTempFile()
  {
	extern char	*mktemp();

	CatchSignalsPlease();
	SaveOut = dup(1);
	TempName = mktemp("/tmp/cprXXXXXX");
	if( freopen(TempName, "w", stdout) == NULL )
	  {
		fprintf(stderr, "%s: Can't open temp file!\n", ProgName);
		exit(1);
	  }
  }

EndTempFile()
  {
	Temp2Name = mktemp("/tmp/CPRXXXXXX");
	if( freopen(Temp2Name, "w", stdout) == NULL )
	  {
		fprintf(stderr, "%s: Can't open temp file!\n", ProgName);
		exit(1);
	  }
  }

DumpTempFiles()
  {
	register int	pid, w;

	fclose(stdout);
	dup2(SaveOut, 1);

	while( (pid = fork()) < 0 ) sleep(1);
	if( pid )
		while ((w = wait(0)) != pid && w != -1);
	else
	  {
		execl( "/bin/cat", "cat", Temp2Name, TempName, 0 );
		fprintf(stderr, "%s: exec failed!\n", ProgName);
		exit(0);
	  }
  }

Done()
  {
	signal(SIGQUIT, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGINT, SIG_IGN);

	if( TempName )  unlink( TempName );
	if( Temp2Name ) unlink( Temp2Name );
	exit(0);
  }

CatchSignalsPlease()
  {
	signal(SIGQUIT, Done);
	signal(SIGHUP, Done);
	signal(SIGINT, Done);
  }

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

	NewPage();
	NewFile();
	bp = Braces = 0;
	while( fgets(buffer, 256, File) != NULL )
	  {
		if( bp )
			NewFunction();
		if( ++LineNumber > PageEnd ) NewPage();
		if( (Braces == 0) && LooksLikeFunction(buffer) )
			AddToTableOfContents();
		bp = PutLine(buffer);
	  }
  }

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

	save = l;

	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 '\'':
				++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;

	while( c = *p++ )
		if( c == '*' && *p == '/' )
		  {
			InComment = 0;
			break;
		  }
	return(p-1);
  }

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

	while( c = *p++ )
		if( c == '\\' ) 
		  {
			++p;
			continue;
		  }
		else if( c == '"' )
		  {
			InString = 0;
			break;
		  }
	return(p-1);
  }

NewFunction()
  {
	register int	i;

	if( LineNumber > (PageLength * 3 / 4) )
		NewPage();
	else
	  {
		for( i=0; i < (PageLength/7); ++i ) putchar('\n');
		LineNumber += PageLength/7;
	  }
  }

#define HEADER_SIZE 3

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

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

	putchar('\n');
	l = strlen(Name);
	for( j=0; j < 3; ++j )
	  {
		printf("%s", Name);
		if( j < 2 )
			for( i=0; i < l; ++i ) putchar('\b');
	  }
	if( PageNumber > 0 )
	  {
		for( i = (l+7)/8; i < 9; ++i ) putchar('\t');
		printf("Page: %d\n\n", PageNumber);
	  }
	else
	  {
		for( i = (l+7)/8; i < 7; ++i ) putchar('\t');
		printf("%s\n\n", Today);
	  }

	LineNumber += HEADER_SIZE;
  }

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

LooksLikeFunction(s)
register char	*s;
  {
	register char	*p;
	register int	i;
	char		*save;

	if( InComment || InString ) return(0);
	p = FunctionName;
	save = s;
	if( *s == '*' ) ++s;

	if( (*s == '_') || isalpha(*s) )
	  {
		while( isidchr(*s) )
			*p++ = *s++;
		*p = '\0';
		while( *s == ' ' ) ++s;
		if( *s != '(' ) return(0);
		while( *s ) if( *s == ')' ) break; else ++s;
		if( !*s ) return(0);

		/*
		 * This will cause the function name part of the line to
		 * be double striken.
		 */
		for( i=0; *save && *save != '('; ++i ) putchar(*save++);
		while( i --> 0 ) putchar('\b');

		return(1);
	  }
	return(0);
  }

char	*Toc[1024];
int	TocPages[1024];
int	TocCount;

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

	l = strlen(FunctionName);
	p = Toc[TocCount] = (char *)malloc(l+1);
	strcpy(p, FunctionName);
	TocPages[TocCount] = PageNumber;
	++TocCount;
  }

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

	Toc[TocCount] = (char *)malloc(130);
	sprintf(Toc[TocCount], "\n\tFile: %s ", Name);
	l = strlen(Toc[TocCount]) - 1;
	if( l < 64 )
	  {
		i = (64 - l) / 8;
		for( l=0; l < i; ++l ) strcat(Toc[TocCount], "\t");
	  }
	sprintf(temp, "  Page %d\n", PageNumber);
	strcat(Toc[TocCount], temp);
	++TocCount;
  }

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

	if( TocCount == 0 ) return;
	Name = "Table of Contents";

	PageNumber = -1;
	LineNumber = 0;
	NewPage();

	for( i=0; i < TocCount; ++i )
	  {
		if( Toc[i][0] == '\n' )
		  {
			if( (LineNumber + 5) > PageEnd )
				NewPage();
			printf("%s", Toc[i]);
			LineNumber += 2;
			continue;
		  }
		if( ++LineNumber > PageEnd )
			NewPage();
		printf("\t\t%s ", Toc[i]);
		l = strlen(Toc[i]);
		for( j=l; j < 48; ++j ) putchar('.');
		printf(" %d\n", TocPages[i]);
	  }
	putchar(BP);
  }



More information about the Comp.sources.unix mailing list