ref: 6b6b9a236d773c704daaf7f7b5b090111e28ac87
dir: /sys/src/cmd/cb/cb.c/
#include <u.h> #include <libc.h> #include <bio.h> #include "cb.h" #include "cbtype.h" static void usage(void) { fprint(2, "usage: cb [-sj] [-l width]\n"); exits("usage"); } void main(int argc, char *argv[]) { Biobuf stdin, stdout; ARGBEGIN{ case 'j': join = 1; break; case 'l': maxleng = atoi(EARGF(usage())); maxtabs = maxleng/TABLENG - 2; maxleng -= (maxleng + 5)/10; break; case 's': strict = 1; break; default: usage(); }ARGEND Binit(&stdout, 1, OWRITE); output = &stdout; if (argc <= 0){ Binit(&stdin, 0, OREAD); input = &stdin; work(); Bterm(input); } else { while (argc-- > 0){ if ((input = Bopen(*argv, OREAD)) == 0) sysfatal("can't open input file %s: %r", *argv); work(); Bterm(input); argv++; } } exits(0); } void work(void) { int c, cc; struct keyw *lptr; char *pt; 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 ((cc = getch()) == ':') { putch(c,NO); putch(cc,NO); continue; } unget(cc); 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(( *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, "\t"); } } *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(*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(*lastplace)||ispunct(*lastplace)||isop(*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"); }