another version of cpr
BILL K. William C. King
wck at ccieng5.UUCP
Wed Aug 24 14:16:06 AEST 1983
Here is a version of the program `cpr' which has been floating around
which I have hacked up. I've added a few options. The first is the
`-n' option which causes lines in the source file to be numbered. The
second option is `-o' which is used for putting One-Function-Per-Page.
In addition I have added line folding. (A default line width of 80 is
used instead of having an option to specify the line length because I
did not feel like changing things in the table of contents which
use this as a default.)
I have also written up a man page since I had not seen any others
floating around.
By the way, for some reason unknown to me now I changed the `-l' option
to take the space from between that and the supplied page length.
Lance E. Shepard
a lowly co-op from:
Computer Consoles, Inc.
&
Rochester Institute of Technology
...!seismo!rochester!ritcv!ritvp!les8070
or for a short time longer
...!seismo!rochester!ritcv!ccieng5!wck
________________
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting cpr.n'
sed 's/^X//' <<'//go.sysin dd *' >cpr.n
X.TH CPR 1
X.SH "NAME"
cpr \- print `C' files
X.SH "SYNOPSIS"
X.B cpr
[ -l# ] [ -n ] [ -o ]
[ file ] ...
X.SH "DESCRIPTION"
X.I Cpr
produces a printed listing of one or more
X.B `C'
X.I files.
The output is separated into pages headed by
the name of the file (in bold face) a date, and the page number.
Function names are output in bold face.
An index (same format as table of contents, except in alphabetical order)
now follows the output file.
Lines greater than 80 columns in width (minus the width of added line numbers,
if any) are folded.
X.PP
The following options are allowed:
X.TP
X.BI \-l#
Take the length of the page to be
X.I #
lines instead of the default 66.
X.TP
X.BI \- n
Print line numbers.
X.TP
X.BI \- o
Print
X.I one\-function\-per\-page.
X.PP
X.SH "FILES"
X.nf
X/tmp/cpr$$ temp files holding text
X/tmp/CPR$$
X.fi
X.SH "SEE ALSO"
X.nf
cat(1)
fold(1)
num(1)
pr(1)
X.fi
X.SH "DIAGNOSTICS"
Various messages about being unable to open files.
Self explanatory.
X.SH "BUGS"
Mistakes structure declarations as a function.
X.br
Unable to find function names that do not begin at the left margin.
X.SH "AUTHOR"
X.nf
Paul Breslin original
Human Computing Resources Corp.
Rick Wise modified original
CALCULON Corp.
Lance E. Shepard modified original
CCI & RIT
X.fi
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 444 cpr.n
/bin/echo -n ' '; /bin/ls -ld cpr.n
fi
/bin/echo 'Extracting cpr.c'
sed 's/^X//' <<'//go.sysin dd *' >cpr.c
X/*
* 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
X/*
X/*
* Index and standard input reading added by Rick Wise, CALCULON Corp.,
* Rockville, MD. -- decvax!harpo!seismo!rlgvax!cvl!umcp-cs!cal-unix!wise
*/
X/*
* The following options have been added. The `-n' option is used
* to number source lines. Numbering starts at 1 (one) and is reset
* to this number for each file. The `-o' option is used to put 1
* (one) function on each page instead of multiple functions per page.
* Line folding has been added.
*
* The `-l' option has been changed so that the blank space between
* it and the following number has been eliminated. ("-l60" instead
* of "-l 60")
*
* modified by: Lance E. Shepard
* CCI & RIT (a lowly co-op)
* Rochester, NY
*
* ...!rochester!ritcv!ritvp!les8070
*
* NOTE:
* These modifications have been TESTED only ONCE. (And this
* one time was under IDEAL CONDITIONS.) NO GUARANTEES!!
*
*/
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#define BP 0xC /* Form feed */
#define MAX_S 256 /* Maximum string length */
#define WIDTH 80 /* Page Width */
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;
int OnePerPage = 0;
int NumLines = 0;
int Number = 1;
char *Name; /* Current file name */
char FunctionName[40];
char *ProgName;
char *Today;
main(argc, argv)
int argc;
char **argv;
{
register int i = 1;
char *ctime();
long thetime, time();
ProgName = argv[0];
thetime = time(0);
Today = ctime(&thetime);
while (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'l':
if (!isdigit(argv[i][2])) {
Usage();
break;
}
PageLength = atoi(&argv[i][2]);
break;
case 'n':
NumLines = 1;
break;
case 'o':
OnePerPage = 1;
break;
default:
Usage();
break;
}
i++;
}
PageEnd = PageLength - (1 + 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 [-lpagelength] [-n] [-o] 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();
char *expand();
char *substr();
register char c;
int bp;
char *save;
char *section;
int offset;
char Digits[15];
int Size;
int pos;
bp = 0;
for( save = expand(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;
}
if (NumLines) {
sprintf(Digits,"[%d] ", Number);
Size = strlen(Digits);
}
else
Size = 0;
if (strlen(save) + Size > WIDTH) {
section = substr(save, 0, WIDTH - Size);
if (section[strlen(section) - 1] != ' ') {
offset = (int) rindex(section, ' ') - (int) section;
section[offset] = NULL;
}
else
offset = strlen(section) - 1;
if (NumLines) {
printf("[%d] %s\n", Number++, section);
}
else {
printf("%s\n", section);
}
pos = offset + 1;
do {
section = substr(save, pos, pos + WIDTH - 8);
if (strlen(section) + 8 > WIDTH &&
section[strlen(section) - 1] != ' ') {
offset = (int) rindex(section, ' ') -
(int) section;
section[offset] = NULL;
}
if (section[strlen(section) - 1] == '\n')
section[strlen(section) - 1] = NULL;
printf("C %s\n", section);
if (++LineNumber > PageEnd)
NewPage();
} while ((pos += offset + 1) < strlen(save));
}
else {
if (NumLines)
printf("[%d] %s", Number++, save);
else
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
{
if (!OnePerPage) {
for( i=0; i < (PageLength/7); ++i ) putchar('\n');
LineNumber += PageLength/7;
}
else
NewPage();
}
}
#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;
char *save;
int Cnt;
char Digits[15];
int AddOne = 0;
if( InComment || InString ) return(0);
p = FunctionName;
save = s;
if( *s == '*' ) {
++s;
AddOne = 1;
}
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.
*/
if (NumLines) {
sprintf(Digits,"[%d] ", Number);
Cnt = strlen(Digits) + AddOne;
while (Cnt-- > 0) putchar(' ');
AddOne = 0;
}
while (*save && *save != '(') putchar(*save++);
putchar('\r');
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;
if (NumLines)
Number = 1;
}
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);
}
X/*
* This is the function substr(). The calling sequence is:
*
* substr(string, startpos, endpos)
*
* The function returns a pointer to a static string (written over
* on subsequent calls) which is a substring of the string `string'
* starting at `startpos' (the first position is 0 (zero)) and ending
* at `endpos' (non-inclusive). All arguments must be present or
* strange things happen with the system stack.
*
* An example of the use is:
*
* x = substr(string, 2, 5);
* (where string == "This is a test.")
*
* This call returns a pointer to:
*
* "is "
*
* An error code of -1 is returned is the `endpos' is greater than
* `startpos'
*
*
* Lance E. Shepard
*/
char *
substr(string, start, end)
char *string;
int start;
int end;
{
static char retstr[MAX_S];
int loop1;
int loop2;
if (end < start) {
exit(-1);
}
for (loop2 = 0; loop2 < MAX_S; loop2++)
retstr[loop2] = NULL;
for (loop1 = start, loop2 = 0; string[loop1] != NULL &&
loop1 < end && loop2 <= MAX_S; loop1++, loop2++)
retstr[loop2] = string[loop1];
retstr[++loop2] = NULL;
return(retstr);
}
X/*
* This is the function `char *expand().' This function takes as
* an argument a NULL terminated string and replaces all occurances
* of the tab character with 8 (eight) spaces. The function returns
* a pointer to a static string which is overwritten on subsequent
* calls.
*/
char *
expand(string)
char *string;
{
int count;
static char retstr[MAX_S];
for (count = 0; count < MAX_S; retstr[count++] = NULL) ;
for (count = 0; *string != NULL; count++, string++) {
if (*string == '\t') {
strcpy(&retstr[count], " ");
count += 7;
}
else
retstr[count] = *string;
}
retstr[count] = NULL;
return(retstr);
}
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);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 444 cpr.c
/bin/echo -n ' '; /bin/ls -ld cpr.c
fi
More information about the Comp.sources.unix
mailing list