blob: 0b2458965d54aae9186f44a406c58dd85d85eaaa [file] [log] [blame]
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "cb.h"
#include "cbtype.h"
void
main(int argc, char *argv[])
{
Biobuf stdin, stdout;
while (--argc > 0 && (*++argv)[0] == '-'){
switch ((*argv)[1]){
case 's':
strict = 1;
continue;
case 'j':
join = 1;
continue;
case 'l':
if((*argv)[2] != '\0'){
maxleng = atoi( &((*argv)[2]) );
}
else{
maxleng = atoi(*++argv);
argc--;
}
maxtabs = maxleng/TABLENG - 2;
maxleng -= (maxleng + 5)/10;
continue;
default:
fprint(2, "cb: illegal option %c\n", *argv[1]);
exits("boom");
}
}
Binit(&stdout, 1, OWRITE);
output = &stdout;
if (argc <= 0){
Binit(&stdin, 0, OREAD);
input = &stdin;
work();
} else {
while (argc-- > 0){
if ((input = Bopen( *argv, OREAD)) == 0){
fprint(2, "cb: cannot open input file %s\n", *argv);
exits("boom");
}
work();
argv++;
}
}
exits(0);
}
void
work(void){
int c;
struct keyw *lptr;
char *pt;
int cc;
int ct;
while ((c = getch()) != Beof){
switch (c){
case '{':
if ((lptr = lookup(lastlook,p)) != 0){
if (lptr->type == ELSE)gotelse();
else if(lptr->type == DO)gotdo();
else if(lptr->type == STRUCT)structlev++;
}
if(++clev >= &ind[CLEVEL-1]){
fprint(2,"too many levels of curly brackets\n");
clev = &ind[CLEVEL-1];
}
clev->pdepth = 0;
clev->tabs = (clev-1)->tabs;
clearif(clev);
if(strict && clev->tabs > 0)
putspace(' ',NO);
putch(c,NO);
getnl();
if(keyflag == DATADEF){
OUT;
}
else {
OUTK;
}
clev->tabs++;
pt = getnext(0); /* to handle initialized structures */
if(*pt == '{'){ /* hide one level of {} */
while((c=getch()) != '{')
if(c == Beof)error("{");
putch(c,NO);
if(strict){
putch(' ',NO);
eatspace();
}
keyflag = SINIT;
}
continue;
case '}':
pt = getnext(0); /* to handle initialized structures */
if(*pt == ','){
if(strict){
putspace(' ',NO);
eatspace();
}
putch(c,NO);
putch(*pt,NO);
*pt = '\0';
ct = getnl();
pt = getnext(0);
if(*pt == '{'){
OUT;
while((cc = getch()) != '{')
if(cc == Beof)error("}");
putch(cc,NO);
if(strict){
putch(' ',NO);
eatspace();
}
getnext(0);
continue;
}
else if(strict || ct){
OUT;
}
continue;
}
else if(keyflag == SINIT && *pt == '}'){
if(strict)
putspace(' ',NO);
putch(c,NO);
getnl();
OUT;
keyflag = DATADEF;
*pt = '\0';
pt = getnext(0);
}
outs(clev->tabs);
if(--clev < ind)clev = ind;
ptabs(clev->tabs);
putch(c,NO);
lbegin = 0;
lptr=lookup(pt,lastplace+1);
c = *pt;
if(*pt == ';' || *pt == ','){
putch(*pt,NO);
*pt = '\0';
lastplace=pt;
}
ct = getnl();
if((dolevel && clev->tabs <= dotabs[dolevel]) || (structlev )
|| (lptr != 0 &&lptr->type == ELSE&& clev->pdepth == 0)){
if(c == ';'){
OUTK;
}
else if(strict || (lptr != 0 && lptr->type == ELSE && ct == 0)){
putspace(' ',NO);
eatspace();
}
else if(lptr != 0 && lptr->type == ELSE){
OUTK;
}
if(structlev){
structlev--;
keyflag = DATADEF;
}
}
else {
OUTK;
if(strict && clev->tabs == 0){
if((c=getch()) != '\n'){
Bputc(output, '\n');
Bputc(output, '\n');
unget(c);
}
else {
lineno++;
Bputc(output, '\n');
if((c=getch()) != '\n')unget(c);
else lineno++;
Bputc(output, '\n');
}
}
}
if(lptr != 0 && lptr->type == ELSE && clev->pdepth != 0){
UNBUMP;
}
if(lptr == 0 || lptr->type != ELSE){
clev->iflev = 0;
if(dolevel && docurly[dolevel] == NO && clev->tabs == dotabs[dolevel]+1)
clev->tabs--;
else if(clev->pdepth != 0){
UNBUMP;
}
}
continue;
case '(':
paren++;
if ((lptr = lookup(lastlook,p)) != 0){
if(!(lptr->type == TYPE || lptr->type == STRUCT))keyflag=KEYWORD;
if (strict){
putspace(lptr->punc,NO);
opflag = 1;
}
putch(c,NO);
if (lptr->type == IF)gotif();
}
else {
putch(c,NO);
lastlook = p;
opflag = 1;
}
continue;
case ')':
if(--paren < 0)paren = 0;
putch(c,NO);
if((lptr = lookup(lastlook,p)) != 0){
if(lptr->type == TYPE || lptr->type == STRUCT)
opflag = 1;
}
else if(keyflag == DATADEF)opflag = 1;
else opflag = 0;
outs(clev->tabs);
pt = getnext(1);
if ((ct = getnl()) == 1 && !strict){
if(dolevel && clev->tabs <= dotabs[dolevel])
resetdo();
if(clev->tabs > 0 && (paren != 0 || keyflag == 0)){
if(join){
eatspace();
putch(' ',YES);
continue;
} else {
OUT;
split = 1;
continue;
}
}
else if(clev->tabs > 0 && *pt != '{'){
BUMP;
}
OUTK;
}
else if(strict){
if(clev->tabs == 0){
if(*pt != ';' && *pt != ',' && *pt != '(' && *pt != '['){
OUTK;
}
}
else {
if(keyflag == KEYWORD && paren == 0){
if(dolevel && clev->tabs <= dotabs[dolevel]){
resetdo();
eatspace();
continue;
}
if(*pt != '{'){
BUMP;
OUTK;
}
else {
*pt='\0';
eatspace();
unget('{');
}
}
else if(ct){
if(paren){
if(join){
eatspace();
} else {
split = 1;
OUT;
}
}
else {
OUTK;
}
}
}
}
else if(dolevel && clev->tabs <= dotabs[dolevel])
resetdo();
continue;
case ' ':
case '\t':
if ((lptr = lookup(lastlook,p)) != 0){
if(!(lptr->type==TYPE||lptr->type==STRUCT))
keyflag = KEYWORD;
else if(paren == 0)keyflag = DATADEF;
if(strict){
if(lptr->type != ELSE){
if(lptr->type == TYPE){
if(paren != 0)putch(' ',YES);
}
else
putch(lptr->punc,NO);
eatspace();
}
}
else putch(c,YES);
switch(lptr->type){
case CASE:
outs(clev->tabs-1);
continue;
case ELSE:
pt = getnext(1);
eatspace();
if((cc = getch()) == '\n' && !strict){
unget(cc);
}
else {
unget(cc);
if(checkif(pt))continue;
}
gotelse();
if(strict) unget(c);
if(getnl() == 1 && !strict){
OUTK;
if(*pt != '{'){
BUMP;
}
}
else if(strict){
if(*pt != '{'){
OUTK;
BUMP;
}
}
continue;
case IF:
gotif();
continue;
case DO:
gotdo();
pt = getnext(1);
if(*pt != '{'){
eatallsp();
OUTK;
docurly[dolevel] = NO;
dopdepth[dolevel] = clev->pdepth;
clev->pdepth = 0;
clev->tabs++;
}
continue;
case TYPE:
if(paren)continue;
if(!strict)continue;
gottype(lptr);
continue;
case STRUCT:
gotstruct();
continue;
}
}
else if (lbegin == 0 || p > string)
if(strict)
putch(c,NO);
else putch(c,YES);
continue;
case ';':
putch(c,NO);
if(paren != 0){
if(strict){
putch(' ',YES);
eatspace();
}
opflag = 1;
continue;
}
outs(clev->tabs);
pt = getnext(0);
lptr=lookup(pt,lastplace+1);
if(lptr == 0 || lptr->type != ELSE){
clev->iflev = 0;
if(clev->pdepth != 0){
UNBUMP;
}
if(dolevel && docurly[dolevel] == NO && clev->tabs <= dotabs[dolevel]+1)
clev->tabs--;
/*
else if(clev->pdepth != 0){
UNBUMP;
}
*/
}
getnl();
OUTK;
continue;
case '\n':
if ((lptr = lookup(lastlook,p)) != 0){
pt = getnext(1);
if (lptr->type == ELSE){
if(strict)
if(checkif(pt))continue;
gotelse();
OUTK;
if(*pt != '{'){
BUMP;
}
}
else if(lptr->type == DO){
OUTK;
gotdo();
if(*pt != '{'){
docurly[dolevel] = NO;
dopdepth[dolevel] = clev->pdepth;
clev->pdepth = 0;
clev->tabs++;
}
}
else {
OUTK;
if(lptr->type == STRUCT)gotstruct();
}
}
else if(p == string)Bputc(output, '\n');
else {
if(clev->tabs > 0 &&(paren != 0 || keyflag == 0)){
if(join){
putch(' ',YES);
eatspace();
continue;
} else {
OUT;
split = 1;
continue;
}
}
else if(keyflag == KEYWORD){
OUTK;
continue;
}
OUT;
}
continue;
case '"':
case '\'':
putch(c,NO);
while ((cc = getch()) != c){
if(cc == Beof)
error("\" or '");
putch(cc,NO);
if (cc == '\\'){
putch(getch(),NO);
}
if (cc == '\n'){
outs(clev->tabs);
lbegin = 1;
count = 0;
}
}
putch(cc,NO);
opflag=0;
if (getnl() == 1){
unget('\n');
}
continue;
case '\\':
putch(c,NO);
putch(getch(),NO);
continue;
case '?':
question = 1;
gotop(c);
continue;
case ':':
if (question == 1){
question = 0;
gotop(c);
continue;
}
putch(c,NO);
if(structlev)continue;
if ((lptr = lookup(lastlook,p)) != 0){
if (lptr->type == CASE)outs(clev->tabs - 1);
}
else {
lbegin = 0;
outs(clev->tabs);
}
getnl();
OUTK;
continue;
case '/':
if ((cc = getch()) == '/') {
putch(c,NO);
putch(cc,NO);
cpp_comment(YES);
OUT;
lastlook = 0;
continue;
}
else if (cc != '*') {
unget(cc);
gotop(c);
continue;
}
putch(c,NO);
putch(cc,NO);
cc = comment(YES);
if(getnl() == 1){
if(cc == 0){
OUT;
}
else {
outs(0);
Bputc(output, '\n');
lbegin = 1;
count = 0;
}
lastlook = 0;
}
continue;
case '[':
putch(c,NO);
ct = 0;
while((c = getch()) != ']' || ct > 0){
if(c == Beof)error("]");
putch(c,NO);
if(c == '[')ct++;
if(c == ']')ct--;
}
putch(c,NO);
continue;
case '#':
putch(c,NO);
while ((cc = getch()) != '\n'){
if(cc == Beof)error("newline");
if (cc == '\\'){
putch(cc,NO);
cc = getch();
}
putch(cc,NO);
}
putch(cc,NO);
lbegin = 0;
outs(clev->tabs);
lbegin = 1;
count = 0;
continue;
default:
if (c == ','){
opflag = 1;
putch(c,YES);
if (strict){
if ((cc = getch()) != ' ')unget(cc);
if(cc != '\n')putch(' ',YES);
}
}
else if(isop(c))gotop(c);
else {
if(isalnum(c) && lastlook == 0)lastlook = p;
if(isdigit(c)){
putch(c,NO);
while(isdigit(c=Bgetc(input))||c == '.')putch(c,NO);
if(c == 'e'){
putch(c,NO);
c = Bgetc(input);
putch(c, NO);
while(isdigit(c=Bgetc(input)))putch(c,NO);
}
Bungetc(input);
}
else putch(c,NO);
if(keyflag != DATADEF)opflag = 0;
}
}
}
}
void
gotif(void){
outs(clev->tabs);
if(++clev->iflev >= IFLEVEL-1){
fprint(2,"too many levels of if %d\n",clev->iflev );
clev->iflev = IFLEVEL-1;
}
clev->ifc[clev->iflev] = clev->tabs;
clev->spdepth[clev->iflev] = clev->pdepth;
}
void
gotelse(void){
clev->tabs = clev->ifc[clev->iflev];
clev->pdepth = clev->spdepth[clev->iflev];
if(--(clev->iflev) < 0)clev->iflev = 0;
}
int
checkif(char *pt)
{
struct keyw *lptr;
int cc;
if((lptr=lookup(pt,lastplace+1))!= 0){
if(lptr->type == IF){
if(strict)putch(' ',YES);
copy(lptr->name);
*pt='\0';
lastplace = pt;
if(strict){
putch(lptr->punc,NO);
eatallsp();
}
clev->tabs = clev->ifc[clev->iflev];
clev->pdepth = clev->spdepth[clev->iflev];
keyflag = KEYWORD;
return(1);
}
}
return(0);
}
void
gotdo(void){
if(++dolevel >= DOLEVEL-1){
fprint(2,"too many levels of do %d\n",dolevel);
dolevel = DOLEVEL-1;
}
dotabs[dolevel] = clev->tabs;
docurly[dolevel] = YES;
}
void
resetdo(void){
if(docurly[dolevel] == NO)
clev->pdepth = dopdepth[dolevel];
if(--dolevel < 0)dolevel = 0;
}
void
gottype(struct keyw *lptr)
{
char *pt;
struct keyw *tlptr;
int c;
while(1){
pt = getnext(1);
if((tlptr=lookup(pt,lastplace+1))!=0){
putch(' ',YES);
copy(tlptr->name);
*pt='\0';
lastplace = pt;
if(tlptr->type == STRUCT){
putch(tlptr->punc,YES);
gotstruct();
break;
}
lptr=tlptr;
continue;
}
else{
putch(lptr->punc,NO);
while((c=getch())== ' ' || c == '\t');
unget(c);
break;
}
}
}
void
gotstruct(void){
int c;
int cc;
char *pt;
while((c=getch()) == ' ' || c == '\t')
if(!strict)putch(c,NO);
if(c == '{'){
structlev++;
unget(c);
return;
}
if(isalpha(c)){
putch(c,NO);
while(isalnum(c=getch()))putch(c,NO);
}
unget(c);
pt = getnext(1);
if(*pt == '{')structlev++;
if(strict){
eatallsp();
putch(' ',NO);
}
}
void
gotop(int c)
{
char optmp[OPLENGTH];
char *op_ptr;
struct op *s_op;
char *a, *b;
op_ptr = optmp;
*op_ptr++ = c;
while (isop((uchar)( *op_ptr = getch())))op_ptr++;
if(!strict)unget(*op_ptr);
else if (*op_ptr != ' ')unget( *op_ptr);
*op_ptr = '\0';
s_op = op;
b = optmp;
while ((a = s_op->name) != 0){
op_ptr = b;
while ((*op_ptr == *a) && (*op_ptr != '\0')){
a++;
op_ptr++;
}
if (*a == '\0'){
keep(s_op);
opflag = s_op->setop;
if (*op_ptr != '\0'){
b = op_ptr;
s_op = op;
continue;
}
else break;
}
else s_op++;
}
}
void
keep(struct op *o)
{
char *s;
int ok;
if(o->blanks == NEVER)ok = NO;
else ok = YES;
if (strict && ((o->blanks & ALWAYS)
|| ((opflag == 0 && o->blanks & SOMETIMES) && clev->tabs != 0)))
putspace(' ',YES);
for(s=o->name; *s != '\0'; s++){
if(*(s+1) == '\0')putch(*s,ok);
else
putch(*s,NO);
}
if (strict && ((o->blanks & ALWAYS)
|| ((opflag == 0 && o->blanks & SOMETIMES) && clev->tabs != 0))) putch(' ',YES);
}
int
getnl(void){
int ch;
char *savp;
int gotcmt;
gotcmt = 0;
savp = p;
while ((ch = getch()) == '\t' || ch == ' ')putch(ch,NO);
if (ch == '/'){
if ((ch = getch()) == '*'){
putch('/',NO);
putch('*',NO);
comment(NO);
ch = getch();
gotcmt=1;
}
else if (ch == '/') {
putch('/',NO);
putch('/',NO);
cpp_comment(NO);
ch = getch();
gotcmt = 1;
}
else {
if(inswitch)*(++lastplace) = ch;
else {
inswitch = 1;
*lastplace = ch;
}
unget('/');
return(0);
}
}
if(ch == '\n'){
if(gotcmt == 0)p=savp;
return(1);
}
unget(ch);
return(0);
}
void
ptabs(int n){
int i;
int num;
if(n > maxtabs){
if(!folded){
Bprint(output, "/* code folded from here */\n");
folded = 1;
}
num = n-maxtabs;
}
else {
num = n;
if(folded){
folded = 0;
Bprint(output, "/* unfolding */\n");
}
}
for (i = 0; i < num; i++)Bputc(output, '\t');
}
void
outs(int n){
if (p > string){
if (lbegin){
ptabs(n);
lbegin = 0;
if (split == 1){
split = 0;
if (clev->tabs > 0)Bprint(output, " ");
}
}
*p = '\0';
Bprint(output, "%s", string);
lastlook = p = string;
}
else {
if (lbegin != 0){
lbegin = 0;
split = 0;
}
}
}
void
putch(char c,int ok)
{
int cc;
if(p < &string[LINE-1]){
if(count+TABLENG*clev->tabs >= maxleng && ok && !folded){
if(c != ' ')*p++ = c;
OUT;
split = 1;
if((cc=getch()) != '\n')unget(cc);
}
else {
*p++ = c;
count++;
}
}
else {
outs(clev->tabs);
*p++ = c;
count = 0;
}
}
struct keyw *
lookup(char *first, char *last)
{
struct keyw *ptr;
char *cptr, *ckey, *k;
if(first == last || first == 0)return(0);
cptr = first;
while (*cptr == ' ' || *cptr == '\t')cptr++;
if(cptr >= last)return(0);
ptr = key;
while ((ckey = ptr->name) != 0){
for (k = cptr; (*ckey == *k && *ckey != '\0'); k++, ckey++);
if(*ckey=='\0' && (k==last|| (k<last && !isalnum((uchar)*k)))){
opflag = 1;
lastlook = 0;
return(ptr);
}
ptr++;
}
return(0);
}
int
comment(int ok)
{
int ch;
int hitnl;
hitnl = 0;
while ((ch = getch()) != Beof){
putch(ch, NO);
if (ch == '*'){
gotstar:
if ((ch = getch()) == '/'){
putch(ch,NO);
return(hitnl);
}
putch(ch,NO);
if (ch == '*')goto gotstar;
}
if (ch == '\n'){
if(ok && !hitnl){
outs(clev->tabs);
}
else {
outs(0);
}
lbegin = 1;
count = 0;
hitnl = 1;
}
}
return(hitnl);
}
int
cpp_comment(int ok)
{
int ch;
int hitnl;
hitnl = 0;
while ((ch = getch()) != -1) {
if (ch == '\n') {
if (ok && !hitnl)
outs(clev->tabs);
else
outs(0);
lbegin = 1;
count = 0;
hitnl = 1;
break;
}
putch(ch, NO);
}
return hitnl;
}
void
putspace(char ch, int ok)
{
if(p == string)putch(ch,ok);
else if (*(p - 1) != ch) putch(ch,ok);
}
int
getch(void){
char c;
if(inswitch){
if(next != '\0'){
c=next;
next = '\0';
return(c);
}
if(tptr <= lastplace){
if(*tptr != '\0')return(*tptr++);
else if(++tptr <= lastplace)return(*tptr++);
}
inswitch=0;
lastplace = tptr = temp;
}
return(Bgetc(input));
}
void
unget(char c)
{
if(inswitch){
if(tptr != temp)
*(--tptr) = c;
else next = c;
}
else Bungetc(input);
}
char *
getnext(int must){
int c;
char *beg;
int prect,nlct;
prect = nlct = 0;
if(tptr > lastplace){
tptr = lastplace = temp;
err = 0;
inswitch = 0;
}
tp = lastplace;
if(inswitch && tptr <= lastplace)
if (isalnum((uchar)*lastplace)||ispunct((uchar)*lastplace)||isop((uchar)*lastplace))return(lastplace);
space:
while(isspace(c=Bgetc(input)))puttmp(c,1);
beg = tp;
puttmp(c,1);
if(c == '/'){
if(puttmp(Bgetc(input),1) == '*'){
cont:
while((c=Bgetc(input)) != '*'){
puttmp(c,0);
if(must == 0 && c == '\n')
if(nlct++ > 2)goto done;
}
puttmp(c,1);
star:
if(puttmp((c=Bgetc(input)),1) == '/'){
beg = tp;
puttmp((c=Bgetc(input)),1);
}
else if(c == '*')goto star;
else goto cont;
}
else goto done;
}
if(isspace(c))goto space;
if(c == '#' && tp > temp+1 && *(tp-2) == '\n'){
if(prect++ > 2)goto done;
while(puttmp((c=Bgetc(input)),1) != '\n')
if(c == '\\')puttmp(Bgetc(input),1);
goto space;
}
if(isalnum(c)){
while(isalnum(c = Bgetc(input)))puttmp(c,1);
Bungetc(input);
}
done:
puttmp('\0',1);
lastplace = tp-1;
inswitch = 1;
return(beg);
}
void
copy(char *s)
{
while(*s != '\0')putch(*s++,NO);
}
void
clearif(struct indent *cl)
{
int i;
for(i=0;i<IFLEVEL-1;i++)cl->ifc[i] = 0;
}
char
puttmp(char c, int keep)
{
if(tp < &temp[TEMP-120])
*tp++ = c;
else {
if(keep){
if(tp >= &temp[TEMP-1]){
fprint(2,"can't look past huge comment - quiting\n");
exits("boom");
}
*tp++ = c;
}
else if(err == 0){
err++;
fprint(2,"truncating long comment\n");
}
}
return(c);
}
void
error(char *s)
{
fprint(2,"saw EOF while looking for %s\n",s);
exits("boom");
}