shithub: riscv

ref: bf645afaac246967b9590ae7463f243c11d97480
dir: /sys/src/cmd/dc.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>

typedef	void*	pointer;
#pragma	varargck	type	"lx"	pointer

#define FATAL 0
#define NFATAL 1
#define BLK sizeof(Blk)
#define PTRSZ sizeof(int*)
#define TBLSZ 256			/* 1<<BI2BY */

#define HEADSZ 1024
#define STKSZ 100
#define RDSKSZ 100
#define ARRAYST 221
#define MAXIND 2048

#define NL 1
#define NG 2
#define NE 3

#define length(p)	((p)->wt-(p)->beg)
#define rewind(p)	(p)->rd=(p)->beg
#define create(p)	(p)->rd = (p)->wt = (p)->beg
#define fsfile(p)	(p)->rd = (p)->wt
#define truncate(p)	(p)->wt = (p)->rd
#define sfeof(p)	(((p)->rd==(p)->wt)?1:0)
#define sfbeg(p)	(((p)->rd==(p)->beg)?1:0)
#define sungetc(p,c)	*(--(p)->rd)=c
#define sgetc(p)	(((p)->rd==(p)->wt)?-1:*(p)->rd++)
#define skipc(p)	{if((p)->rd<(p)->wt)(p)->rd++;}
#define slookc(p)	(((p)->rd==(p)->wt)?-1:*(p)->rd)
#define sbackc(p)	(((p)->rd==(p)->beg)?-1:*(--(p)->rd))
#define backc(p)	{if((p)->rd>(p)->beg) --(p)->rd;}
#define sputc(p,c)	{if((p)->wt==(p)->last)more(p);\
				*(p)->wt++ = c; }
#define salterc(p,c)	{if((p)->rd==(p)->last)more(p);\
				*(p)->rd++ = c;\
				if((p)->rd>(p)->wt)(p)->wt=(p)->rd;}
#define sunputc(p)	(*((p)->rd = --(p)->wt))
#define sclobber(p)	((p)->rd = --(p)->wt)
#define zero(p)		for(pp=(p)->beg;pp<(p)->last;)\
				*pp++='\0'
#define OUTC(x)		{Bputc(&bout,x); if(--count == 0){Bprint(&bout,"\\\n"); count=ll;} }
#define TEST2		{if((count -= 2) <=0){Bprint(&bout,"\\\n");count=ll;}}
#define EMPTY		if(stkerr != 0){Bprint(&bout,"stack empty\n"); continue; }
#define EMPTYR(x)	if(stkerr!=0){pushp(x);Bprint(&bout,"stack empty\n");continue;}
#define EMPTYS		if(stkerr != 0){Bprint(&bout,"stack empty\n"); return(1);}
#define EMPTYSR(x)	if(stkerr !=0){Bprint(&bout,"stack empty\n");pushp(x);return(1);}
#define error(p)	{Bprint(&bout,p); continue; }
#define errorrt(p)	{Bprint(&bout,p); return(1); }

#define LASTFUN 026

typedef	struct	Blk	Blk;
struct	Blk
{
	char	*rd;
	char	*wt;
	char	*beg;
	char	*last;
};
typedef	struct	Sym	Sym;
struct	Sym
{
	Sym	*next;
	Blk	*val;
};
typedef	struct	Wblk	Wblk;
struct	Wblk
{
	Blk	**rdw;
	Blk	**wtw;
	Blk	**begw;
	Blk	**lastw;
};

Biobuf	*curfile, *fsave;
Blk	*arg1, *arg2;
uchar	savk;
int	dbg;
int	ifile;
Blk	*scalptr, *basptr, *tenptr, *inbas;
Blk	*sqtemp, *chptr, *strptr, *divxyz;
Blk	*stack[STKSZ];
Blk	**stkptr,**stkbeg;
Blk	**stkend;
Blk	*hfree;
int	stkerr;
int	lastchar;
Blk	*readstk[RDSKSZ];
Blk	**readptr;
Blk	*rem;
int	k;
Blk	*irem;
int	skd,skr;
int	neg;
Sym	symlst[TBLSZ];
Sym	*stable[TBLSZ];
Sym	*sptr, *sfree;
long	rel;
long	nbytes;
long	all;
long	headmor;
long	obase;
int	fw,fw1,ll;
void	(*outdit)(Blk *p, int flg);
int	logo;
int	logten;
int	count;
char	*pp;
char	*dummy;
long	longest, maxsize, active;
int	lall, lrel, lcopy, lmore, lbytes;
int	inside;
Biobuf	bin;
Biobuf	bout;

void	main(int argc, char *argv[]);
void	commnds(void);
Blk*	readin(void);
Blk*	div(Blk *ddivd, Blk *ddivr);
int	dscale(void);
Blk*	removr(Blk *p, int n);
Blk*	dcsqrt(Blk *p);
void	init(int argc, char *argv[]);
void	onintr(void);
void	pushp(Blk *p);
Blk*	pop(void);
Blk*	readin(void);
Blk*	add0(Blk *p, int ct);
Blk*	mult(Blk *p, Blk *q);
void	chsign(Blk *p);
int	readc(void);
void	unreadc(char c);
void	binop(char c);
void	dcprint(Blk *hptr);
Blk*	dcexp(Blk *base, Blk *ex);
Blk*	getdec(Blk *p, int sc);
void	tenot(Blk *p, int sc);
void	oneot(Blk *p, int sc, char ch);
void	hexot(Blk *p, int flg);
void	bigot(Blk *p, int flg);
Blk*	add(Blk *a1, Blk *a2);
int	eqk(void);
Blk*	removc(Blk *p, int n);
Blk*	scalint(Blk *p);
Blk*	scale(Blk *p, int n);
int	subt(void);
int	command(void);
int	cond(char c);
void	load(void);
int	log2(long n);
Blk*	salloc(int size);
Blk*	morehd(void);
Blk*	copy(Blk *hptr, int size);
void	sdump(char *s1, Blk *hptr);
void	seekc(Blk *hptr, int n);
void	salterwd(Blk *hptr, Blk *n);
void	more(Blk *hptr);
void	ospace(char *s);
void	garbage(char *s);
void	release(Blk *p);
Blk*	dcgetwd(Blk *p);
void	putwd(Blk *p, Blk *c);
Blk*	lookwd(Blk *p);
int	getstk(void);

/********debug only**/
void
tpr(char *cp, Blk *bp)
{
	print("%s-> ", cp);
	print("beg: %lx rd: %lx wt: %lx last: %lx\n", bp->beg, bp->rd,
		bp->wt, bp->last);
	for (cp = bp->beg; cp != bp->wt; cp++) {
		print("%d", *cp);
		if (cp != bp->wt-1)
			print("/");
	}
	print("\n");
}
/************/

void
main(int argc, char *argv[])
{
	Binit(&bin, 0, OREAD);
	Binit(&bout, 1, OWRITE);
	init(argc,argv);
	commnds();
	exits(0);
}

