home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_200
/
208_01
/
cb.c
< prev
next >
Wrap
Text File
|
1987-10-13
|
10KB
|
468 lines
/*
NAME
cb - C program beautifier
SYNOPSIS
cb
DESCRIPTION
`cb' places a copy of the C program from the standard input
on the standard output with spacing and indentation that displays
the structure of the program.
BUG
almost ignorant of the C syntax.
AUTHOR
William C. Colley, III swiped from the CIPG's UNIX system
and modified to run under BDS C around July 1980.
restored to Portable C by Yoshimasa Tsuji on 18 June 1987
DIAGNOSTICS
there used to be none.
the pairing of braces, parentheses, quotes and comments is checked.
when a closing curly brace is found at column 1, the pairing
balance must be zero. otherwise a warning message is printed on
the standard error file.
nested comments will invoke an error message.
preprocessor directive('#') must be at column 1.
funny characters are detected.
warning messages will not be issued too often because "include" files
or preprocessor conditionals can contain unpaired parentheses etc.
BUG FIX
EOF within comments used to be caught in an endless loop.
preprocessor statements were not allowed to continue to the next line.
many other bugs of the old version have been killed.
RESTRICTION
trouble may be caused if the input file ends with a '\\','\n',EOF
sequence.
not fit for non-C format (e.g. "#define begin {" ).
*/
#include <stdio.h>
#include <ctype.h>
typedef int bool;
#define MAXCURL 20 /* {} may nest this deep */
#define MAXLEVL (MAXCURL/2) /* `if' etc may nest this deep */
#define MAXLEN 200 /*line buffer length*/
#define MAXWARN 4 /*not more than MAXWARN will be printed*/
int clevel; /* curly brace count */
int spflg[MAXCURL][MAXLEVL];
int sind[MAXCURL][MAXLEVL];
int iflev; /* `if' nesting depth */
int ifflg = -1;
int level;
int ind[MAXLEVL];
int paren; /* parenthesis count */
int pflg[MAXLEVL];
int pchar;
bool aflg; /*flag to print a few more spaces after tabbing*/
int stabs[MAXCURL][MAXLEVL];
char string[MAXLEN];
char *cptr= string;
bool sflg = 1; /* print the beginning part of a line */
int peek; /* I like 0 better than EOF */
int tabs; /* indent count */
int lineno = 1;
int column;
int errcount;
main() {
static int slevel[MAXLEVL] = { 0 };
static int siflev[MAXLEVL] = { 0 };
static int sifflg[MAXLEVL] = { 0 };
int lchar;
register bool qflg = 0;
static char *wif[] = { "if",0 };
static char *welse[] = { "else",0 };
static char *wfor[] = { "for", 0 };
static char *wds[] = { "case","default",0 };
register int c, cc;
static char unmatched[] = "%d: unmatched () before %s\n";
while((c = getchr()) != EOF){
switch(c){
case '\\':
case '@':
case '$':
fprintf(stderr,"%d: illegal char %c\n",lineno, c);
default:
*cptr++ = c;
if(c != ',')lchar = c;
continue;
case ' ':
case '\t':
if(lookup(welse) == 1){
gotelse();
if(sflg == 0 || cptr > string) *cptr++ = c;
putst();
sflg = 0;
continue;
}
if(sflg == 0 || cptr > string) *cptr++ = c;
continue;
case '\n':
{
register bool eflg;
if((eflg = lookup(welse)) == 1)
gotelse();
putst();
putchar('\n');
sflg++;
if(eflg == 1){
pflg[level]++;
tabs++;
}
else if(pchar == lchar)
aflg++;
continue;
}
case '{':
if(paren!= 0 && ++errcount <= MAXWARN)
fprintf(stderr,unmatched,lineno,"{"),
paren=0;
if(lookup(welse) == 1)gotelse();
siflev[clevel] = iflev;
sifflg[clevel] = ifflg;
iflev = ifflg = 0;
if( ++clevel > MAXCURL)
fprintf(stderr,"%d: {} nested too deeply\n",lineno),
exit(1);
if(sflg != 0 && pflg[level] != 0){
pflg[level]--;
tabs--;
}
*cptr++ = c;
putst();
getnl();
putst();
putchar('\n');
tabs++;
sflg++;
if(pflg[level] > 0){
ind[level] = 1;
if(++level > MAXLEVL)
fprintf(stderr,"%d: nesting too deep\n",lineno),
exit(1);
slevel[level] = clevel;
}
continue;
case '}':
if(paren != 0 && ++errcount <= MAXWARN)
fprintf(stderr,unmatched,lineno,"}"),
paren=0;/*recover*/
if(--clevel < 0 && ++errcount <= MAXWARN)
fprintf(stderr,"%d: too many }\n",lineno);
if(column == 1 && clevel != 0 && ++errcount <= MAXWARN)
fprintf(stderr,"%d: unmatched {}\n",lineno);
if((iflev = siflev[clevel]-1) < 0)iflev = 0;
ifflg = sifflg[clevel];
putst();
ptabs(--tabs);
putchar(c);
if((peek = getchr()) == ';'){
putchar(';');
peek = 0;
}
getnl();
putst();
putchar('\n');
sflg++;
if(clevel < slevel[level] && level > 0)
level--;
if(ind[level] != 0){
tabs -= pflg[level];
ind[level] = pflg[level] = 0;
}
continue;
case '"':
case '\'':
*cptr++ = c;
while((cc = getchr()) != c){
*cptr++ = cc;
if(cc == '\\')
*cptr++ = getchr();
if(cc == '\n'){
fprintf(stderr,
"%d: %c crossed line\n",lineno,c);
putst();
sflg++;break;/*bug tolerant*/
}
}
*cptr++ = cc;
if(getnl() == 1){
lchar = cc;
peek = '\n';
}
continue;
case ';':
*cptr++ = c;
putst();
if(pflg[level] > 0 && ind[level] == 0){
tabs -= pflg[level];
pflg[level] = 0;
}
getnl();
putst();
putchar('\n');
sflg++;
if(iflev > 0)
if(ifflg == 1){
iflev--;
ifflg = 0;
}
else iflev = 0;
continue;
case '?':
qflg = 1;
*cptr++ = c;
continue;
case ':':
*cptr++ = c;
/* "A? B:C */
if(qflg == 1){
qflg = 0;
continue;
}
/* bit field or label*/
if(paren != 0 && ++errcount <= MAXWARN)
fprintf(stderr,unmatched,lineno,":"),
paren = 0;
if(lookup(wds) == 0){
sflg = 0;
putst();
}
else{
tabs--;
putst();
tabs++;
}
if((peek = getchr()) == ';'){
putchar(';');
peek = 0;
}
getnl();
putst();
putchar('\n');
sflg++;
continue;
case '/':
if(pchar == '*' && ++errcount <= MAXWARN)
fprintf(stderr,"%d: nested comments\n",
lineno);
*cptr++ = c;
if((peek = getchr()) != '*')continue;
*cptr++ = peek;
peek = 0;
comment();
continue;
case ')':
paren--;
*cptr++ = c;
putst();
if(getnl() == 1){
peek = '\n';
if(paren != 0)aflg++;
else if(tabs > 0){
pflg[level]++;
tabs++;
ind[level] = 0;
}
}
continue;
case '#':
if(column != 1)
fprintf(stderr,"%d: '#' at illegal column\n",lineno);
*cptr++ = c;
while((c = getchr()) != '\n') {
/* the last character before EOF
* is always a newline and it is not preceded
* by an escape character.
*/
*cptr++ = c;
if(c == '\\')
*cptr++ = getchr();
}
*cptr++ = c;
sflg = 0;
putst();
sflg++;
continue;
case '(':
*cptr++ = c;
paren++;
if(lookup(wfor) == 1){
register int ct;
while((c = getst()) != ';');
for(ct=0;;) {
if ((c = getst()) == ')'){
if(ct==0)break;
ct--;
continue;
}
if(c == '(') ct++;
}
paren--;
putst();
if(getnl() == 1){
peek = '\n';
pflg[level]++;
tabs++;
ind[level] = 0;
}
continue;
}
if(lookup(wif) == 1){
putst();
stabs[clevel][iflev] = tabs;
spflg[clevel][iflev] = pflg[level];
sind[clevel][iflev] = ind[level];
iflev++;
ifflg = 1;
}
}
}
if(clevel != 0 && ++errcount <= MAXWARN)
fprintf(stderr,"unmatched {} at end\n");
exit(errcount ==0 ? 0 :1);
}
ptabs(tabbs)
register int tabbs;
{
while(--tabbs >= 0)putchar('\t');
}
getchr() {
static int lastchar = 0;
register int c;
if (peek == 0) {
if(lastchar != ' ' && lastchar != '\t')
pchar = lastchar;
if((c = getchar()) == '\n')lineno++,column = 0;
else if(c != '\t' && (c < 040 || c >= 0177) && c != EOF)
fprintf(stderr,"%d: funny character '\\%03o'\n",lineno, c);
else column++;
} else {
c = peek; peek = 0;
}
return(lastchar = c);
}
putst() {
if(cptr > string){
if(sflg != 0){
ptabs(tabs);
sflg = 0;
if(aflg != 0){
aflg = 0;
if(tabs > 0)printf(" ");
}
}
*cptr = '\0';
if(cptr > string + MAXLEN)
fprintf(stderr,"%d: line too long\n",lineno),
exit(1);
printf("%s",string);
cptr = string;
}
else if(sflg != 0)
aflg= sflg = 0;
}
bool
lookup(tab)
register char **tab;
{
register char r;
register char *strptr, *sptr, *tptr;
if(cptr <= string)return(0);
sptr = string -1;
while(*++sptr == ' ' || *sptr == '\t');
while(tptr = *tab++) {
strptr=sptr -1; /*dont optimise*/
while((r = *tptr++) == *++strptr && r != '\0');
if(r == '\0' && !isalnum(*strptr) && *strptr != '_')
return(1);
}
return(0);
}
/*getst returns the first normal character after a parenthesis */
getst(){
register int ch, cc;
for(;;) {
*cptr++ = ch = getchr();
if(ch == '\'' || ch == '"'){
while((*cptr++ = cc= getchr()) != ch)
if(cc == '\\') {
*cptr++ = getchr();
putst(); /*trim*/
}
else if(cc== '\n') {
fprintf(stderr,
"%d: %c crossed line\n",lineno,ch);
break; /*bug tolerant*/
}
continue;
}
if(ch == '\n') {
putst();
aflg++;
continue;
}
return(ch);
}
}
gotelse()
{
tabs = stabs[clevel][iflev];
pflg[level] = spflg[clevel][iflev];
ind[level] = sind[clevel][iflev];
ifflg = 1;
}
getnl()
{
while((peek = getchr()) == '\t' || peek == ' '){
*cptr++ = peek;
peek = 0;
}
if((peek = getchr()) == '/'){
peek = 0;
*cptr++ = '/';
if((peek = getchr()) == '*'){
*cptr++ = '*';
peek = 0;
comment();
}
}
if((peek = getchr()) == '\n'){
peek = 0;
return(1);
}
return(0);
}
comment()
{
register int c;
register int line;
line= lineno;
for(;;) {
if((*cptr++ = c = getchr()) != '*') {
if(c == '\n') putst(), sflg++;
else if(c== EOF) {
fprintf(stderr,"%d: unmatched comment\n",line);
exit(1);
}
continue;
}
while ((*cptr++ = c = getchr()) == '*')
;
if(c == '/')break;
}
}