tAdd. - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit ad9e684811638b69d3800b011ee5fafb448992a3
 (DIR) parent 8307dc614ae985f3dc7f4d2feb4235ee805c6e66
 (HTM) Author: rsc <devnull@localhost>
       Date:   Fri, 12 Aug 2005 20:14:32 +0000
       
       Add.
       
       Diffstat:
         A src/cmd/cb/cb.c                     |    1035 +++++++++++++++++++++++++++++++
         A src/cmd/cb/cb.h                     |     172 ++++++++++++++++++++++++++++++
         A src/cmd/cb/cbtype.c                 |      21 +++++++++++++++++++++
         A src/cmd/cb/cbtype.h                 |      42 +++++++++++++++++++++++++++++++
         A src/cmd/cb/mkfile                   |      11 +++++++++++
       
       5 files changed, 1281 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/cb/cb.c b/src/cmd/cb/cb.c
       t@@ -0,0 +1,1035 @@
       +#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;
       +        char 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(( *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(*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");
       +}
 (DIR) diff --git a/src/cmd/cb/cb.h b/src/cmd/cb/cb.h
       t@@ -0,0 +1,172 @@
       +#define        IF        1
       +#define        ELSE        2
       +#define        CASE        3
       +#define TYPE        4
       +#define DO        5
       +#define STRUCT        6
       +#define OTHER        7
       +
       +#define ALWAYS        01
       +#define        NEVER        02
       +#define        SOMETIMES        04
       +
       +#define YES        1
       +#define NO        0
       +
       +#define        KEYWORD        1
       +#define        DATADEF        2
       +#define        SINIT        3
       +
       +#define CLEVEL        200
       +#define IFLEVEL        100
       +#define DOLEVEL        100
       +#define OPLENGTH        100
       +#define LINE        2048
       +#define LINELENG        2048
       +#define MAXTABS        8
       +#define TABLENG        8
       +#define TEMP        20480
       +
       +#define OUT        outs(clev->tabs); Bputc(output, '\n');opflag = lbegin = 1; count = 0
       +#define OUTK        OUT; keyflag = 0;
       +#define BUMP        clev->tabs++; clev->pdepth++
       +#define UNBUMP        clev->tabs -= clev->pdepth; clev->pdepth = 0
       +#define eatspace()        while((cc=getch()) == ' ' || cc == '\t'); unget(cc)
       +#define eatallsp()        while((cc=getch()) == ' ' || cc == '\t' || cc == '\n'); unget(cc)
       +
       +struct indent {                /* one for each level of { } */
       +        int tabs;
       +        int pdepth;
       +        int iflev;
       +        int ifc[IFLEVEL];
       +        int spdepth[IFLEVEL];
       +} ind[CLEVEL];
       +struct indent *clev = ind;
       +struct keyw {
       +        char        *name;
       +        char        punc;
       +        char        type;
       +} key[] = {
       +        "switch", ' ', OTHER,
       +        "do", ' ', DO,
       +        "while", ' ', OTHER,
       +        "if", ' ', IF,
       +        "for", ' ', OTHER,
       +        "else", ' ', ELSE,
       +        "case", ' ', CASE,
       +        "default", ' ', CASE,
       +        "char", '\t', TYPE,
       +        "int", '\t', TYPE,
       +        "short", '\t', TYPE,
       +        "long", '\t', TYPE,
       +        "unsigned", '\t', TYPE,
       +        "float", '\t', TYPE,
       +        "double", '\t', TYPE,
       +        "struct", ' ', STRUCT,
       +        "union", ' ', STRUCT,
       +        "enum", ' ', STRUCT,
       +        "extern", ' ', TYPE,
       +        "register", ' ', TYPE,
       +        "static", ' ', TYPE,
       +        "typedef", ' ', TYPE,
       +        0, 0, 0
       +};
       +struct op {
       +        char        *name;
       +        char        blanks;
       +        char        setop;
       +} op[] = {
       +        "+=",         ALWAYS,  YES,
       +        "-=",         ALWAYS,  YES,
       +        "*=",         ALWAYS,  YES,
       +        "/=",         ALWAYS,  YES,
       +        "%=",         ALWAYS,  YES,
       +        ">>=",         ALWAYS,  YES,
       +        "<<=",         ALWAYS,  YES,
       +        "&=",         ALWAYS,  YES,
       +        "^=",         ALWAYS,  YES,
       +        "|=",         ALWAYS,  YES,
       +        ">>",         ALWAYS,  YES,
       +        "<<",         ALWAYS,  YES,
       +        "<=",         ALWAYS,  YES,
       +        ">=",         ALWAYS,  YES,
       +        "==",         ALWAYS,  YES,
       +        "!=",         ALWAYS,  YES,
       +        "=",         ALWAYS,  YES,
       +        "&&",         ALWAYS, YES,
       +        "||",         ALWAYS, YES,
       +        "++",         NEVER, NO,
       +        "--",         NEVER, NO,
       +        "->",         NEVER, NO,
       +        "<",         ALWAYS, YES,
       +        ">",         ALWAYS, YES,
       +        "+",         ALWAYS, YES,
       +        "/",         ALWAYS, YES,
       +        "%",         ALWAYS, YES,
       +        "^",         ALWAYS, YES,
       +        "|",         ALWAYS, YES,
       +        "!",         NEVER, YES,
       +        "~",         NEVER, YES,
       +        "*",         SOMETIMES, YES,
       +        "&",         SOMETIMES, YES,
       +        "-",         SOMETIMES, YES,
       +        "?",        ALWAYS,YES,
       +        ":",        ALWAYS,YES,
       +        0,         0,0
       +};
       +Biobuf *input;
       +Biobuf *output;
       +int        strict = 0;
       +int        join        = 0;
       +int        opflag = 1;
       +int        keyflag = 0;
       +int        paren         = 0;
       +int        split         = 0;
       +int        folded        = 0;
       +int        dolevel        =0;
       +int        dotabs[DOLEVEL];
       +int        docurly[DOLEVEL];
       +int        dopdepth[DOLEVEL];
       +int        structlev = 0;
       +int        question         = 0;
       +char        string[LINE];
       +char        *lastlook;
       +char        *p = string;
       +char temp[TEMP];
       +char *tp;
       +int err = 0;
       +char *lastplace = temp;
       +char *tptr = temp;
       +int maxleng        = LINELENG;
       +int maxtabs        = MAXTABS;
       +int count        = 0;
       +char next = '\0';
       +int        inswitch        =0;
       +int        lbegin         = 1;
       +int lineno        = 0;
       +
       +void work(void);
       +void gotif(void);
       +void gotelse(void);
       +int checkif(char *);
       +void gotdo(void);
       +void resetdo(void);
       +void gottype(struct keyw *lptr);
       +void gotstruct(void);
       +void gotop(int);
       +void keep(struct op *);
       +int getnl(void);
       +void ptabs(int);
       +void outs(int);
       +void putch(char, int);
       +struct keyw *lookup(char *, char *);
       +int comment(int);
       +void putspace(char, int);
       +int getch(void);
       +void unget(char);
       +char *getnext(int);
       +void copy(char *);
       +void clearif(struct indent *);
       +char puttmp(char, int);
       +void error(char *);
       +int cpp_comment(int);
 (DIR) diff --git a/src/cmd/cb/cbtype.c b/src/cmd/cb/cbtype.c
       t@@ -0,0 +1,21 @@
       +#include        "cbtype.h"
       +
       +unsigned char _cbtype_[] = {
       +        0,
       +        _C,        _C,        _C,        _C,        _C,        _C,        _C,        _C,
       +        _C,        _C|_S,        _C|_S,        _C|_S,        _C|_S,        _C|_S,        _C,        _C,
       +        _C,        _C,        _C,        _C,        _C,        _C,        _C,        _C,
       +        _C,        _C,        _C,        _C,        _C,        _C,        _C,        _C,
       +        _S,        _P|_O,        _P,        _P,        _P,        _P|_O,        _P|_O,        _P,
       +        _P,        _P,        _P|_O,        _P|_O,        _P,        _P|_O,        _P,        _P|_O,
       +        _N,        _N,        _N,        _N,        _N,        _N,        _N,        _N,
       +        _N,        _N,        _P,        _P,        _P|_O,        _P|_O,        _P|_O,        _P,
       +        _P,        _U|_X,        _U|_X,        _U|_X,        _U|_X,        _U|_X,        _U|_X,        _U,
       +        _U,        _U,        _U,        _U,        _U,        _U,        _U,        _U,
       +        _U,        _U,        _U,        _U,        _U,        _U,        _U,        _U,
       +        _U,        _U,        _U,        _P,        _P,        _P,        _P|_O,        _P|_L,
       +        _P,        _L|_X,        _L|_X,        _L|_X,        _L|_X,        _L|_X,        _L|_X,        _L,
       +        _L,        _L,        _L,        _L,        _L,        _L,        _L,        _L,
       +        _L,        _L,        _L,        _L,        _L,        _L,        _L,        _L,
       +        _L,        _L,        _L,        _P,        _P|_O,        _P,        _P,        _C
       +};
 (DIR) diff --git a/src/cmd/cb/cbtype.h b/src/cmd/cb/cbtype.h
       t@@ -0,0 +1,42 @@
       +#define        _U        01
       +#define        _L        02
       +#define        _N        04
       +#define        _S        010
       +#define _P        020
       +#define _C        040
       +#define        _X        0100
       +#define _O        0200
       +
       +extern        unsigned char        _cbtype_[];        /* in /usr/src/libc/gen/ctype_.c */
       +
       +#undef isop
       +#undef        isalpha
       +#undef        isupper
       +#undef        islower
       +#undef        isdigit
       +#undef        isxdigit
       +#undef        isspace
       +#undef ispunct
       +#undef isalnum
       +#undef isprint
       +#undef iscntrl
       +#undef isascii
       +#undef toupper
       +#undef tolower
       +#undef toascii
       +
       +#define isop(c)        ((_cbtype_+1)[(uchar)(c)]&_O)
       +#define        isalpha(c)        ((_cbtype_+1)[(uchar)(c)]&(_U|_L))
       +#define        isupper(c)        ((_cbtype_+1)[(uchar)(c)]&_U)
       +#define        islower(c)        ((_cbtype_+1)[(uchar)(c)]&_L)
       +#define        isdigit(c)        ((_cbtype_+1)[(uchar)(c)]&_N)
       +#define        isxdigit(c)        ((_cbtype_+1)[(uchar)(c)]&(_N|_X))
       +#define        isspace(c)        ((_cbtype_+1)[(uchar)(c)]&_S)
       +#define ispunct(c)        ((_cbtype_+1)[(uchar)(c)]&_P)
       +#define isalnum(c)        ((_cbtype_+1)[(uchar)(c)]&(_U|_L|_N))
       +#define isprint(c)        ((_cbtype_+1)[(uchar)(c)]&(_P|_U|_L|_N))
       +#define iscntrl(c)        ((_cbtype_+1)[(uchar)(c)]&_C)
       +#define isascii(c)        ((unsigned)(c)<=0177)
       +#define toupper(c)        ((c)-'a'+'A')
       +#define tolower(c)        ((c)-'A'+'a')
       +#define toascii(c)        ((c)&0177)
 (DIR) diff --git a/src/cmd/cb/mkfile b/src/cmd/cb/mkfile
       t@@ -0,0 +1,11 @@
       +<$PLAN9/src/mkhdr
       +
       +TARG=cb
       +OFILES=\
       +        cb.$O\
       +        cbtype.$O\
       +
       +HFILES=cb.h\
       +        cbtype.h\
       +
       +<$PLAN9/src/mkone