void
commnds(void)
{
	Blk *p, *q, **ptr, *s, *t;
	long l;
	Sym *sp;
	int sk, sk1, sk2, c, sign, n, d;

	while(1) {
		Bflush(&bout);
		if(((c = readc())>='0' && c <= '9') ||
		    (c>='A' && c <='F') || c == '.') {
			unreadc(c);
			p = readin();
			pushp(p);
			continue;
		}
		switch(c) {
		case ' ':
		case '\t':
		case '\n':
		case -1:
			continue;
		case 'Y':
			sdump("stk",*stkptr);
			Bprint(&bout, "all %ld rel %ld headmor %ld\n",all,rel,headmor);
			Bprint(&bout, "nbytes %ld\n",nbytes);
			Bprint(&bout, "longest %ld active %ld maxsize %ld\n", longest,
				active, maxsize);
			Bprint(&bout, "new all %d rel %d copy %d more %d lbytes %d\n",
				lall, lrel, lcopy, lmore, lbytes);
			lall = lrel = lcopy = lmore = lbytes = 0;
			continue;
		case '_':
			p = readin();
			savk = sunputc(p);
			chsign(p);
			sputc(p,savk);
			pushp(p);
			continue;
		case '-':
			subt();
			continue;
		case '+':
			if(eqk() != 0)
				continue;
			binop('+');
			continue;
		case '*':
			arg1 = pop();
			EMPTY;
			arg2 = pop();
			EMPTYR(arg1);
			sk1 = sunputc(arg1);
			sk2 = sunputc(arg2);
			savk = sk1+sk2;
			binop('*');
			p = pop();
			if(savk>k && savk>sk1 && savk>sk2) {
				sclobber(p);
				sk = sk1;
				if(sk<sk2)
					sk = sk2;
				if(sk<k)
					sk = k;
				p = removc(p,savk-sk);
				savk = sk;
				sputc(p,savk);
			}
			pushp(p);
			continue;
		case '/':
		casediv:
			if(dscale() != 0)
				continue;
			binop('/');
			if(irem != 0)
				release(irem);
			release(rem);
			continue;
		case '%':
			if(dscale() != 0)
				continue;
			binop('/');
			p = pop();
			release(p);
			if(irem == 0) {
				sputc(rem,skr+k);
				pushp(rem);
				continue;
			}
			p = add0(rem,skd-(skr+k));
			q = add(p,irem);
			release(p);
			release(irem);
			sputc(q,skd);
			pushp(q);
			continue;
		case 'v':
			p = pop();
			EMPTY;
			savk = sunputc(p);
			if(length(p) == 0) {
				sputc(p,savk);
				pushp(p);
				continue;
			}
			if(sbackc(p)<0) {
				error("sqrt of neg number\n");
			}
			if(k<savk)
				n = savk;
			else {
				n = k*2-savk;
				savk = k;
			}
			arg1 = add0(p,n);
			arg2 = dcsqrt(arg1);
			sputc(arg2,savk);
			pushp(arg2);
			continue;

		case '^':
			neg = 0;
			arg1 = pop();
			EMPTY;
			if(sunputc(arg1) != 0)
				error("exp not an integer\n");
			arg2 = pop();
			EMPTYR(arg1);
			if(sfbeg(arg1) == 0 && sbackc(arg1)<0) {
				neg++;
				chsign(arg1);
			}
			if(length(arg1)>=5) {
				error("exp too big\n");
			}
			savk = sunputc(arg2);
			p = dcexp(arg2,arg1);
			release(arg2);
			rewind(arg1);
			c = sgetc(arg1);
			if(c == -1)
				c = 0;
			else
			if(sfeof(arg1) == 0)
				c = sgetc(arg1)*100 + c;
			d = c*savk;
			release(arg1);
		/*	if(neg == 0) {		removed to fix -exp bug*/
				if(k>=savk)
					n = k;
				else
					n = savk;
				if(n<d) {
					q = removc(p,d-n);
					sputc(q,n);
					pushp(q);
				} else {
					sputc(p,d);
					pushp(p);
				}
		/*	} else { this is disaster for exp <-127 */
		/*		sputc(p,d);		*/
		/*		pushp(p);		*/
		/*	}				*/
			if(neg == 0)
				continue;
			p = pop();
			q = salloc(2);
			sputc(q,1);
			sputc(q,0);
			pushp(q);
			pushp(p);
			goto casediv;
		case 'z':
			p = salloc(2);
			n = stkptr - stkbeg;
			if(n >= 100) {
				sputc(p,n/100);
				n %= 100;
			}
			sputc(p,n);
			sputc(p,0);
			pushp(p);
			continue;
		case 'Z':
			p = pop();
			EMPTY;
			n = (length(p)-1)<<1;
			fsfile(p);
			backc(p);
			if(sfbeg(p) == 0) {
				if((c = sbackc(p))<0) {
					n -= 2;
					if(sfbeg(p) == 1)
						n++;
					else {
						if((c = sbackc(p)) == 0)
							n++;
						else
						if(c > 90)
							n--;
					}
				} else
				if(c < 10)
					n--;
			}
			release(p);
			q = salloc(1);
			if(n >= 100) {
				sputc(q,n%100);
				n /= 100;
			}
			sputc(q,n);
			sputc(q,0);
			pushp(q);
			continue;
		case 'i':
			p = pop();
			EMPTY;
			p = scalint(p);
			release(inbas);
			inbas = p;
			continue;
		case 'I':
			p = copy(inbas,length(inbas)+1);
			sputc(p,0);
			pushp(p);
			continue;
		case 'o':
			p = pop();
			EMPTY;
			p = scalint(p);
			sign = 0;
			n = length(p);
			q = copy(p,n);
			fsfile(q);
			l = c = sbackc(q);
			if(n != 1) {
				if(c<0) {
					sign = 1;
					chsign(q);
					n = length(q);
					fsfile(q);
					l = c = sbackc(q);
				}
				if(n != 1) {
					while(sfbeg(q) == 0)
						l = l*100+sbackc(q);
				}
			}
			logo = log2(l);
			obase = l;
			release(basptr);
			if(sign == 1)
				obase = -l;
			basptr = p;
			outdit = bigot;
			if(n == 1 && sign == 0) {
				if(c <= 16) {
					outdit = hexot;
					fw = 1;
					fw1 = 0;
					ll = 70;
					release(q);
					continue;
				}
			}
			n = 0;
			if(sign == 1)
				n++;
			p = salloc(1);
			sputc(p,-1);
			t = add(p,q);
			n += length(t)*2;
			fsfile(t);
			if(sbackc(t)>9)
				n++;
			release(t);
			release(q);
			release(p);
			fw = n;
			fw1 = n-1;
			ll = 70;
			if(fw>=ll)
				continue;
			ll = (70/fw)*fw;
			continue;
		case 'O':
			p = copy(basptr,length(basptr)+1);
			sputc(p,0);
			pushp(p);
			continue;
		case '[':
			n = 0;
			p = salloc(0);
			for(;;) {
				if((c = readc()) == ']') {
					if(n == 0)
						break;
					n--;
				}
				sputc(p,c);
				if(c == '[')
					n++;
			}
			pushp(p);
			continue;
		case 'k':
			p = pop();
			EMPTY;
			p = scalint(p);
			if(length(p)>1) {
				error("scale too big\n");
			}
			rewind(p);
			k = 0;
			if(!sfeof(p))
				k = sgetc(p);
			release(scalptr);
			scalptr = p;
			continue;
		case 'K':
			p = copy(scalptr,length(scalptr)+1);
			sputc(p,0);
			pushp(p);
			continue;
		case 'X':
			p = pop();
			EMPTY;
			fsfile(p);
			n = sbackc(p);
			release(p);
			p = salloc(2);
			sputc(p,n);
			sputc(p,0);
			pushp(p);
			continue;
		case 'Q':
			p = pop();
			EMPTY;
			if(length(p)>2) {
				error("Q?\n");
			}
			rewind(p);
			if((c =  sgetc(p))<0) {
				error("neg Q\n");
			}
			release(p);
			while(c-- > 0) {
				if(readptr == &readstk[0]) {
					error("readstk?\n");
				}
				if(*readptr != 0)
					release(*readptr);
				readptr--;
			}
			continue;
		case 'q':
			if(readptr <= &readstk[1])
				exits(0);
			if(*readptr != 0)
				release(*readptr);
			readptr--;
			if(*readptr != 0)
				release(*readptr);
			readptr--;
			continue;
		case 'f':
			if(stkptr == &stack[0])
				Bprint(&bout,"empty stack\n");
			else {
				for(ptr = stkptr; ptr > &stack[0];) {
					dcprint(*ptr--);
				}
			}
			continue;
		case 'p':
			if(stkptr == &stack[0])
				Bprint(&bout,"empty stack\n");
			else {
				dcprint(*stkptr);
			}
			continue;
		case 'P':
			p = pop();
			EMPTY;
			sputc(p,0);
			Bprint(&bout,"%s",p->beg);
			release(p);
			continue;
		case 'd':
			if(stkptr == &stack[0]) {
				Bprint(&bout,"empty stack\n");
				continue;
			}
			q = *stkptr;
			n = length(q);
			p = copy(*stkptr,n);
			pushp(p);
			continue;
		case 'c':
			while(stkerr == 0) {
				p = pop();
				if(stkerr == 0)
					release(p);
			}
			continue;
		case 'S':
			if(stkptr == &stack[0]) {
				error("save: args\n");
			}
			c = getstk() & 0377;
			sptr = stable[c];
			sp = stable[c] = sfree;
			sfree = sfree->next;
			if(sfree == 0)
				goto sempty;
			sp->next = sptr;
			p = pop();
			EMPTY;
			if(c >= ARRAYST) {
				q = copy(p,length(p)+PTRSZ);
				for(n = 0;n < PTRSZ;n++) {
					sputc(q,0);
				}
				release(p);
				p = q;
			}
			sp->val = p;
			continue;
		sempty:
			error("symbol table overflow\n");
		case 's':
			if(stkptr == &stack[0]) {
				error("save:args\n");
			}
			c = getstk() & 0377;
			sptr = stable[c];
			if(sptr != 0) {
				p = sptr->val;
				if(c >= ARRAYST) {
					rewind(p);
					while(sfeof(p) == 0) {
						q = dcgetwd(p);
						if(q != 0)
							release(q);
					}
				}
				release(p);
			} else {
				sptr = stable[c] = sfree;
				sfree = sfree->next;
				if(sfree == 0)
					goto sempty;
				sptr->next = 0;
			}
			p = pop();
			sptr->val = p;
			continue;
		case 'l':
			load();
			continue;
		case 'L':
			c = getstk() & 0377;
			sptr = stable[c];
			if(sptr == 0) {
				error("L?\n");
			}
			stable[c] = sptr->next;
			sptr->next = sfree;
			sfree = sptr;
			p = sptr->val;
			if(c >= ARRAYST) {
				rewind(p);
				while(sfeof(p) == 0) {
					q = dcgetwd(p);
					if(q != 0)
						release(q);
				}
			}
			pushp(p);
			continue;
		case ':':
			p = pop();
			EMPTY;
			q = scalint(p);
			fsfile(q);
			c = 0;
			if((sfbeg(q) == 0) && ((c = sbackc(q))<0)) {
				error("neg index\n");
			}
			if(length(q)>2) {
				error("index too big\n");
			}
			if(sfbeg(q) == 0)
				c = c*100+sbackc(q);
			if(c >= MAXIND) {
				error("index too big\n");
			}
			release(q);
			n = getstk() & 0377;
			sptr = stable[n];
			if(sptr == 0) {
				sptr = stable[n] = sfree;
				sfree = sfree->next;
				if(sfree == 0)
					goto sempty;
				sptr->next = 0;
				p = salloc((c+PTRSZ)*PTRSZ);
				zero(p);
			} else {
				p = sptr->val;
				if(length(p)-PTRSZ < c*PTRSZ) {
					q = copy(p,(c+PTRSZ)*PTRSZ);
					release(p);
					p = q;
				}
			}
			sptr->val = p;
			seekc(p,c*PTRSZ);
			q = lookwd(p);
			if(q!=0)
				release(q);
			s = pop();
			EMPTY;
			salterwd(p, s);
			continue;
		case ';':
			p = pop();
			EMPTY;
			q = scalint(p);
			fsfile(q);
			c = 0;
			if((sfbeg(q) == 0) && ((c = sbackc(q))<0)) {
				error("neg index\n");
			}
			if(length(q)>2) {
				error("index too big\n");
			}
			if(sfbeg(q) == 0)
				c = c*100+sbackc(q);
			if(c >= MAXIND) {
				error("index too big\n");
			}
			release(q);
			n = getstk() & 0377;
			sptr = stable[n];
			if(sptr != 0){
				p = sptr->val;
				if(length(p)-PTRSZ >= c*PTRSZ) {
					seekc(p,c*PTRSZ);
					s = dcgetwd(p);
					if(s != 0) {
						q = copy(s,length(s));
						pushp(q);
						continue;
					}
				}
			}
			q = salloc(1);	/*so uninitialized array elt prints as 0*/
			sputc(q, 0);
			pushp(q);
			continue;
		case 'x':
		execute:
			p = pop();
			EMPTY;
			if((readptr != &readstk[0]) && (*readptr != 0)) {
				if((*readptr)->rd == (*readptr)->wt)
					release(*readptr);
				else {
					if(readptr++ == &readstk[RDSKSZ]) {
						error("nesting depth\n");
					}
				}
			} else
				readptr++;
			*readptr = p;
			if(p != 0)
				rewind(p);
			else {
				if((c = readc()) != '\n')
					unreadc(c);
			}
			continue;
		case '?':
			if(++readptr == &readstk[RDSKSZ]) {
				error("nesting depth\n");
			}
			*readptr = 0;
			fsave = curfile;
			curfile = &bin;
			while((c = readc()) == '!')
				command();
			p = salloc(0);
			sputc(p,c);
			while((c = readc()) != '\n') {
				sputc(p,c);
				if(c == '\\')
					sputc(p,readc());
			}
			curfile = fsave;
			*readptr = p;
			continue;
		case '!':
			if(command() == 1)
				goto execute;
			continue;
		case '<':
		case '>':
		case '=':
			if(cond(c) == 1)
				goto execute;
			continue;
		default:
			Bprint(&bout,"%o is unimplemented\n",c);
		}
	}
}

