home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Guide
/
c-cplusplus-interactive-guide.iso
/
c_ref
/
csource4
/
233_01
/
cprint.c
< prev
next >
Wrap
Text File
|
1987-07-01
|
7KB
|
222 lines
/*
CPRINT, Print a (fairly) neat listing of a c program
Programmed by Andrew L. Bender, M. D.
June 24, 1984 - Version 1.0
June 26, 1984 - Version 1.1
Fix some bugs in string processing
July 3, 1984 - Version 1.2
Allow for printer file device.
Count source statements
Permission is hereby given to freely distribute this
program but it may not be sold. This program may be
modified by anyone as long as this notice remains.
The purpose of this program was to test the CI86
optimizing c compiler. It does a clean compilation
of this program which tests most features of the
c language as described by Kernighan and Ritchie in
their book "The C Programming Language."
CI-86 is a trademark of Computer Innovations,
Tinton Falls NJ for their implementation of the full
c programming language as described in Kernighan and
Ritchie.
The listing contains two columns on the left:
column 1 is the "nesting level" of compound
statements and column 2 is a rough idea of
what the line number will be. It is actually
a count of "\n" characters. The heading on
each page gives the name of the file being
printed and the date and time it was created.
If braces, brackets or parenthesis are unbalanced
this will be reported at the end of the listing.
A complete syntactical analysis of the program
would require more effort but would be worth it as
an exercise of much value in learning the c language
because of the facility and fluency needed to write
such a checker.
A program checker "lint" is quite through in its
analysis of c programs and is available on most
UNIX systems.
*/
#include "local.h"
#define LPP 58
#define TAB 3
#define CHPL 74
/* LPP=lines per page
TAB = number of spaces to indent for a tab
CHPL = characters to print on each line (74 is very tight)
because the line and level count take up 8 columns
*/
unsigned int hour,minute,second,month,day,year;
int pagect, level, tabct, lines, stmnt, linect;
typedef int void;
typedef int boolean;
struct regval { int ax, bx, cx, dx, si, di, ds, es; };
struct regval callreg, retreg;
unsigned char title[60];
boolean comment, quote, squote, instrng;
unsigned char lineimage[520];
unsigned char fmt[]=
{"\fListing of file: %s Catalogued on %d/%d/%d At %d:%02d:%02d\
Page %d \n\n"};
unsigned char output[60]={"PRN:"};
/* top of page routine */
void toppage(pr)
FILE *pr;
{
fprintf(pr,fmt,title,month,day,year,hour,minute,second,pagect);
linect=1;
pagect++;
}
/* main program */
main(argc,argv)
int argc;
unsigned char *argv[];
{
int i,j,kk,jj,n;
unsigned char buf[600], fname [254];
unsigned char k;
int *pb;
int lbrace, rbrace, lparen, rparen, lbrack, rbrack;
extern FILE *fopen();
extern FILE *fclose();
extern char *fgets();
FILE *prn, *fd;
fprintf(stderr,"C Program Listing Version 1.2\n");
if (argc<2)
{
fprintf(stderr,"Type In Filename To Print: ");
gets(buf,254,stdin); /*get user file name if not on control card*/
pb=index(buf,'\n');
*pb='\0';
}
else strcpy(buf,argv[1]); /*copy control stmnt string to user bfr*/
makefnam(buf,".c",fname); /*convert file name to filename.c*/
fprintf(stderr,"Listing Of File: %s \n",fname);
if (argc==3) strcpy(output,argv[2]); /*copy prt file name to output*/
prn=fopen(output,"w"); /*open printer*/
if(prn==NULL) {
fprintf(stderr,"Assignment of print device: %s failed.",output);
exit(1);
}
fd=fopen(fname,"r"); /*open program file to list*/
if (fd==NULL) {
fprintf(stderr,"Cannot Open File: %s \n",fname);
exit(1); /*error exit*/
}
linect = pagect = 1; /*set page & line count to one*/
stmnt = j = rbrack = lbrack = rbrace = lbrace = rparen = lparen = 0;
callreg.bx =*fd; /*get file handle*/
callreg.ax = 0x5700 ; /*get file data */
sysint21(&callreg,&retreg); /*fetch file date and time*/
/* n.b. -> ci86 c documentation is a bit confusing here.
the structure is naturally a memory area so it conflicts
in that sense with the register lo-hi multiplexing */
month=(retreg.dx & 0x01E0)>>5;
day=retreg.dx & 0x001F;
year=((retreg.dx >>9)& 0x00EF)+80;
hour=(retreg.cx >>11) & 0x001F;
minute=(retreg.cx & 0x07E0)>>5;
second=(retreg.cx & 0x001F)<<1; /* multiply by 2 */
strcpy(title,fname);
comment=squote=instrng=quote=FALSE;
toppage(prn); /*take top of page action*/
while(fgets(lineimage,519,fd)!=NULL){
jj=strlen(lineimage);
for(i=0;k=lineimage[i],k!='\0'&& i<jj;i++){
kk=k;
if (kk=='\n')
{
lines++;
}
if (comment==FALSE && instrng==FALSE) {
/* switch is entered when processing outside a comment
or string. If in a comment or string (either " or ') then
the if statement drops thru to the else at the
conclusion of the loop to turn processing back on
In the case of alphanumerics the loop is totally ignored.
*/
if (isalnum(k)==0){ /* don't switch on alphanumerics */
switch (kk) {
case '{':
level++;
lbrace++;
break;
case '}':
rbrace++;
level--;
break;
case '(':
lparen++;
break;
case ')':
rparen++;
break;
case '[':
lbrack++;
break;
case ']':
rbrack++;
break;
case '/':
comment= lineimage[i+1]=='*';
break;
case ';':
stmnt++;
break;
case '\'':
quote=!squote;
instrng=quote|squote;
break;
case '"':
squote= !quote;
instrng= squote|quote;
break;
}
}
}
else { /*if comment or instrng == TRUE*/
if (comment==TRUE && k=='*' && lineimage[i+1]=='/')
comment=FALSE;
if (quote==TRUE && k=='\'' &&
(lineimage[i-1] != '\\' ||
(lineimage[i-2]=='\\' && lineimage[i-1]=='\\')))
quote=FALSE;
if (squote==TRUE && k=='"') squote=FALSE;
instrng = quote | squote;
}
if (k=='\t') for(n=j;buf[j++]=' ',j<n+TAB;);
else buf[j++]=k;
if (j>CHPL || k == '\n'){
if (k != '\n')
buf[j++]='\n';
buf[j]='\0';
fprintf(prn,"%2d%4d: %s",level,lines,buf);
j=0;
if (linect++>LPP) toppage(prn);
}
}
}
fclose(fd);
if (level==0 && rbrack==lbrack && rparen==lparen)
{
fprintf(prn,"\n%d Statements in source code. \
Braces, brackets and parenthesis are balanced.\n",stmnt);
}
else
{
fprintf(prn,"\nUnbalanced pairs { %d, } %d, [ %d, ] %d, ( %d, ) %d\n",
lbrace,rbrace,lbrack,rbrack,lparen,rparen);
fclose(prn);
}
}