forsyth20121205-174063a80cc13 years agoHistory
380 lines · 6.5 KB · Brainfuck
RawDownload
implement Bufferm; include "common.m"; sys : Sys;dat : Dat;utils : Utils;diskm : Diskm;ecmd: Editcmd; FALSE, TRUE, XXX, Maxblock, Astring : import Dat;Block : import Dat;disk : import dat;Disk : import diskm;File: import Filem;error, warning, min : import utils; init(mods : ref Dat->Mods){	sys = mods.sys;	dat = mods.dat;	utils = mods.utils;	diskm = mods.diskm;	ecmd = mods.editcmd;} nullbuffer : Buffer; newbuffer() : ref Buffer{	b := ref nullbuffer;	return b;} Slop : con 100;	# room to grow with reallocation Buffer.sizecache(b : self ref Buffer, n : int){	if(n <= b.cmax)		return;	b.cmax = n+Slop;	os := b.c;	b.c = utils->stralloc(b.cmax);	if (os != nil) {		loss := len os.s;		c := b.c;		oss := os.s;		for (i := 0; i < loss && i < b.cmax; i++)			c.s[i] = oss[i];		utils->strfree(os);	}} ## Move cache so b.cq <= q0 < b.cq+b.cnc.# If at very end, q0 will fall on end of cache block.# Buffer.flush(b : self ref Buffer){	if(b.cdirty || b.cnc==0){		if(b.cnc == 0)			b.delblock(b.cbi);		else			b.bl[b.cbi] = disk.write(b.bl[b.cbi], b.c.s, b.cnc);		b.cdirty = FALSE;	}} Buffer.setcache(b : self ref Buffer, q0 : int){	blp, bl : ref Block;	i, q : int; 	if (q0 > b.nc)		error("bad assert in setcache"); 	# flush and reload if q0 is not in cache.	 	if(b.nc == 0 || (b.cq<=q0 && q0<b.cq+b.cnc))		return; 	# if q0 is at end of file and end of cache, continue to grow this block	 	if(q0==b.nc && q0==b.cq+b.cnc && b.cnc<Maxblock)		return;	b.flush();	# find block 	if(q0 < b.cq){		q = 0;		i = 0;	}else{		q = b.cq;		i = b.cbi;	}	blp = b.bl[i];	while(q+blp.n <= q0 && q+blp.n < b.nc){		q += blp.n;		i++;		blp = b.bl[i];		if(i >= b.nbl)			error("block not found");	}	bl = blp;	# remember position 	b.cbi = i;	b.cq = q;	b.sizecache(bl.n);	b.cnc = bl.n;	#read block	disk.read(bl, b.c, b.cnc);} Buffer.addblock(b : self ref Buffer, i : int, n : int){	if (i > b.nbl)		error("bad assert in addblock"); 	obl := b.bl;	b.bl = array[b.nbl+1] of ref Block;	b.bl[0:] = obl[0:i];	if(i < b.nbl)		b.bl[i+1:] = obl[i:b.nbl];	b.bl[i] = disk.new(n);	b.nbl++;	obl = nil;} Buffer.delblock(b : self ref Buffer, i : int){	if (i >= b.nbl)		error("bad assert in delblock"); 	disk.release(b.bl[i]);	obl := b.bl;	b.bl = array[b.nbl-1] of ref Block;	b.bl[0:] = obl[0:i];	if(i < b.nbl-1)		b.bl[i:] = obl[i+1:b.nbl];	b.nbl--;	obl = nil;} Buffer.insert(b : self ref Buffer, q0 : int, s : string, n : int){	i, j,  m, t, off, p : int; 	if (q0>b.nc)		error("bad assert in insert");	p = 0;	while(n > 0){		b.setcache(q0);		off = q0-b.cq;		if(b.cnc+n <= Maxblock){			# Everything fits in one block. 			t = b.cnc+n;			m = n;			if(b.bl == nil){	# allocate 				if (b.cnc != 0)					error("bad assert in insert");				b.addblock(0, t);				b.cbi = 0;			}			b.sizecache(t);			c := b.c;			# cs := c.s;			for (j = b.cnc-1; j >= off; j--)				c.s[j+m] = c.s[j];			for (j = 0; j < m; j++)				c.s[off+j] = s[p+j];			b.cnc = t;		}		#		# We must make a new block.  If q0 is at		# the very beginning or end of this block,		# just make a new block and fill it.		#		else if(q0==b.cq || q0==b.cq+b.cnc){			if(b.cdirty)				b.flush();			m = min(n, Maxblock);			if(b.bl == nil){	# allocate 				if (b.cnc != 0)					error("bad assert in insert");				i = 0;			}else{				i = b.cbi;				if(q0 > b.cq)					i++;			}			b.addblock(i, m);			b.sizecache(m);			c := b.c;			for (j = 0; j < m; j++)				c.s[j] = s[p+j];			b.cq = q0;			b.cbi = i;			b.cnc = m;		}		else {			#		 	# Split the block; cut off the right side and		 	# let go of it.			#		 			m = b.cnc-off;			if(m > 0){				i = b.cbi+1;				b.addblock(i, m);				b.bl[i] = disk.write(b.bl[i], b.c.s[off:], m);				b.cnc -= m;			}			#			# Now at end of block.  Take as much input			# as possible and tack it on end of block.			#		 			m = min(n, Maxblock-b.cnc);			b.sizecache(b.cnc+m);			c := b.c;			for (j = 0; j < m; j++)				c.s[j+b.cnc] = s[p+j];			b.cnc += m;		}		b.nc += m;		q0 += m;		p += m;		n -= m;		b.cdirty = TRUE;	}} Buffer.delete(b : self ref Buffer, q0 : int, q1 : int){	m, n, off : int; 	if (q0>q1 || q0>b.nc || q1>b.nc)		error("bad assert in delete"); 	while(q1 > q0){		b.setcache(q0);		off = q0-b.cq;		if(q1 > b.cq+b.cnc)			n = b.cnc - off;		else			n = q1-q0;		m = b.cnc - (off+n);		if(m > 0) {			c := b.c;			# cs := c.s;			p := m+off;			for (j := off; j < p; j++)				c.s[j] = c.s[j+n];		}		b.cnc -= n;		b.cdirty = TRUE;		q1 -= n;		b.nc -= n;	}} # Buffer.replace(b: self ref Buffer, q0: int, q1: int, s: string, n: int)# {#	if(q0>q1 || q0>b.nc || q1>b.nc || n != q1-q0)#		error("bad assert in replace");#	p := 0;#	while(q1 > q0){#		b.setcache(q0);#		off := q0-b.cq;#		if(q1 > b.cq+b.cnc)#			n = b.cnc-off;#		else#			n = q1-q0;#		c := b.c;#		for(i := 0; i < n; i++)#			c.s[i+off] = s[i+p];#		b.cdirty = TRUE;#		q0 += n;#		p += n;#	}	# } pbuf : array of byte; bufloader(b: ref Buffer, q0: int, r: string, nr: int): int{	b.insert(q0, r, nr);	return nr;} loadfile(fd: ref Sys->FD, q0: int, fun: int, b: ref Buffer, f: ref File): int{	p : array of byte;	r : string;	m, n, nb, nr : int;	q1 : int; 	if (pbuf == nil)		pbuf = array[Maxblock+Sys->UTFmax] of byte;	p = pbuf;	m = 0;	n = 1;	q1 = q0;	#	# At top of loop, may have m bytes left over from	# last pass, possibly representing a partial rune.	#	 	while(n > 0){		n = sys->read(fd, p[m:], Maxblock);		if(n < 0){			warning(nil, "read error in Buffer.load");			break;		}		m += n;		nb = sys->utfbytes(p, m);		r = string p[0:nb];		p[0:] = p[nb:m];		m -= nb;		nr = len r;		if(fun == Dat->BUFL)			q1 += bufloader(b, q1, r, nr);		else			q1 += ecmd->readloader(f, q1, r, nr);	}	p = nil;	r = nil;	return q1-q0;} Buffer.loadx(b : self ref Buffer, q0 : int, fd : ref Sys->FD) : int{	if (q0>b.nc)		error("bad assert in load");	return loadfile(fd, q0, Dat->BUFL, b, nil);} Buffer.read(b : self ref Buffer, q0 : int, s : ref Astring, p : int, n : int){	m : int; 	if (q0>b.nc || q0+n>b.nc)		error("bad assert in read");	while(n > 0){		b.setcache(q0);		m = min(n, b.cnc-(q0-b.cq));		c := b.c;		cs := c.s;		for (j := 0; j < m; j++)			s.s[p+j] = cs[j+q0-b.cq];		q0 += m;		p += m;		n -= m;	}} Buffer.reset(b : self ref Buffer){	i : int; 	b.nc = 0;	b.cnc = 0;	b.cq = 0;	b.cdirty = 0;	b.cbi = 0;	# delete backwards to avoid n² behavior 	for(i=b.nbl-1; --i>=0; )		b.delblock(i);} Buffer.close(b : self ref Buffer){	b.reset();	if (b.c != nil) {		utils->strfree(b.c);		b.c = nil;	}	b.cnc = 0;	b.bl = nil;	b.nbl = 0;}