Blk*
div(Blk *ddivd, Blk *ddivr)
{
	int divsign, remsign, offset, divcarry,
		carry, dig, magic, d, dd, under, first;
	long c, td, cc;
	Blk *ps, *px, *p, *divd, *divr;

	dig = 0;
	under = 0;
	divcarry = 0;
	rem = 0;
	p = salloc(0);
	if(length(ddivr) == 0) {
		pushp(ddivr);
		Bprint(&bout,"divide by 0\n");
		return(p);
	}
	divsign = remsign = first = 0;
	divr = ddivr;
	fsfile(divr);
	if(sbackc(divr) == -1) {
		divr = copy(ddivr,length(ddivr));
		chsign(divr);
		divsign = ~divsign;
	}
	divd = copy(ddivd,length(ddivd));
	fsfile(divd);
	if(sfbeg(divd) == 0 && sbackc(divd) == -1) {
		chsign(divd);
		divsign = ~divsign;
		remsign = ~remsign;
	}
	offset = length(divd) - length(divr);
	if(offset < 0)
		goto ddone;
	seekc(p,offset+1);
	sputc(divd,0);
	magic = 0;
	fsfile(divr);
	c = sbackc(divr);
	if(c < 10)
		magic++;
	c = c * 100 + (sfbeg(divr)?0:sbackc(divr));
	if(magic>0){
		c = (c * 100 +(sfbeg(divr)?0:sbackc(divr)))*2;
		c /= 25;
	}
	while(offset >= 0) {
		first++;
		fsfile(divd);
		td = sbackc(divd) * 100;
		dd = sfbeg(divd)?0:sbackc(divd);
		td = (td + dd) * 100;
		dd = sfbeg(divd)?0:sbackc(divd);
		td = td + dd;
		cc = c;
		if(offset == 0)
			td++;
		else
			cc++;
		if(magic != 0)
			td = td<<3;
		dig = td/cc;
		under=0;
		if(td%cc < 8  && dig > 0 && magic) {
			dig--;
			under=1;
		}
		rewind(divr);
		rewind(divxyz);
		carry = 0;
		while(sfeof(divr) == 0) {
			d = sgetc(divr)*dig+carry;
			carry = d / 100;
			salterc(divxyz,d%100);
		}
		salterc(divxyz,carry);
		rewind(divxyz);
		seekc(divd,offset);
		carry = 0;
		while(sfeof(divd) == 0) {
			d = slookc(divd);
			d = d-(sfeof(divxyz)?0:sgetc(divxyz))-carry;
			carry = 0;
			if(d < 0) {
				d += 100;
				carry = 1;
			}
			salterc(divd,d);
		}
		divcarry = carry;
		backc(p);
		salterc(p,dig);
		backc(p);
		fsfile(divd);
		d=sbackc(divd);
		if((d != 0) && /*!divcarry*/ (offset != 0)) {
			d = sbackc(divd) + 100;
			salterc(divd,d);
		}
		if(--offset >= 0)
			divd->wt--;
	}
	if(under) {	/* undershot last - adjust*/
		px = copy(divr,length(divr));	/*11/88 don't corrupt ddivr*/
		chsign(px);
		ps = add(px,divd);
		fsfile(ps);
		if(length(ps) > 0 && sbackc(ps) < 0) {
			release(ps);	/*only adjust in really undershot*/
		} else {
			release(divd);
			salterc(p, dig+1);
			divd=ps;
		}
	}
	if(divcarry != 0) {
		salterc(p,dig-1);
		salterc(divd,-1);
		ps = add(divr,divd);
		release(divd);
		divd = ps;
	}

	rewind(p);
	divcarry = 0;
	while(sfeof(p) == 0){
		d = slookc(p)+divcarry;
		divcarry = 0;
		if(d >= 100){
			d -= 100;
			divcarry = 1;
		}
		salterc(p,d);
	}
	if(divcarry != 0)salterc(p,divcarry);
	fsfile(p);
	while(sfbeg(p) == 0) {
		if(sbackc(p) != 0)
			break;
		truncate(p);
	}
	if(divsign < 0)
		chsign(p);
	fsfile(divd);
	while(sfbeg(divd) == 0) {
		if(sbackc(divd) != 0)
			break;
		truncate(divd);
	}
ddone:
	if(remsign<0)
		chsign(divd);
	if(divr != ddivr)
		release(divr);
	rem = divd;
	return(p);
}

