program to create output with a table of contents

wise at cal-unix.UUCP wise at cal-unix.UUCP
Wed Aug 17 23:16:55 AEST 1983


The table of contents program as originally given was excellent.  However,
it seemed worthwhile to make a few minor modifications and one addition.
These changes are in our local version, and if you can use them,

they are:

    An alphabetically sorted index is appended to the files.

    If no file names are given, the standard input is read.

    If a '-' (minus sign) is encountered in a file list, the standard
	input is read.

My compliments to Mr. Breslin.  The program was well done, which allowed me
to make these mods in less than an hour.


/*
 *	This program prints the files named in its argument list, preceding
 *      the output with a table of contents and appending an index.
 *      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).
 *
 *      If no file names are given, stdin is read.  '-' in the file list
 *      also causes stdin to be read.
 *
 *	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
 *
 *      Index and standard input reading added by Rick Wise, CALCULON Corp.,
 *      Rockville, MD. -- decvax!harpo!seismo!rlgvax!cvl!umcp-cs!cal-unix!wise
 */

#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)
	int     argc;
	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();

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

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

	if( PageNumber > 1 || LineNumber > 0 )
		putchar(BP);
	ListIndex();
	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);
  }

ListIndex()
{
	register int	i, j, l;
	int     index[1024],
		temp,
		flag;

	if( TocCount == 0 ) return;
	for (i = 0; i < TocCount; i++)
		index[i] = i;
	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 */
			if (strcmp (Toc[index[i]], Toc[index[i+1]]) > 0) {
				temp = index[i];
				index[i] = index[i+1];
				index[i+1] = temp;
				flag = 1;
			}
		}
	} while (flag);


	Name = "Index";

	PageNumber = -1;
	LineNumber = 0;
	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("\t\t%s ", Toc[index[i]]);
		l = strlen(Toc[index[i]]);
		for( j=l; j < 48; ++j ) putchar('.');
		printf(" %d\n", TocPages[index[i]]);
	  }
	putchar(BP);
  }



More information about the Comp.sources.unix mailing list