home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD2.mdf
/
c
/
tools
/
formatte
/
cpr
/
cpr.c
next >
Wrap
C/C++ Source or Header
|
1986-07-08
|
20KB
|
859 lines
/*
* 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.
*
* 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
*/
/*
* 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!!
*
*/
/* This might be the last crack at this. I added the ability to read
* standard input, removed dup2() calls to improve transportability,
* and made sorting the table of contents an option (this was suggested
* by the original author, Paul Breslin, who pointed out that people
* (and VAXEN) will use the sorted or unsorted but probably not both).
* So now there's only one table of contents (at the beginning), which
* is sorted if the -s option is used. I wanted to make sorting the
* default, but that would be inconsistant with the other options, so
* if you're like me, alias it to cpr -s. I also robustized the command
* line decoding, and set it up so that -l expects the length as the next
* argument, but will accept it without an intervening space, so -l30
* means the same as -l 30. The same is true of a new option, -w.
* -w allows the user to specify the line width.
*
* The program should also grab fewer non-function constructs. It now
* compares potential function names with the 'C' reserved words (from
* "The C Programming Language", Kernighan and Ritchie, 1978) and
* discards those that match. No, this doesn't take forever. Look
* at the code.
*
* I agree with people who dislike 3 million options for one little
* program, but plead that when reasonable defaults are provided it
* needn't make a program cumbersome. Line width defaults to 132,
* since we print mostly on our line printer, but the default is a
* #define called WIDTH, so it's easy to change. Likewise for page
* length (called LENGTH).
*
* I added a feature similar to that suggested by Rich Johnson at
* Bell Labs, Whippany. Rather than substituting eight spaces for
* every tab, it looks for the next tab stop in a string defining
* tabs.
*
* I tested this rather thoroughly, but I also won't guarantee anything.
*
* Rick Wise
* CALCULON Corp.
* Rockville MD, 20850
*
* decvax!harpo!seismo!rlgvax!cal-unix!wise
*
*/
/* I fixed the lack of a page title on the table of contents page.
* I made the table of contents only in sorted mode.
* I made the function that deturmines weather a string is a function
* or not much more intellegent. It now nolonger has to start at the
* beginning of a line!!!
* Overstrike now uses \r instead of \b for my printer's sake.
*
*
* Blake McBride
* 3900 SW 52 AVE #803
* Pembroke Park, FL 33023
*/
#include <stdio.h>
#include <fcntl.h>
/* #include <signal.h> */
#define rindex strrchr
#define mktemp(x) "cpr$.tmp"
#define BP 0xC /* Form feed */
#define MAX_S 256 /* Maximum string length */
#define LENGTH 66 /* Default Page Length */
#define WIDTH 132 /* Default page width */
#define N_FILES 20 /* Maximum number of files */
#define TOC_LEN 1024 /* Max no of T of C entries */
/* The following string is the definition of tab stops. Every 'T' is a
** tab, any other character is not. It is currently defined as a tab
** every 8 spaces. The comment below helps if you want to modify this,
** each row being 0+n, 50+n, 100+n, and 150+n, where n is the number
** above the declaration. Don't try to number each row with a comment,
** because you'll notice that the '\'s make it one big string.
*/
char *Rs(), *Datetime();
/* 1 2 3 4 5
12345678901234567890123456789012345678901234567890 */
char *TabDef = "\
-------T-------T-------T-------T-------T-------T--\
-----T-------T-------T-------T-------T-------T----\
---T-------T-------T-------T-------T-------T------\
-T-------T-------T-------T-------T-------T-------T";
FILE *File;
int Braces; /* Keeps track of brace depth */
int LineNumber; /* Count output lines */
int PageNumber = 1; /* You figure this one out */
int PageLength = LENGTH; /* Normal paper length */
int PageWidth = WIDTH; /* normal page width */
int PageEnd; /* Accounts for space at bottom */
int InComment;
int InString;
int OnePerPage = 0;
int NumLines = 0;
int Number = 1;
int WantSorted = 1; /* Sort the table of contents */
char *Name; /* Current file name */
char FunctionName[40];
char *ProgName;
char Todayv[45];
char *STDIN = "\n"; /* special string pointer value to */
/* flag a file as being stdin */
main(argc, argv)
int argc;
char **argv;
{
register int i,
nextf = 0; /* index into fname[] */
char *fname[N_FILES]; /* file names to be worked on */
/* char *ctime();
long thetime, time();
*/
ProgName = argv[0];
/* thetime = time(0);
Todayv = ctime(&thetime);
*/
Datetime(Todayv);
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'l':
if ( ! argv[i][2]) {
if (++i >= argc)
Usage();
if ( ! ISdigit (argv[i][0]))
Usage();
PageLength = atoi (argv[i]);
}
else {
if (!ISdigit(argv[i][2]))
Usage();
PageLength = atoi(&argv[i][2]);
}
break;
case 'w':
if ( ! argv[i][2]) {
if (++i >= argc)
Usage();
if ( ! ISdigit (argv[i][0]))
Usage();
PageWidth = atoi (argv[i]);
}
else {
if (!ISdigit(argv[i][2]))
Usage();
PageWidth = atoi(&argv[i][2]);
}
break;
case 'n':
NumLines = 1;
break;
case 'o':
OnePerPage = 1;
break;
case 's':
WantSorted = 1;
break;
case '\0':
if (nextf >= N_FILES) {
fprintf (stderr, "%s: too many files\n", argv[0]);
exit (1);
}
fname[nextf++] = STDIN;
break;
default:
Usage();
break;
}
}
else {
if (nextf >= N_FILES) {
fprintf (stderr, "%s: too many files\n", argv[0]);
exit (1);
}
fname[nextf++] = argv[i];
}
}
if ( ! nextf)
fname[nextf++] = STDIN; /* if no files specified, use stdin */
PageEnd = PageLength - (1 + PageLength / 20);
StartTempFile();
for (i = 0; i < nextf; i++) {
if (fname[i] == STDIN) {
File = stdin;
Name = "standard input";
}
else {
if( (File = fopen( Name = fname[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 )
BreakPage();
EndTempFile();
DumpTableOfContents();
DumpTempFile();
Done();
}
Usage()
{
fprintf (stderr, "Usage: %s [-lpagelength] [-wpagewidth] [-n] [-o] [-s] file ...\n", ProgName);
exit(1);
}
char *TempName;
FILE *TempFile;
StartTempFile()
{
/* extern char *mktemp(); */
CatchSignalsPlease();
TempName = mktemp("cprXXXXXX");
if( (TempFile = fopen(TempName, "w")) == NULL )
{
fprintf (stderr, "%s: Can't open temp file!\n", ProgName);
exit(1);
}
}
EndTempFile()
{
fclose (TempFile);
}
DumpTempFile()
{
int fd,
n;
char buff[1024];
if ((fd = open (TempName, O_RDONLY | O_RAW)) == -1) {
fprintf (stderr, "%s: can't open temp file\n", ProgName);
exit (1);
}
while (n = read (fd, buff, 1024)) {
if (write (1, buff, n) == -1) {
fprintf (stderr, "%s: write error (1)\n", ProgName);
exit (1);
}
}
}
Done()
{
/*
signal(SIGQUIT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGINT, SIG_IGN);
*/
if( TempName ) unlink( TempName );
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 )
{
Rs(buffer);
if( bp )
NewFunction();
if( 1+LineNumber > PageEnd ) NewPage();
if(!Braces && LooksLikeFunction(buffer))
AddToTableOfContents();
bp = PutLine(buffer);
LineNumber++;
}
}
PutLine(l)
register char *l;
{
extern char *EndComment();
extern char *EndString();
char *expand(), *rindex();
char *substr1();
register char c;
int bp;
char *save;
char *section, *p;
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;
/* if (*(l+1) == ';') ++l;
else bp = 1;
* this is so no blank lines after structers */
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 > PageWidth) {
section = substr1(save, 0, PageWidth - Size);
if (section[strlen(section) - 1] != ' ')
if (NULL == (p = rindex(section, ' ')))
offset = strlen(section);
else
offset = p - section;
else
offset = strlen(section) - 1;
section[offset] = NULL;
if (NumLines) {
fprintf (TempFile, "[%d] %s\n", Number++, section);
}
else {
fprintf (TempFile, "%s\n", section);
}
pos = offset + 1;
do {
section = substr1(save, pos, pos + PageWidth - 8);
if (strlen(save) - pos + 8 > PageWidth)
if (section[strlen(section) - 1] != ' ')
if (NULL == (p = rindex(section, ' ')))
offset = strlen(section);
else
offset = p - section;
else
offset = strlen (section) - 1;
else offset = strlen(section);
section[offset] = NULL;
/* if (section[strlen(section) - 1] == '\n')
section[strlen(section) - 1] = NULL; */
fprintf (TempFile, "C %s\n", section);
if (++LineNumber > PageEnd)
NewPage();
} while ((pos += offset + 1) < strlen(save));
}
else {
if (NumLines)
fprintf (TempFile, "[%d] %s\n", Number++, save);
else
fprintf (TempFile, "%s\n", 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 ) putc ('\n', TempFile);
LineNumber += PageLength/7;
}
else
NewPage();
}
}
#define HEADER_SIZE 3
NewPage()
{
if( LineNumber > HEADER_SIZE )
{
if( PageNumber >= 0 ) ++PageNumber;
BreakPage();
LineNumber = 0;
}
if( LineNumber == 0 )
PutHeader();
}
BreakPage()
{
putc (BP, TempFile);
}
PutHeader()
{
register int i, l, j;
putc ('\n', TempFile);
l = strlen(Name);
for( j=0; j < 3; ++j )
{
fprintf (TempFile, "%s", Name);
if( j < 2 )
/* for( i=0; i < l; ++i ) putc ('\b', TempFile); */
putc('\r', TempFile);
}
if( PageNumber > 0 )
{
for( i = (l+7)/8; i < 9; ++i ) putc ('\t', TempFile);
fprintf (TempFile, "Page: %d\n\n", PageNumber);
}
else
{
for( i = (l+7)/8; i < 6; ++i ) putc ('\t', TempFile);
fprintf (TempFile, "%s\n\n", Todayv);
}
LineNumber += HEADER_SIZE;
}
#define isidchr(c) (isalnum(c) || (c == '_'))
#define isiechr(c) (isidchr(c) || c==' ' || c=='*' || c=='\t' || c=='\n')
LooksLikeFunction(s)
register char *s;
{
register char *p;
char *save;
int Cnt, nosl,nolp,norp,flg;
char Digits[15];
int AddOne = 0;
if( InComment || InString ) return(0);
p = FunctionName;
save = s;
nosl = nolp = norp = 0;
flg = 1;
for (; *s && flg ; s++) {
switch (*s) {
case '(':
if (!nolp) nolp = 1;
else return(0);
break;
case ')':
if (nolp && !norp) norp = 1;
else return(0);
break;
default:
if (!nolp) {
if (isiechr(*s)) {
if (isidchr(*s)) *p++ = *s;
else p = FunctionName;
break;
}
else return(0);
}
if (!norp) {
if (isiechr(*s) || *s == ',') break;
else return(0);
}
if (Cmemb(*s," \t\n\r") && !nosl) break;
if (*s == '/' && !nosl) {
nosl = 1;
break;
}
if (*s == '*' && nosl) {
flg = 0;
break;
}
return(0);
}
}
if (nolp != 1) return(0);
*p = '\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) putc (' ', TempFile);
AddOne = 0;
}
while (*save && *save != '(') putc (*save++, TempFile);
putc ('\r', TempFile);
return(1);
}
char *Toc[TOC_LEN];
int TocPages[TOC_LEN];
int TocCount;
AddToTableOfContents()
{
register int l;
register char *p;
char *malloc();
if (TocCount >= TOC_LEN) {
fprintf (stderr, "%s: too many table of contents entries\n", ProgName);
exit (1);
}
l = strlen(FunctionName);
p = Toc[TocCount] = malloc(l+1);
strcpy(p, FunctionName);
TocPages[TocCount] = PageNumber;
++TocCount;
}
NewFile()
{
register int i, l;
char temp[20];
if (TocCount >= TOC_LEN) {
fprintf (stderr, "%s: too many table of contents entries\n", ProgName);
exit (1);
}
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;
if (WantSorted)
SortTableOfContents();
Name = "Table of Contents";
PageNumber = -1;
LineNumber = 0;
TempFile = stdout;
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);
fflush (stdout);
}
SortTableOfContents()
{
register int i,
tempint;
char *tempchar;
int flag;
do {
flag = 0;
for (i = 0; i < TocCount - 1; i++) {
if (Toc[i][0] == '\n' || Toc[i+1][0] == '\n')
continue; /* don't sort across file names */
if (strcmp (Toc[i], Toc[i+1]) > 0) {
tempchar = Toc[i];
Toc[i] = Toc[i+1];
Toc[i+1] = tempchar;
tempint = TocPages[i];
TocPages[i] = TocPages[i+1];
TocPages[i+1] = tempint;
flag = 1;
}
}
} while (flag);
}
/*
* This is the function substr1(). The calling sequence is:
*
* substr1(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 = substr1(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 *
substr1(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);
}
/*
* 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') {
retstr[count] = ' ';
/* while (((count + 1) % 8) != 0) */
while (TabDef[count] != 'T')
retstr[++count] = ' ';
}
else
retstr[count] = *string;
}
retstr[count] = NULL;
return(retstr);
}
char *Rs(s) /* strip trailing blanks from string */
char s[];
{
int n;
for (n=strlen(s)-1 ; n>=0 && isspace(s[n]) ; n--);
s[n+1] = '\0';
return(s);
}
int Cmemb(a,b) /* is character "a" a member of string "b" */
char a, *b;
{
while (*b)
if (a == *b++) return(1);
if (!a) return(1);
else return(0);
}