int
dscale(void)
{
	Blk *dd, *dr, *r;
	int c;

	dr = pop();
	EMPTYS;
	dd = pop();
	EMPTYSR(dr);
	fsfile(dd);
	skd = sunputc(dd);
	fsfile(dr);
	skr = sunputc(dr);
	if(sfbeg(dr) == 1 || (sfbeg(dr) == 0 && sbackc(dr) == 0)) {
		sputc(dr,skr);
		pushp(dr);
		Bprint(&bout,"divide by 0\n");
		return(1);
	}
	if(sfbeg(dd) == 1 || (sfbeg(dd) == 0 && sbackc(dd) == 0)) {
		sputc(dd,skd);
		pushp(dd);
		return(1);
	}
	c = k-skd+skr;
	if(c < 0)
		r = removr(dd,-c);
	else {
		r = add0(dd,c);
		irem = 0;
	}
	arg1 = r;
	arg2 = dr;
	savk = k;
	return(0);
}

Blk*
removr(Blk *p, int n)
{
	int nn, neg;
	Blk *q, *s, *r;

	fsfile(p);
	neg = sbackc(p);
	if(neg < 0)
		chsign(p);
	rewind(p);
	nn = (n+1)/2;
	q = salloc(nn);
	while(n>1) {
		sputc(q,sgetc(p));
		n -= 2;
	}
	r = salloc(2);
	while(sfeof(p) == 0)
		sputc(r,sgetc(p));
	release(p);
	if(n == 1){
		s = div(r,tenptr);
		release(r);
		rewind(rem);
		if(sfeof(rem) == 0)
			sputc(q,sgetc(rem));
		release(rem);
		if(neg < 0){
			chsign(s);
			chsign(q);
			irem = q;
			return(s);
		}
		irem = q;
		return(s);
	}
	if(neg < 0) {
		chsign(r);
		chsign(q);
		irem = q;
		return(r);
	}
	irem = q;
	return(r);
}

