Browse Source

Plan 9 from Bell Labs 2003-09-07

David du Colombier 20 years ago
parent
commit
c5944c72b7
7 changed files with 1248 additions and 0 deletions
  1. 7 0
      dist/replica/plan9.db
  2. 7 0
      dist/replica/plan9.log
  3. 998 0
      sys/src/cmd/cb/cb.c
  4. 171 0
      sys/src/cmd/cb/cb.h
  5. 21 0
      sys/src/cmd/cb/cbtype.c
  6. 26 0
      sys/src/cmd/cb/cbtype.h
  7. 18 0
      sys/src/cmd/cb/mkfile

+ 7 - 0
dist/replica/plan9.db

@@ -171,6 +171,7 @@
 386/bin/cal - 775 sys sys 1056364226 66698
 386/bin/calendar - 775 sys sys 1056364227 78213
 386/bin/cat - 775 sys sys 1039758550 37944
+386/bin/cb - 775 sys sys 1062860430 75704
 386/bin/cdfs - 775 sys sys 1056364228 163188
 386/bin/cfs - 775 sys sys 1056364229 129790
 386/bin/chgrp - 775 sys sys 1056364229 58515
@@ -6928,6 +6929,12 @@ sys/src/cmd/bzip2/mkfile - 664 sys sys 969510789 881
 sys/src/cmd/cal.c - 664 sys sys 944961619 4206
 sys/src/cmd/calendar.c - 664 sys sys 1034213625 3571
 sys/src/cmd/cat.c - 664 sys sys 1014926693 532
+sys/src/cmd/cb - 20000000775 sys sys 1062860425 0
+sys/src/cmd/cb/cb.c - 664 sys sys 1062860425 17924
+sys/src/cmd/cb/cb.h - 664 sys sys 1062860425 3382
+sys/src/cmd/cb/cbtype.c - 664 sys sys 1062860425 674
+sys/src/cmd/cb/cbtype.h - 664 sys sys 1062860425 794
+sys/src/cmd/cb/mkfile - 664 sys sys 1062860425 172
 sys/src/cmd/cc - 20000000775 sys sys 1018556175 0
 sys/src/cmd/cc/acid.c - 664 sys sys 944960808 5314
 sys/src/cmd/cc/bits.c - 664 sys sys 944960873 850

+ 7 - 0
dist/replica/plan9.log

@@ -13128,3 +13128,10 @@
 1062721914 2 c sys/src/9/port/systab.h - 664 sys sys 1062721698 3044
 1062761471 0 c 386/bin/ramfs - 775 sys sys 1062759946 90119
 1062761471 1 c sys/src/cmd/ramfs.c - 664 sys sys 1062759940 15377
+1062860489 0 a 386/bin/cb - 775 sys sys 1062860430 75704
+1062860489 1 a sys/src/cmd/cb - 20000000775 sys sys 1062860425 0
+1062860489 2 a sys/src/cmd/cb/cb.c - 664 sys sys 1062860425 17924
+1062860489 3 a sys/src/cmd/cb/cb.h - 664 sys sys 1062860425 3382
+1062860489 4 a sys/src/cmd/cb/cbtype.c - 664 sys sys 1062860425 674
+1062860489 5 a sys/src/cmd/cb/cbtype.h - 664 sys sys 1062860425 794
+1062860489 6 a sys/src/cmd/cb/mkfile - 664 sys sys 1062860425 172

+ 998 - 0
sys/src/cmd/cb/cb.c

@@ -0,0 +1,998 @@
+#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()) != '*'){
+				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(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);
+}
+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");
+}

+ 171 - 0
sys/src/cmd/cb/cb.h

@@ -0,0 +1,171 @@
+#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 *);

+ 21 - 0
sys/src/cmd/cb/cbtype.c

@@ -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
+};

+ 26 - 0
sys/src/cmd/cb/cbtype.h

@@ -0,0 +1,26 @@
+#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 */
+
+#define isop(c)	((_cbtype_+1)[c]&_O)
+#define	isalpha(c)	((_cbtype_+1)[c]&(_U|_L))
+#define	isupper(c)	((_cbtype_+1)[c]&_U)
+#define	islower(c)	((_cbtype_+1)[c]&_L)
+#define	isdigit(c)	((_cbtype_+1)[c]&_N)
+#define	isxdigit(c)	((_cbtype_+1)[c]&(_N|_X))
+#define	isspace(c)	((_cbtype_+1)[c]&_S)
+#define ispunct(c)	((_cbtype_+1)[c]&_P)
+#define isalnum(c)	((_cbtype_+1)[c]&(_U|_L|_N))
+#define isprint(c)	((_cbtype_+1)[c]&(_P|_U|_L|_N))
+#define iscntrl(c)	((_cbtype_+1)[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)

+ 18 - 0
sys/src/cmd/cb/mkfile

@@ -0,0 +1,18 @@
+</$objtype/mkfile
+
+TARG=cb
+OFILES=\
+	cb.$O\
+	cbtype.$O\
+
+HFILES=cb.h\
+	cbtype.h\
+
+BIN=/$objtype/bin
+
+UPDATE=\
+	mkfile\
+	$HFILES\
+	${OFILES:%.$O=%.c}\
+
+< /sys/src/cmd/mkone