summaryrefslogtreecommitdiff
path: root/appl/acme/file.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/acme/file.b')
-rw-r--r--appl/acme/file.b331
1 files changed, 331 insertions, 0 deletions
diff --git a/appl/acme/file.b b/appl/acme/file.b
new file mode 100644
index 00000000..1f53cc66
--- /dev/null
+++ b/appl/acme/file.b
@@ -0,0 +1,331 @@
+implement Filem;
+
+include "common.m";
+
+sys : Sys;
+dat : Dat;
+utils : Utils;
+buffm : Bufferm;
+textm : Textm;
+editlog: Editlog;
+
+FALSE, TRUE, XXX, Delete, Insert, Filename, BUFSIZE, Astring : import Dat;
+Buffer, newbuffer : import buffm;
+Text : import textm;
+error : import utils;
+
+init(mods : ref Dat->Mods)
+{
+ sys = mods.sys;
+ dat = mods.dat;
+ utils = mods.utils;
+ buffm = mods.bufferm;
+ textm = mods.textm;
+ editlog = mods.editlog;
+}
+
+#
+# Structure of Undo list:
+# The Undo structure follows any associated data, so the list
+# can be read backwards: read the structure, then read whatever
+# data is associated (insert string, file name) and precedes it.
+# The structure includes the previous value of the modify bit
+# and a sequence number; successive Undo structures with the
+# same sequence number represent simultaneous changes.
+#
+
+Undo : adt
+{
+ typex : int; # Delete, Insert, Filename
+ mod : int; # modify bit
+ seq : int; # sequence number
+ p0 : int; # location of change (unused in f)
+ n : int; # # runes in string or file name
+};
+
+Undosize : con 8;
+SHM : con 16rffff;
+
+undotostr(t, m, s, p, n : int) : string
+{
+ a := "01234567";
+ a[0] = t;
+ a[1] = m;
+ a[2] = s&SHM;
+ a[3] = (s>>16)&SHM;
+ a[4] = p&SHM;
+ a[5] = (p>>16)&SHM;
+ a[6] = n&SHM;
+ a[7] = (n>>16)&SHM;
+ return a;
+}
+
+strtoundo(s: string): Undo
+{
+ u: Undo;
+
+ u.typex = s[0];
+ u.mod = s[1];
+ u.seq = s[2]|(s[3]<<16);
+ u.p0 = s[4]|(s[5]<<16);
+ u.n = s[6]|(s[7]<<16);
+ return u;
+}
+
+nullfile : File;
+
+File.addtext(f : self ref File, t : ref Text) : ref File
+{
+ if(f == nil) {
+ f = ref nullfile;
+ f.buf = newbuffer();
+ f.delta = newbuffer();
+ f.epsilon = newbuffer();
+ f.ntext = 0;
+ f.unread = TRUE;
+ }
+ oft := f.text;
+ f.text = array[f.ntext+1] of ref Text;
+ f.text[0:] = oft[0:f.ntext];
+ oft = nil;
+ f.text[f.ntext++] = t;
+ f.curtext = t;
+ return f;
+}
+
+File.deltext(f : self ref File, t : ref Text)
+{
+ i : int;
+
+ for(i=0; i<f.ntext; i++)
+ if(f.text[i] == t)
+ break;
+ if (i == f.ntext)
+ error("can't find text in File.deltext");
+
+ f.ntext--;
+ if(f.ntext == 0){
+ f.close();
+ return;
+ }
+ f.text[i:] = f.text[i+1:f.ntext+1];
+ if(f.curtext == t)
+ f.curtext = f.text[0];
+}
+
+File.insert(f : self ref File, p0 : int, s : string, ns : int)
+{
+ if (p0 > f.buf.nc)
+ error("bad assert in File.insert");
+ if(f.seq > 0)
+ f.uninsert(f.delta, p0, ns);
+ f.buf.insert(p0, s, ns);
+ if(ns)
+ f.mod = TRUE;
+}
+
+File.uninsert(f : self ref File, delta : ref Buffer, p0 : int, ns : int)
+{
+ # undo an insertion by deleting
+ a := undotostr(Delete, f.mod, f.seq, p0, ns);
+ delta.insert(delta.nc, a, Undosize);
+}
+
+File.delete(f : self ref File, p0 : int, p1 : int)
+{
+ if (p0>p1 || p0>f.buf.nc || p1>f.buf.nc)
+ error("bad assert in File.delete");
+ if(f.seq > 0)
+ f.undelete(f.delta, p0, p1);
+ f.buf.delete(p0, p1);
+ if(p1 > p0)
+ f.mod = TRUE;
+}
+
+File.undelete(f : self ref File, delta : ref Buffer, p0 : int, p1 : int)
+{
+ buf : ref Astring;
+ i, n : int;
+
+ # undo a deletion by inserting
+ a := undotostr(Insert, f.mod, f.seq, p0, p1-p0);
+ m := p1-p0;
+ if(m > BUFSIZE)
+ m = BUFSIZE;
+ buf = utils->stralloc(m);
+ for(i=p0; i<p1; i+=n){
+ n = p1 - i;
+ if(n > BUFSIZE)
+ n = BUFSIZE;
+ f.buf.read(i, buf, 0, n);
+ delta.insert(delta.nc, buf.s, n);
+ }
+ utils->strfree(buf);
+ buf = nil;
+ delta.insert(delta.nc, a, Undosize);
+}
+
+File.setname(f : self ref File, name : string, n : int)
+{
+ if(f.seq > 0)
+ f.unsetname(f.delta);
+ f.name = name[0:n];
+ f.unread = TRUE;
+}
+
+File.unsetname(f : self ref File, delta : ref Buffer)
+{
+ # undo a file name change by restoring old name
+ a := undotostr(Filename, f.mod, f.seq, 0, len f.name);
+ if(f.name != nil)
+ delta.insert(delta.nc, f.name, len f.name);
+ delta.insert(delta.nc, a, Undosize);
+}
+
+File.loadx(f : self ref File, p0 : int, fd : ref Sys->FD) : int
+{
+ if(f.seq > 0)
+ error("undo in file.load unimplemented");
+ return f.buf.loadx(p0, fd);
+}
+
+File.undo(f : self ref File, isundo : int, q0 : int, q1 : int) : (int, int)
+{
+ buf : ref Astring;
+ i, j, n, up : int;
+ stop : int;
+ delta, epsilon : ref Buffer;
+ u : Undo;
+
+ a := utils->stralloc(Undosize);
+ if(isundo){
+ # undo; reverse delta onto epsilon, seq decreases
+ delta = f.delta;
+ epsilon = f.epsilon;
+ stop = f.seq;
+ }else{
+ # redo; reverse epsilon onto delta, seq increases
+ delta = f.epsilon;
+ epsilon = f.delta;
+ stop = 0; # don't know yet
+ }
+
+ buf = utils->stralloc(BUFSIZE);
+ while(delta.nc > 0){
+ up = delta.nc-Undosize;
+ delta.read(up, a, 0, Undosize);
+ u = strtoundo(a.s);
+ if(isundo){
+ if(u.seq < stop){
+ f.seq = u.seq;
+ utils->strfree(buf);
+ utils->strfree(a);
+ return (q0, q1);
+ }
+ }else{
+ if(stop == 0)
+ stop = u.seq;
+ if(u.seq > stop){
+ utils->strfree(buf);
+ utils->strfree(a);
+ return (q0, q1);
+ }
+ }
+ case(u.typex){
+ Delete =>
+ f.seq = u.seq;
+ f.undelete(epsilon, u.p0, u.p0+u.n);
+ f.mod = u.mod;
+ f.buf.delete(u.p0, u.p0+u.n);
+ for(j=0; j<f.ntext; j++)
+ f.text[j].delete(u.p0, u.p0+u.n, FALSE);
+ q0 = u.p0;
+ q1 = u.p0;
+ Insert =>
+ f.seq = u.seq;
+ f.uninsert(epsilon, u.p0, u.n);
+ f.mod = u.mod;
+ up -= u.n;
+ # buf = utils->stralloc(BUFSIZE);
+ for(i=0; i<u.n; i+=n){
+ n = u.n - i;
+ if(n > BUFSIZE)
+ n = BUFSIZE;
+ delta.read(up+i, buf, 0, n);
+ f.buf.insert(u.p0+i, buf.s, n);
+ for(j=0; j<f.ntext; j++)
+ f.text[j].insert(u.p0+i, buf.s, n, FALSE, 0);
+ }
+ # utils->strfree(buf);
+ # buf = nil;
+ q0 = u.p0;
+ q1 = u.p0+u.n;
+ Filename =>
+ f.seq = u.seq;
+ f.unsetname(epsilon);
+ f.mod = u.mod;
+ up -= u.n;
+ f.name = nil;
+ if(u.n == 0)
+ f.name = nil;
+ else {
+ fn0 := utils->stralloc(u.n);
+ delta.read(up, fn0, 0, u.n);
+ f.name = fn0.s;
+ utils->strfree(fn0);
+ fn0 = nil;
+ }
+ * =>
+ error(sys->sprint("undo: 0x%ux", u.typex));
+ error("");
+ }
+ delta.delete(up, delta.nc);
+ }
+ utils->strfree(buf);
+ utils->strfree(a);
+ buf = nil;
+ if(isundo)
+ f.seq = 0;
+ return (q0, q1);
+}
+
+File.reset(f : self ref File)
+{
+ f.delta.reset();
+ f.epsilon.reset();
+ f.seq = 0;
+}
+
+File.close(f : self ref File)
+{
+ f.name = nil;
+ f.ntext = 0;
+ f.text = nil;
+ f.buf.close();
+ f.delta.close();
+ f.epsilon.close();
+ editlog->elogclose(f);
+ f = nil;
+}
+
+File.mark(f : self ref File)
+{
+ if(f.epsilon.nc)
+ f.epsilon.delete(0, f.epsilon.nc);
+ f.seq = dat->seq;
+}
+
+File.redoseq(f : self ref File): int
+{
+ u: Undo;
+ delta: ref Buffer;
+
+ delta = f.epsilon;
+ if(delta.nc == 0)
+ return ~0;
+ buf := utils->stralloc(Undosize);
+ delta.read(delta.nc-Undosize, buf, 0, Undosize);
+ u = strtoundo(buf.s);
+ utils->strfree(buf);
+ return u.seq;
+} \ No newline at end of file