Blk*
dcsqrt(Blk *p)
{
	Blk *t, *r, *q, *s;
	int c, n, nn;

	n = length(p);
	fsfile(p);
	c = sbackc(p);
	if((n&1) != 1)
		c = c*100+(sfbeg(p)?0:sbackc(p));
	n = (n+1)>>1;
	r = salloc(n);
	zero(r);
	seekc(r,n);
	nn=1;
	while((c -= nn)>=0)
		nn+=2;
	c=(nn+1)>>1;
	fsfile(r);
	backc(r);
	if(c>=100) {
		c -= 100;
		salterc(r,c);
		sputc(r,1);
	} else
		salterc(r,c);
	for(;;){
		q = div(p,r);
		s = add(q,r);
		release(q);
		release(rem);
		q = div(s,sqtemp);
		release(s);
		release(rem);
		s = copy(r,length(r));
		chsign(s);
		t = add(s,q);
		release(s);
		fsfile(t);
		nn = sfbeg(t)?0:sbackc(t);
		if(nn>=0)
			break;
		release(r);
		release(t);
		r = q;
	}
	release(t);
	release(q);
	release(p);
	return(r);
}

Blk*
dcexp(Blk *base, Blk *ex)
{
	Blk *r, *e, *p, *e1, *t, *cp;
	int temp, c, n;

	r = salloc(1);
	sputc(r,1);
	p = copy(base,length(base));
	e = copy(ex,length(ex));
	fsfile(e);
	if(sfbeg(e) != 0)
		goto edone;
	temp=0;
	c = sbackc(e);
	if(c<0) {
		temp++;
		chsign(e);
	}
	while(length(e) != 0) {
		e1=div(e,sqtemp);
		release(e);
		e = e1;
		n = length(rem);
		release(rem);
		if(n != 0) {
			e1=mult(p,r);
			release(r);
			r = e1;
		}
		t = copy(p,length(p));
		cp = mult(p,t);
		release(p);
		release(t);
		p = cp;
	}
	if(temp != 0) {
		if((c = length(base)) == 0) {
			goto edone;
		}
		if(c>1)
			create(r);
		else {
			rewind(base);
			if((c = sgetc(base))<=1) {
				create(r);
				sputc(r,c);
			} else
				create(r);
		}
	}
edone:
	release(p);
	release(e);
	return(r);
}

void
init(int argc, char *argv[])
{
	Sym *sp;
	Dir *d;

	ARGBEGIN {
	default:
		dbg = 1;
		break;
	} ARGEND
	ifile = 1;
	curfile = &bin;
	if(*argv){
		d = dirstat(*argv);
		if(d == nil) {
			fprint(2, "dc: can't open file %s\n", *argv);
			exits("open");
		}
		if(d->mode & DMDIR) {
			fprint(2, "dc: file %s is a directory\n", *argv);
			exits("open");
		}
		free(d);
		if((curfile = Bopen(*argv, OREAD)) == 0) {
			fprint(2,"dc: can't open file %s\n", *argv);
			exits("open");
		}
	}
/*	dummy = malloc(0);  /* prepare for garbage-collection */
	scalptr = salloc(1);
	sputc(scalptr,0);
	basptr = salloc(1);
	sputc(basptr,10);
	obase=10;
	logten=log2(10L);
	ll=70;
	fw=1;
	fw1=0;
	tenptr = salloc(1);
	sputc(tenptr,10);
	obase=10;
	inbas = salloc(1);
	sputc(inbas,10);
	sqtemp = salloc(1);
	sputc(sqtemp,2);
	chptr = salloc(0);
	strptr = salloc(0);
	divxyz = salloc(0);
	stkbeg = stkptr = &stack[0];
	stkend = &stack[STKSZ-1];
	stkerr = 0;
	readptr = &readstk[0];
	k=0;
	sp = sptr = &symlst[0];
	while(sptr < &symlst[TBLSZ-1]) {
		sptr->next = ++sp;
		sptr++;
	}
	sptr->next=0;
	sfree = &symlst[0];
}

void
pushp(Blk *p)
{
	if(stkptr == stkend) {
		Bprint(&bout,"out of stack space\n");
		return;
	}
	stkerr=0;
	*++stkptr = p;
	return;
}

Blk*
pop(void)
{
	if(stkptr == stack) {
		stkerr=1;
		return(0);
	}
	return(*stkptr--);
}

Blk*
readin(void)
{
	Blk *p, *q;
	int dp, dpct, c;

	dp = dpct=0;
	p = salloc(0);
	for(;;){
		c = readc();
		switch(c) {
		case '.':
			if(dp != 0)
				goto gotnum;
			dp++;
			continue;
		case '\\':
			readc();
			continue;
		default:
			if(c >= 'A' && c <= 'F')
				c = c - 'A' + 10;
			else
			if(c >= '0' && c <= '9')
				c -= '0';
			else
				goto gotnum;
			if(dp != 0) {
				if(dpct >= 99)
					continue;
				dpct++;
			}
			create(chptr);
			if(c != 0)
				sputc(chptr,c);
			q = mult(p,inbas);
			release(p);
			p = add(chptr,q);
			release(q);
		}
	}
gotnum:
	unreadc(c);
	if(dp == 0) {
		sputc(p,0);
		return(p);
	} else {
		q = scale(p,dpct);
		return(q);
	}
}

/*
 * returns pointer to struct with ct 0's & p
 */
Blk*
add0(Blk *p, int ct)
{
	Blk *q, *t;

	q = salloc(length(p)+(ct+1)/2);
	while(ct>1) {
		sputc(q,0);
		ct -= 2;
	}
	rewind(p);
	while(sfeof(p) == 0) {
		sputc(q,sgetc(p));
	}
	release(p);
	if(ct == 1) {
		t = mult(tenptr,q);
		release(q);
		return(t);
	}
	return(q);
}

Blk*
mult(Blk *p, Blk *q)
{
	Blk *mp, *mq, *mr;
	int sign, offset, carry;
	int cq, cp, mt, mcr;

	offset = sign = 0;
	fsfile(p);
	mp = p;
	if(sfbeg(p) == 0) {
		if(sbackc(p)<0) {
			mp = copy(p,length(p));
			chsign(mp);
			sign = ~sign;
		}
	}
	fsfile(q);
	mq = q;
	if(sfbeg(q) == 0){
		if(sbackc(q)<0) {
			mq = copy(q,length(q));
			chsign(mq);
			sign = ~sign;
		}
	}
	mr = salloc(length(mp)+length(mq));
	zero(mr);
	rewind(mq);
	while(sfeof(mq) == 0) {
		cq = sgetc(mq);
		rewind(mp);
		rewind(mr);
		mr->rd += offset;
		carry=0;
		while(sfeof(mp) == 0) {
			cp = sgetc(mp);
			mcr = sfeof(mr)?0:slookc(mr);
			mt = cp*cq + carry + mcr;
			carry = mt/100;
			salterc(mr,mt%100);
		}
		offset++;
		if(carry != 0) {
			mcr = sfeof(mr)?0:slookc(mr);
			salterc(mr,mcr+carry);
		}
	}
	if(sign < 0) {
		chsign(mr);
	}
	if(mp != p)
		release(mp);
	if(mq != q)
		release(mq);
	return(mr);
}

void
chsign(Blk *p)
{
	int carry;
	char ct;

	carry=0;
	rewind(p);
	while(sfeof(p) == 0) {
		ct=100-slookc(p)-carry;
		carry=1;
		if(ct>=100) {
			ct -= 100;
			carry=0;
		}
		salterc(p,ct);
	}
	if(carry != 0) {
		sputc(p,-1);
		fsfile(p);
		backc(p);
		ct = sbackc(p);
		if(ct == 99 /*&& !sfbeg(p)*/) {
			truncate(p);
			sputc(p,-1);
		}
	} else{
		fsfile(p);
		ct = sbackc(p);
		if(ct == 0)
			truncate(p);
	}
	return;
}

int
readc(void)
{
loop:
	if((readptr != &readstk[0]) && (*readptr != 0)) {
		if(sfeof(*readptr) == 0)
			return(lastchar = sgetc(*readptr));
		release(*readptr);
		readptr--;
		goto loop;
	}
	lastchar = Bgetc(curfile);
	if(lastchar != -1)
		return(lastchar);
	if(readptr != &readptr[0]) {
		readptr--;
		if(*readptr == 0)
			curfile = &bin;
		goto loop;
	}
	if(curfile != &bin) {
		Bterm(curfile);
		curfile = &bin;
		goto loop;
	}
	exits(0);
	return 0;	/* shut up ken */
}

void
unreadc(char c)
{

	if((readptr != &readstk[0]) && (*readptr != 0)) {
		sungetc(*readptr,c);
	} else
		Bungetc(curfile);
	return;
}

void
binop(char c)
{
	Blk *r;

	r = 0;
	switch(c) {
	case '+':
		r = add(arg1,arg2);
		break;
	case '*':
		r = mult(arg1,arg2);
		break;
	case '/':
		r = div(arg1,arg2);
		break;
	}
	release(arg1);
	release(arg2);
	sputc(r,savk);
	pushp(r);
}

void
dcprint(Blk *hptr)
{
	Blk *p, *q, *dec;
	int dig, dout, ct, sc;

	rewind(hptr);
	while(sfeof(hptr) == 0) {
		if(sgetc(hptr)>99) {
			rewind(hptr);
			while(sfeof(hptr) == 0) {
				Bprint(&bout,"%c",sgetc(hptr));
			}
			Bprint(&bout,"\n");
			return;
		}
	}
	fsfile(hptr);
	sc = sbackc(hptr);
	if(sfbeg(hptr) != 0) {
		Bprint(&bout,"0\n");
		return;
	}
	count = ll;
	p = copy(hptr,length(hptr));
	sclobber(p);
	fsfile(p);
	if(sbackc(p)<0) {
		chsign(p);
		OUTC('-');
	}
	if((obase == 0) || (obase == -1)) {
		oneot(p,sc,'d');
		return;
	}
	if(obase == 1) {
		oneot(p,sc,'1');
		return;
	}
	if(obase == 10) {
		tenot(p,sc);
		return;
	}
	/* sleazy hack to scale top of stack - divide by 1 */
	pushp(p);
	sputc(p, sc);
	p=salloc(0);
	create(p);
	sputc(p, 1);
	sputc(p, 0);
	pushp(p);
	if(dscale() != 0)
		return;
	p = div(arg1, arg2);
	release(arg1);
	release(arg2);
	sc = savk;

	create(strptr);
	dig = logten*sc;
	dout = ((dig/10) + dig) / logo;
	dec = getdec(p,sc);
	p = removc(p,sc);
	while(length(p) != 0) {
		q = div(p,basptr);
		release(p);
		p = q;
		(*outdit)(rem,0);
	}
	release(p);
	fsfile(strptr);
	while(sfbeg(strptr) == 0)
		OUTC(sbackc(strptr));
	if(sc == 0) {
		release(dec);
		Bprint(&bout,"\n");
		return;
	}
	create(strptr);
	OUTC('.');
	ct=0;
	do {
		q = mult(basptr,dec);
		release(dec);
		dec = getdec(q,sc);
		p = removc(q,sc);
		(*outdit)(p,1);
	} while(++ct < dout);
	release(dec);
	rewind(strptr);
	while(sfeof(strptr) == 0)
		OUTC(sgetc(strptr));
	Bprint(&bout,"\n");
}

Blk*
getdec(Blk *p, int sc)
{
	int cc;
	Blk *q, *t, *s;

	rewind(p);
	if(length(p)*2 < sc) {
		q = copy(p,length(p));
		return(q);
	}
	q = salloc(length(p));
	while(sc >= 1) {
		sputc(q,sgetc(p));
		sc -= 2;
	}
	if(sc != 0) {
		t = mult(q,tenptr);
		s = salloc(cc = length(q));
		release(q);
		rewind(t);
		while(cc-- > 0)
			sputc(s,sgetc(t));
		sputc(s,0);
		release(t);
		t = div(s,tenptr);
		release(s);
		release(rem);
		return(t);
	}
	return(q);
}

void
tenot(Blk *p, int sc)
{
	int c, f;

	fsfile(p);
	f=0;
	while((sfbeg(p) == 0) && ((p->rd-p->beg-1)*2 >= sc)) {
		c = sbackc(p);
		if((c<10) && (f == 1))
			Bprint(&bout,"0%d",c);
		else
			Bprint(&bout,"%d",c);
		f=1;
		TEST2;
	}
	if(sc == 0) {
		Bprint(&bout,"\n");
		release(p);
		return;
	}
	if((p->rd-p->beg)*2 > sc) {
		c = sbackc(p);
		Bprint(&bout,"%d.",c/10);
		TEST2;
		OUTC(c%10 +'0');
		sc--;
	} else {
		OUTC('.');
	}
	while(sc>(p->rd-p->beg)*2) {
		OUTC('0');
		sc--;
	}
	while(sc > 1) {
		c = sbackc(p);
		if(c<10)
			Bprint(&bout,"0%d",c);
		else
			Bprint(&bout,"%d",c);
		sc -= 2;
		TEST2;
	}
	if(sc == 1) {
		OUTC(sbackc(p)/10 +'0');
	}
	Bprint(&bout,"\n");
	release(p);
}

void
oneot(Blk *p, int sc, char ch)
{
	Blk *q;

	q = removc(p,sc);
	create(strptr);
	sputc(strptr,-1);
	while(length(q)>0) {
		p = add(strptr,q);
		release(q);
		q = p;
		OUTC(ch);
	}
	release(q);
	Bprint(&bout,"\n");
}

void
hexot(Blk *p, int flg)
{
	int c;

	USED(flg);
	rewind(p);
	if(sfeof(p) != 0) {
		sputc(strptr,'0');
		release(p);
		return;
	}
	c = sgetc(p);
	release(p);
	if(c >= 16) {
		Bprint(&bout,"hex digit > 16");
		return;
	}
	sputc(strptr,c<10?c+'0':c-10+'a');
}

void
bigot(Blk *p, int flg)
{
	Blk *t, *q;
	int neg, l;

	if(flg == 1) {
		t = salloc(0);
		l = 0;
	} else {
		t = strptr;
		l = length(strptr)+fw-1;
	}
	neg=0;
	if(length(p) != 0) {
		fsfile(p);
		if(sbackc(p)<0) {
			neg=1;
			chsign(p);
		}
		while(length(p) != 0) {
			q = div(p,tenptr);
			release(p);
			p = q;
			rewind(rem);
			sputc(t,sfeof(rem)?'0':sgetc(rem)+'0');
			release(rem);
		}
	}
	release(p);
	if(flg == 1) {
		l = fw1-length(t);
		if(neg != 0) {
			l--;
			sputc(strptr,'-');
		}
		fsfile(t);
		while(l-- > 0)
			sputc(strptr,'0');
		while(sfbeg(t) == 0)
			sputc(strptr,sbackc(t));
		release(t);
	} else {
		l -= length(strptr);
		while(l-- > 0)
			sputc(strptr,'0');
		if(neg != 0) {
			sclobber(strptr);
			sputc(strptr,'-');
		}
	}
	sputc(strptr,' ');
}

Blk*
add(Blk *a1, Blk *a2)
{
	Blk *p;
	int carry, n, size, c, n1, n2;

	size = length(a1)>length(a2)?length(a1):length(a2);
	p = salloc(size);
	rewind(a1);
	rewind(a2);
	carry=0;
	while(--size >= 0) {
		n1 = sfeof(a1)?0:sgetc(a1);
		n2 = sfeof(a2)?0:sgetc(a2);
		n = n1 + n2 + carry;
		if(n>=100) {
			carry=1;
			n -= 100;
		} else
		if(n<0) {
			carry = -1;
			n += 100;
		} else
			carry = 0;
		sputc(p,n);
	}
	if(carry != 0)
		sputc(p,carry);
	fsfile(p);
	if(sfbeg(p) == 0) {
		c = 0;
		while(sfbeg(p) == 0 && (c = sbackc(p)) == 0)
			;
		if(c != 0)
			salterc(p,c);
		truncate(p);
	}
	fsfile(p);
	if(sfbeg(p) == 0 && sbackc(p) == -1) {
		while((c = sbackc(p)) == 99) {
			if(c == -1)
				break;
		}
		skipc(p);
		salterc(p,-1);
		truncate(p);
	}
	return(p);
}

int
eqk(void)
{
	Blk *p, *q;
	int skp, skq;

	p = pop();
	EMPTYS;
	q = pop();
	EMPTYSR(p);
	skp = sunputc(p);
	skq = sunputc(q);
	if(skp == skq) {
		arg1=p;
		arg2=q;
		savk = skp;
		return(0);
	}
	if(skp < skq) {
		savk = skq;
		p = add0(p,skq-skp);
	} else {
		savk = skp;
		q = add0(q,skp-skq);
	}
	arg1=p;
	arg2=q;
	return(0);
}

Blk*
removc(Blk *p, int n)
{
	Blk *q, *r;

	rewind(p);
	while(n>1) {
		skipc(p);
		n -= 2;
	}
	q = salloc(2);
	while(sfeof(p) == 0)
		sputc(q,sgetc(p));
	if(n == 1) {
		r = div(q,tenptr);
		release(q);
		release(rem);
		q = r;
	}
	release(p);
	return(q);
}

Blk*
scalint(Blk *p)
{
	int n;

	n = sunputc(p);
	p = removc(p,n);
	return(p);
}

Blk*
scale(Blk *p, int n)
{
	Blk *q, *s, *t;

	t = add0(p,n);
	q = salloc(1);
	sputc(q,n);
	s = dcexp(inbas,q);
	release(q);
	q = div(t,s);
	release(t);
	release(s);
	release(rem);
	sputc(q,n);
	return(q);
}

int
subt(void)
{
	arg1=pop();
	EMPTYS;
	savk = sunputc(arg1);
	chsign(arg1);
	sputc(arg1,savk);
	pushp(arg1);
	if(eqk() != 0)
		return(1);
	binop('+');
	return(0);
}

int
command(void)
{
	char line[100], *sl;
	int pid, p, c;

	switch(c = readc()) {
	case '<':
		return(cond(NL));
	case '>':
		return(cond(NG));
	case '=':
		return(cond(NE));
	default:
		sl = line;
		*sl++ = c;
		while((c = readc()) != '\n')
			if(sl-line < sizeof(line)-1)
				*sl++ = c;
		*sl = 0;
		if((pid = fork()) == 0) {
			execl("/bin/rc","rc","-c",line,nil);
			exits("shell");
		}
		for(;;) {
			if((p = waitpid()) < 0)
				break;
			if(p== pid)
				break;
		}
		Bprint(&bout,"!\n");
		return(0);
	}
}

int
cond(char c)
{
	Blk *p;
	int cc;

	if(subt() != 0)
		return(1);
	p = pop();
	sclobber(p);
	if(length(p) == 0) {
		release(p);
		if(c == '<' || c == '>' || c == NE) {
			getstk();
			return(0);
		}
		load();
		return(1);
	}
	if(c == '='){
		release(p);
		getstk();
		return(0);
	}
	if(c == NE) {
		release(p);
		load();
		return(1);
	}
	fsfile(p);
	cc = sbackc(p);
	release(p);
	if((cc<0 && (c == '<' || c == NG)) ||
	   (cc >0) && (c == '>' || c == NL)) {
		getstk();
		return(0);
	}
	load();
	return(1);
}

void
load(void)
{
	int c;
	Blk *p, *q, *t, *s;

	c = getstk() & 0377;
	sptr = stable[c];
	if(sptr != 0) {
		p = sptr->val;
		if(c >= ARRAYST) {
			q = salloc(length(p));
			rewind(p);
			while(sfeof(p) == 0) {
				s = dcgetwd(p);
				if(s == 0) {
					putwd(q, (Blk*)0);
				} else {
					t = copy(s,length(s));
					putwd(q,t);
				}
			}
			pushp(q);
		} else {
			q = copy(p,length(p));
			pushp(q);
		}
	} else {
		q = salloc(1);
		if(c <= LASTFUN) {
			Bprint(&bout,"function %c undefined\n",c+'a'-1);
			sputc(q,'c');
			sputc(q,'0');
			sputc(q,' ');
			sputc(q,'1');
			sputc(q,'Q');
		}
		else
			sputc(q,0);
		pushp(q);
	}
}

int
log2(long n)
{
	int i;

	if(n == 0)
		return(0);
	i=31;
	if(n<0)
		return(i);
	while((n <<= 1) > 0)
		i--;
	return i-1;
}

Blk*
salloc(int size)
{
	Blk *hdr;
	char *ptr;

	all++;
	lall++;
	if(all - rel > active)
		active = all - rel;
	nbytes += size;
	lbytes += size;
	if(nbytes >maxsize)
		maxsize = nbytes;
	if(size > longest)
		longest = size;
	ptr = malloc((unsigned)size);
	if(ptr == 0){
		garbage("salloc");
		if((ptr = malloc((unsigned)size)) == 0)
			ospace("salloc");
	}
	if((hdr = hfree) == 0)
		hdr = morehd();
	hfree = (Blk *)hdr->rd;
	hdr->rd = hdr->wt = hdr->beg = ptr;
	hdr->last = ptr+size;
	return(hdr);
}

Blk*
morehd(void)
{
	Blk *h, *kk;

	headmor++;
	nbytes += HEADSZ;
	hfree = h = (Blk *)malloc(HEADSZ);
	if(hfree == 0) {
		garbage("morehd");
		if((hfree = h = (Blk*)malloc(HEADSZ)) == 0)
			ospace("headers");
	}
	kk = h;
	while(h<hfree+(HEADSZ/BLK))
		(h++)->rd = (char*)++kk;
	(h-1)->rd=0;
	return(hfree);
}

Blk*
copy(Blk *hptr, int size)
{
	Blk *hdr;
	unsigned sz;
	char *ptr;

	all++;
	lall++;
	lcopy++;
	nbytes += size;
	lbytes += size;
	if(size > longest)
		longest = size;
	if(size > maxsize)
		maxsize = size;
	sz = length(hptr);
	ptr = malloc(size);
	if(ptr == 0) {
		Bprint(&bout,"copy size %d\n",size);
		ospace("copy");
	}
	memmove(ptr, hptr->beg, sz);
	if (size-sz > 0)
		memset(ptr+sz, 0, size-sz);
	if((hdr = hfree) == 0)
		hdr = morehd();
	hfree = (Blk *)hdr->rd;
	hdr->rd = hdr->beg = ptr;
	hdr->last = ptr+size;
	hdr->wt = ptr+sz;
	ptr = hdr->wt;
	while(ptr<hdr->last)
		*ptr++ = '\0';
	return(hdr);
}

void
sdump(char *s1, Blk *hptr)
{
	char *p;

	if(hptr == nil) {
		Bprint(&bout, "%s no block\n", s1);
		return;
	}
	Bprint(&bout,"%s %lx rd %lx wt %lx beg %lx last %lx\n",
		s1,hptr,hptr->rd,hptr->wt,hptr->beg,hptr->last);
	p = hptr->beg;
	while(p < hptr->wt)
		Bprint(&bout,"%d ",*p++);
	Bprint(&bout,"\n");
}

void
seekc(Blk *hptr, int n)
{
	char *nn,*p;

	nn = hptr->beg+n;
	if(nn > hptr->last) {
		nbytes += nn - hptr->last;
		if(nbytes > maxsize)
			maxsize = nbytes;
		lbytes += nn - hptr->last;
		if(n > longest)
			longest = n;
/*		free(hptr->beg); /**/
		p = realloc(hptr->beg, n);
		if(p == 0) {
/*			hptr->beg = realloc(hptr->beg, hptr->last-hptr->beg);
**			garbage("seekc");
**			if((p = realloc(hptr->beg, n)) == 0)
*/				ospace("seekc");
		}
		hptr->beg = p;
		hptr->wt = hptr->last = hptr->rd = p+n;
		return;
	}
	hptr->rd = nn;
	if(nn>hptr->wt)
		hptr->wt = nn;
}

void
salterwd(Blk *ahptr, Blk *n)
{
	Wblk *hptr;

	hptr = (Wblk*)ahptr;
	if(hptr->rdw == hptr->lastw)
		more(ahptr);
	*hptr->rdw++ = n;
	if(hptr->rdw > hptr->wtw)
		hptr->wtw = hptr->rdw;
}

void
more(Blk *hptr)
{
	unsigned size;
	char *p;

	if((size=(hptr->last-hptr->beg)*2) == 0)
		size=2;
	nbytes += size/2;
	if(nbytes > maxsize)
		maxsize = nbytes;
	if(size > longest)
		longest = size;
	lbytes += size/2;
	lmore++;
/*	free(hptr->beg);/**/
	p = realloc(hptr->beg, size);

	if(p == 0) {
/*		hptr->beg = realloc(hptr->beg, (hptr->last-hptr->beg));
**		garbage("more");
**		if((p = realloc(hptr->beg,size)) == 0)
*/			ospace("more");
	}
	hptr->rd = p + (hptr->rd - hptr->beg);
	hptr->wt = p + (hptr->wt - hptr->beg);
	hptr->beg = p;
	hptr->last = p+size;
}

void
ospace(char *s)
{
	Bprint(&bout,"out of space: %s\n",s);
	Bprint(&bout,"all %ld rel %ld headmor %ld\n",all,rel,headmor);
	Bprint(&bout,"nbytes %ld\n",nbytes);
	sdump("stk",*stkptr);
	abort();
}

void
garbage(char *s)
{
	USED(s);
}

void
release(Blk *p)
{
	rel++;
	lrel++;
	nbytes -= p->last - p->beg;
	p->rd = (char*)hfree;
	hfree = p;
	free(p->beg);
}

Blk*
dcgetwd(Blk *p)
{
	Wblk *wp;

	wp = (Wblk*)p;
	if(wp->rdw == wp->wtw)
		return(0);
	return(*wp->rdw++);
}

void
putwd(Blk *p, Blk *c)
{
	Wblk *wp;

	wp = (Wblk*)p;
	if(wp->wtw == wp->lastw)
		more(p);
	*wp->wtw++ = c;
}

Blk*
lookwd(Blk *p)
{
	Wblk *wp;

	wp = (Wblk*)p;
	if(wp->rdw == wp->wtw)
		return(0);
	return(*wp->rdw);
}

int
getstk(void)
{
	int n;
	uchar c;

	c = readc();
	if(c != '<')
		return c;
	n = 0;
	while(1) {
		c = readc();
		if(c == '>')
			break;
		n = n*10+c-'0';
	}
	return n;
}