ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/acme/xfid.b/
implement Xfidm;
include "common.m";
sys : Sys;
dat : Dat;
graph : Graph;
utils : Utils;
regx : Regx;
bufferm : Bufferm;
diskm : Diskm;
filem : Filem;
textm : Textm;
columnm : Columnm;
scrl : Scroll;
look : Look;
exec : Exec;
windowm : Windowm;
fsys : Fsys;
editm: Edit;
ecmd: Editcmd;
styxaux: Styxaux;
UTFmax : import Sys;
sprint : import sys;
Smsg0 : import Dat;
TRUE, FALSE, XXX, BUFSIZE, MAXRPC : import Dat;
EM_NORMAL, EM_RAW, EM_MASK : import Dat;
Qdir, Qcons, Qlabel, Qindex, Qeditout : import Dat;
QWaddr, QWdata, QWevent, QWconsctl, QWctl, QWbody, QWeditout, QWtag, QWrdsel, QWwrsel : import Dat;
seq, cxfidfree, Lock, Ref, Range, Mntdir, Astring : import dat;
error, warning, max, min, stralloc, strfree, strncmp : import utils;
address : import regx;
Buffer : import bufferm;
File : import filem;
Text : import textm;
scrdraw : import scrl;
Window : import windowm;
bflush : import graph;
Column : import columnm;
row : import dat;
FILE, QID, respond : import fsys;
oldtag, name, offset, count, data, setcount, setdata : import styxaux;
init(mods : ref Dat->Mods)
{
sys = mods.sys;
dat = mods.dat;
graph = mods.graph;
utils = mods.utils;
regx = mods.regx;
filem = mods.filem;
bufferm = mods.bufferm;
diskm = mods.diskm;
textm = mods.textm;
columnm = mods.columnm;
scrl = mods.scroll;
look = mods.look;
exec = mods.exec;
windowm = mods.windowm;
fsys = mods.fsys;
editm = mods.edit;
ecmd = mods.editcmd;
styxaux = mods.styxaux;
}
nullxfid : Xfid;
newxfid() : ref Xfid
{
x := ref Xfid;
*x = nullxfid;
x.buf = array[fsys->messagesize+UTFmax] of byte;
return x;
}
Ctlsize : con 5*12;
Edel := "deleted window";
Ebadctl := "ill-formed control message";
Ebadaddr := "bad address syntax";
Eaddr := "address out of range";
Einuse := "already in use";
Ebadevent:= "bad event syntax";
clampaddr(w : ref Window)
{
if(w.addr.q0 < 0)
w.addr.q0 = 0;
if(w.addr.q1 < 0)
w.addr.q1 = 0;
if(w.addr.q0 > w.body.file.buf.nc)
w.addr.q0 = w.body.file.buf.nc;
if(w.addr.q1 > w.body.file.buf.nc)
w.addr.q1 = w.body.file.buf.nc;
}
xfidtid : array of int;
nxfidtid := 0;
xfidkill()
{
if (sys == nil)
return;
thispid := sys->pctl(0, nil);
for (i := 0; i < nxfidtid; i++)
utils->postnote(Utils->PNPROC, thispid, xfidtid[i], "kill");
}
Xfid.ctl(x : self ref Xfid)
{
x.tid = sys->pctl(0, nil);
ox := xfidtid;
xfidtid = array[nxfidtid+1] of int;
xfidtid[0:] = ox[0:nxfidtid];
xfidtid[nxfidtid++] = x.tid;
ox = nil;
for (;;) {
f := <- x.c;
case (f) {
Xnil => ;
Xflush => x.flush();
Xwalk => x.walk(nil);
Xopen => x.open();
Xclose => x.close();
Xread => x.read();
Xwrite => x.write();
* => error("bad case in Xfid.ctl()");
}
bflush();
cxfidfree <-= x;
}
}
Xfid.flush(x : self ref Xfid)
{
fc : Smsg0;
i, j : int;
w : ref Window;
c : ref Column;
wx : ref Xfid;
# search windows for matching tag
row.qlock.lock();
loop:
for(j=0; j<row.ncol; j++){
c = row.col[j];
for(i=0; i<c.nw; i++){
w = c.w[i];
w.lock('E');
wx = w.eventx;
if(wx!=nil && wx.fcall.tag==oldtag(x.fcall)){
w.eventx = nil;
wx.flushed = TRUE;
wx.c <-= Xnil;
w.unlock();
break loop;
}
w.unlock();
}
}
row.qlock.unlock();
respond(x, fc, nil);
}
Xfid.walk(nil : self ref Xfid, cw: chan of ref Window)
{
# fc : Smsg0;
w : ref Window;
# if(name(x.fcall) != "new")
# error("unknown path in walk\n");
row.qlock.lock(); # tasks->procs now
w = utils->newwindow(nil);
w.settag();
# w.refx.inc();
# x.f.w = w;
# x.f.qid.path = big QID(w.id, Qdir);
# x.f.qid.qtype = Sys->QTDIR;
# fc.qid = x.f.qid;
row.qlock.unlock();
# respond(x, fc, nil);
cw <-= w;
}
Xfid.open(x : self ref Xfid)
{
fc : Smsg0;
w : ref Window;
q : int;
fc.iounit = 0;
w = x.f.w;
if(w != nil){
t := w.body;
row.qlock.lock(); # tasks->procs now
w.lock('E');
q = FILE(x.f.qid);
case(q){
QWaddr or QWdata or QWevent =>
if(w.nopen[q]++ == byte 0){
if(q == QWaddr){
w.addr = (Range)(0,0);
w.limit = (Range)(-1,-1);
}
if(q==QWevent && !w.isdir && w.col!=nil){
w.filemenu = FALSE;
w.settag();
}
}
QWrdsel =>
#
# Use a temporary file.
# A pipe would be the obvious, but we can't afford the
# broken pipe notification. Using the code to read QWbody
# is n², which should probably also be fixed. Even then,
# though, we'd need to squirrel away the data in case it's
# modified during the operation, e.g. by |sort
#
if(w.rdselfd != nil){
w.unlock();
respond(x, fc, Einuse);
return;
}
w.rdselfd = diskm->tempfile();
if(w.rdselfd == nil){
w.unlock();
respond(x, fc, "can't create temp file");
return;
}
w.nopen[q]++;
q0 := t.q0;
q1 := t.q1;
r := utils->stralloc(BUFSIZE);
while(q0 < q1){
n := q1 - q0;
if(n > BUFSIZE)
n = BUFSIZE;
t.file.buf.read(q0, r, 0, n);
s := array of byte r.s[0:n];
m := len s;
if(sys->write(w.rdselfd, s, m) != m){
warning(nil, "can't write temp file for pipe command %r\n");
break;
}
s = nil;
q0 += n;
}
utils->strfree(r);
QWwrsel =>
w.nopen[q]++;
seq++;
t.file.mark();
exec->cut(t, t, FALSE, TRUE);
w.wrselrange = (Range)(t.q1, t.q1);
w.nomark = TRUE;
QWeditout =>
if(editm->editing == FALSE){
w.unlock();
respond(x, fc, "permission denied");
return;
}
w.wrselrange = (Range)(t.q1, t.q1);
break;
}
w.unlock();
row.qlock.unlock();
}
fc.qid = x.f.qid;
fc.iounit = fsys->messagesize-Styx->IOHDRSZ;
x.f.open = TRUE;
respond(x, fc, nil);
}
Xfid.close(x : self ref Xfid)
{
fc : Smsg0;
w : ref Window;
q : int;
w = x.f.w;
# BUG in C version ? fsysclunk() has just set busy, open to FALSE
# x.f.busy = FALSE;
# if(!x.f.open){
# if(w != nil)
# w.close();
# respond(x, fc, nil);
# return;
# }
# x.f.open = FALSE;
if(w != nil){
row.qlock.lock(); # tasks->procs now
w.lock('E');
q = FILE(x.f.qid);
case(q){
QWctl =>
if(w.ctlfid!=~0 && w.ctlfid==x.f.fid){
w.ctlfid = ~0;
w.ctllock.unlock();
}
QWdata or QWaddr or QWevent =>
# BUG: do we need to shut down Xfid?
if (q == QWdata)
w.nomark = FALSE;
if(--w.nopen[q] == byte 0){
if(q == QWdata)
w.nomark = FALSE;
if(q==QWevent && !w.isdir && w.col!=nil){
w.filemenu = TRUE;
w.settag();
}
if(q == QWevent){
w.dumpstr = nil;
w.dumpdir = nil;
}
}
QWrdsel =>
w.rdselfd = nil;
QWwrsel =>
w.nomark = FALSE;
t :=w.body;
# before: only did this if !w->noscroll, but that didn't seem right in practice
t.show(min(w.wrselrange.q0, t.file.buf.nc),
min(w.wrselrange.q1, t.file.buf.nc), TRUE);
scrdraw(t);
QWconsctl=>
w.echomode = EM_NORMAL;
}
w.close();
w.unlock();
row.qlock.unlock();
}
respond(x, fc, nil);
}
Xfid.read(x : self ref Xfid)
{
fc : Smsg0;
n, q : int;
off : int;
sbuf : string;
buf : array of byte;
w : ref Window;
sbuf = nil;
q = FILE(x.f.qid);
w = x.f.w;
if(w == nil){
fc.count = 0;
case(q){
Qcons or Qlabel =>
;
Qindex =>
x.indexread();
return;
* =>
warning(nil, sprint("unknown qid %d\n", q));
}
respond(x, fc, nil);
return;
}
w.lock('F');
if(w.col == nil){
w.unlock();
respond(x, fc, Edel);
return;
}
off = int offset(x.fcall);
case(q){
QWaddr =>
w.body.commit(TRUE);
clampaddr(w);
sbuf = sprint("%11d %11d ", w.addr.q0, w.addr.q1);
QWbody =>
x.utfread(w.body, 0, w.body.file.buf.nc, QWbody);
QWctl =>
sbuf = w.ctlprint(1);
QWevent =>
x.eventread(w);
QWdata =>
# BUG: what should happen if q1 > q0?
if(w.addr.q0 > w.body.file.buf.nc){
respond(x, fc, Eaddr);
break;
}
w.addr.q0 += x.runeread(w.body, w.addr.q0, w.body.file.buf.nc);
w.addr.q1 = w.addr.q0;
QWtag =>
x.utfread(w.tag, 0, w.tag.file.buf.nc, QWtag);
QWrdsel =>
sys->seek(w.rdselfd, big off, 0);
n = count(x.fcall);
if(n > BUFSIZE)
n = BUFSIZE;
b := array[n] of byte;
n = sys->read(w.rdselfd, b, n);
if(n < 0){
respond(x, fc, "I/O error in temp file");
break;
}
fc.count = n;
fc.data = b;
respond(x, fc, nil);
b = nil;
* =>
sbuf = sprint("unknown qid %d in read", q);
respond(x, fc, sbuf);
sbuf = nil;
}
if (sbuf != nil) {
buf = array of byte sbuf;
sbuf = nil;
n = len buf;
if(off > n)
off = n;
if(off+count(x.fcall) > n)
setcount(x.fcall, n-off);
fc.count = count(x.fcall);
fc.data = buf[off:];
respond(x, fc, nil);
buf = nil;
}
w.unlock();
}
Xfid.write(x : self ref Xfid)
{
fc : Smsg0;
c, cnt, qid, q, nb, nr, eval : int;
w : ref Window;
r : string;
a : Range;
t : ref Text;
q0, tq0, tq1 : int;
md : ref Mntdir;
qid = FILE(x.f.qid);
w = x.f.w;
row.qlock.lock(); # tasks->procs now
if(w != nil){
c = 'F';
if(qid==QWtag || qid==QWbody)
c = 'E';
w.lock(c);
if(w.col == nil){
w.unlock();
row.qlock.unlock();
respond(x, fc, Edel);
return;
}
}
bodytag := 0;
case(qid){
Qcons =>
md = x.f.mntdir;
warning(md, string data(x.fcall));
fc.count = count(x.fcall);
respond(x, fc, nil);
QWconsctl =>
if (w != nil) {
r = string data(x.fcall);
if (strncmp(r, "rawon", 5) == 0)
w.echomode = EM_RAW;
else if (strncmp(r, "rawoff", 6) == 0)
w.echomode = EM_NORMAL;
}
fc.count = count(x.fcall);
respond(x, fc, nil);
Qlabel =>
fc.count = count(x.fcall);
respond(x, fc, nil);
QWaddr =>
r = string data(x.fcall);
nr = len r;
t = w.body;
w.commit(t);
(eval, nb, a) = address(x.f.mntdir, t, w.limit, w.addr, nil, r, 0, nr, TRUE);
r = nil;
if(nb < nr){
respond(x, fc, Ebadaddr);
break;
}
if(!eval){
respond(x, fc, Eaddr);
break;
}
w.addr = a;
fc.count = count(x.fcall);
respond(x, fc, nil);
Qeditout or
QWeditout =>
r = string data(x.fcall);
nr = len r;
if(w!=nil)
err := ecmd->edittext(w.body.file, w.wrselrange.q1, r, nr);
else
err = ecmd->edittext(nil, 0, r, nr);
r = nil;
if(err != nil){
respond(x, fc, err);
break;
}
fc.count = count(x.fcall);
respond(x, fc, nil);
break;
QWbody or QWwrsel =>
t = w.body;
bodytag = 1;
QWctl =>
x.ctlwrite(w);
QWdata =>
t = w.body;
w.commit(t);
if(w.addr.q0>t.file.buf.nc || w.addr.q1>t.file.buf.nc){
respond(x, fc, Eaddr);
break;
}
nb = sys->utfbytes(data(x.fcall), count(x.fcall));
r = string data(x.fcall)[0:nb];
nr = len r;
if(w.nomark == FALSE){
seq++;
t.file.mark();
}
q0 = w.addr.q0;
if(w.addr.q1 > q0){
t.delete(q0, w.addr.q1, TRUE);
w.addr.q1 = q0;
}
tq0 = t.q0;
tq1 = t.q1;
t.insert(q0, r, nr, TRUE, 0);
if(tq0 >= q0)
tq0 += nr;
if(tq1 >= q0)
tq1 += nr;
if(!t.w.noscroll)
t.show(tq0, tq1, TRUE);
scrdraw(t);
w.settag();
r = nil;
w.addr.q0 += nr;
w.addr.q1 = w.addr.q0;
fc.count = count(x.fcall);
respond(x, fc, nil);
QWevent =>
x.eventwrite(w);
QWtag =>
t = w.tag;
bodytag = 1;
* =>
r = sprint("unknown qid %d in write", qid);
respond(x, fc, r);
r = nil;
}
if (bodytag) {
q = x.f.nrpart;
cnt = count(x.fcall);
if(q > 0){
nd := array[cnt+q] of byte;
nd[q:] = data(x.fcall)[0:cnt];
nd[0:] = x.f.rpart[0:q];
setdata(x.fcall, nd);
cnt += q;
x.f.nrpart = 0;
}
nb = sys->utfbytes(data(x.fcall), cnt);
r = string data(x.fcall)[0:nb];
nr = len r;
if(nb < cnt){
x.f.rpart = data(x.fcall)[nb:cnt];
x.f.nrpart = cnt-nb;
}
if(nr > 0){
t.w.commit(t);
if(qid == QWwrsel){
q0 = w.wrselrange.q1;
if(q0 > t.file.buf.nc)
q0 = t.file.buf.nc;
}else
q0 = t.file.buf.nc;
if(qid == QWbody || qid == QWwrsel){
if(!w.nomark){
seq++;
t.file.mark();
}
(q0, nr) = t.bsinsert(q0, r, nr, TRUE);
if(qid!=QWwrsel && !t.w.noscroll)
t.show(q0+nr, q0+nr, TRUE);
scrdraw(t);
}else
t.insert(q0, r, nr, TRUE, 0);
w.settag();
if(qid == QWwrsel)
w.wrselrange.q1 += nr;
r = nil;
}
fc.count = count(x.fcall);
respond(x, fc, nil);
}
if(w != nil)
w.unlock();
row.qlock.unlock();
}
Xfid.ctlwrite(x : self ref Xfid, w : ref Window)
{
fc : Smsg0;
i, m, n, nb : int;
r, err, p, pp : string;
q : int;
scrdrw, settag : int;
t : ref Text;
err = nil;
scrdrw = FALSE;
settag = FALSE;
w.tag.commit(TRUE);
nb = sys->utfbytes(data(x.fcall), count(x.fcall));
r = string data(x.fcall)[0:nb];
loop :
for(n=0; n<len r; n+=m){
p = r[n:];
if(strncmp(p, "lock", 4) == 0){ # make window exclusive use
w.ctllock.lock();
w.ctlfid = x.f.fid;
m = 4;
}else
if(strncmp(p, "unlock", 6) == 0){ # release exclusive use
w.ctlfid = ~0;
w.ctllock.unlock();
m = 6;
}else
if(strncmp(p, "clean", 5) == 0){ # mark window 'clean', seq=0
t = w.body;
t.eq0 = ~0;
t.file.reset();
t.file.mod = FALSE;
w.dirty = FALSE;
settag = TRUE;
m = 5;
}else
if(strncmp(p, "show", 4) == 0){ # show dot
t = w.body;
t.show(t.q0, t.q1, TRUE);
m = 4;
}else
if(strncmp(p, "name ", 5) == 0){ # set file name
pp = p[5:];
m = 5;
q = utils->strchr(pp, '\n');
if(q<=0){
err = Ebadctl;
break;
}
nm := pp[0:q];
for(i=0; i<len nm; i++)
if(nm[i] <= ' '){
err = "bad character in file name";
break loop;
}
seq++;
w.body.file.mark();
w.setname(nm, len nm);
m += (q+1);
}else
if(strncmp(p, "dump ", 5) == 0){ # set dump string
pp = p[5:];
m = 5;
q = utils->strchr(pp, '\n');
if(q<=0){
err = Ebadctl;
break;
}
nm := pp[0:q];
w.dumpstr = nm;
m += (q+1);
}else
if(strncmp(p, "dumpdir ", 8) == 0){ # set dump directory
pp = p[8:];
m = 8;
q = utils->strchr(pp, '\n');
if(q<=0){
err = Ebadctl;
break;
}
nm := pp[0:q];
w.dumpdir = nm;
m += (q+1);
}else
if(strncmp(p, "delete", 6) == 0){ # delete for sure
w.col.close(w, TRUE);
m = 6;
}else
if(strncmp(p, "del", 3) == 0){ # delete, but check dirty
if(!w.clean(TRUE, FALSE)){
err = "file dirty";
break;
}
w.col.close(w, TRUE);
m = 3;
}else
if(strncmp(p, "get", 3) == 0){ # get file
exec->get(w.body, nil, nil, FALSE, nil, 0);
m = 3;
}else
if(strncmp(p, "put", 3) == 0){ # put file
exec->put(w.body, nil, nil, 0);
m = 3;
}else
if(strncmp(p, "dot=addr", 8) == 0){ # set dot
w.body.commit(TRUE);
clampaddr(w);
w.body.q0 = w.addr.q0;
w.body.q1 = w.addr.q1;
w.body.setselect(w.body.q0, w.body.q1);
settag = TRUE;
m = 8;
}else
if(strncmp(p, "addr=dot", 8) == 0){ # set addr
w.addr.q0 = w.body.q0;
w.addr.q1 = w.body.q1;
m = 8;
}else
if(strncmp(p, "limit=addr", 10) == 0){ # set limit
w.body.commit(TRUE);
clampaddr(w);
w.limit.q0 = w.addr.q0;
w.limit.q1 = w.addr.q1;
m = 10;
}else
if(strncmp(p, "nomark", 6) == 0){ # turn off automatic marking
w.nomark = TRUE;
m = 6;
}else
if(strncmp(p, "mark", 4) == 0){ # mark file
seq++;
w.body.file.mark();
settag = TRUE;
m = 4;
}else
if(strncmp(p, "noscroll", 8) == 0){ # turn off automatic scrolling
w.noscroll = TRUE;
m = 8;
}else
if(strncmp(p, "cleartag", 8) == 0){ # wipe tag right of bar
w.cleartag();
settag = TRUE;
m = 8;
}else
if(strncmp(p, "scroll", 6) == 0){ # turn on automatic scrolling (writes to body only)
w.noscroll = FALSE;
m = 6;
}else
if(strncmp(p, "noecho", 6) == 0){ # don't echo chars - mask them
w.echomode = EM_MASK;
m = 6;
}else
if (strncmp(p, "echo", 4) == 0){ # echo chars (normal state)
w.echomode = EM_NORMAL;
m = 4;
}else{
err = Ebadctl;
break;
}
while(m < len p && p[m] == '\n')
m++;
}
ab := array of byte r[0:n];
n = len ab;
ab = nil;
r = nil;
if(err != nil)
n = 0;
fc.count = n;
respond(x, fc, err);
if(settag)
w.settag();
if(scrdrw)
scrdraw(w.body);
}
Xfid.eventwrite(x : self ref Xfid, w : ref Window)
{
fc : Smsg0;
m, n, nb : int;
r, err : string;
p, q : int;
t : ref Text;
c : int;
q0, q1 : int;
err = nil;
nb = sys->utfbytes(data(x.fcall), count(x.fcall));
r = string data(x.fcall)[0:nb];
loop :
for(n=0; n<len r; n+=m){
p = n;
w.owner = r[p++]; # disgusting
c = r[p++];
while(r[p] == ' ')
p++;
q0 = int r[p:];
q = p;
if (r[q] == '+' || r[q] == '-')
q++;
while (r[q] >= '0' && r[q] <= '9')
q++;
if(q == p) {
err = Ebadevent;
break;
}
p = q;
while(r[p] == ' ')
p++;
q1 = int r[p:];
q = p;
if (r[q] == '+' || r[q] == '-')
q++;
while (r[q] >= '0' && r[q] <= '9')
q++;
if(q == p) {
err = Ebadevent;
break;
}
p = q;
while(r[p] == ' ')
p++;
if(r[p++] != '\n') {
err = Ebadevent;
break;
}
m = p-n;
if('a'<=c && c<='z')
t = w.tag;
else if('A'<=c && c<='Z')
t = w.body;
else {
err = Ebadevent;
break;
}
if(q0>t.file.buf.nc || q1>t.file.buf.nc || q0>q1) {
err = Ebadevent;
break;
}
# row.qlock.lock();
case(c){
'x' or 'X' =>
exec->execute(t, q0, q1, TRUE, nil);
'l' or 'L' =>
look->look3(t, q0, q1, TRUE);
* =>
err = Ebadevent;
break loop;
}
# row.qlock.unlock();
}
ab := array of byte r[0:n];
n = len ab;
ab = nil;
r = nil;
if(err != nil)
n = 0;
fc.count = n;
respond(x, fc, err);
}
Xfid.utfread(x : self ref Xfid, t : ref Text, q0, q1 : int, qid : int)
{
fc : Smsg0;
w : ref Window;
r : ref Astring;
b, b1 : array of byte;
q, off, boff : int;
m, n, nr, nb : int;
w = t.w;
w.commit(t);
off = int offset(x.fcall);
r = stralloc(BUFSIZE);
b1 = array[MAXRPC] of byte;
n = 0;
if(qid==w.utflastqid && off>=w.utflastboff && w.utflastq<=q1){
boff = w.utflastboff;
q = w.utflastq;
}else{
# BUG: stupid code: scan from beginning
boff = 0;
q = q0;
}
w.utflastqid = qid;
while(q<q1 && n<count(x.fcall)){
w.utflastboff = boff;
w.utflastq = q;
nr = q1-q;
if(nr > BUFSIZE)
nr = BUFSIZE;
t.file.buf.read(q, r, 0, nr);
b = array of byte r.s[0:nr];
nb = len b;
if(boff >= off){
m = nb;
if(boff+m > off+count(x.fcall))
m = off+count(x.fcall) - boff;
b1[n:] = b[0:m];
n += m;
}else if(boff+nb > off){
if(n != 0)
error("bad count in utfrune");
m = nb - (off-boff);
if(m > count(x.fcall))
m = count(x.fcall);
b1[0:] = b[off-boff:off-boff+m];
n += m;
}
b = nil;
boff += nb;
q += nr;
}
strfree(r);
r = nil;
fc.count = n;
fc.data = b1;
respond(x, fc, nil);
b1 = nil;
}
Xfid.runeread(x : self ref Xfid, t : ref Text, q0, q1 : int) : int
{
fc : Smsg0;
w : ref Window;
r : ref Astring;
junk, ok : int;
b, b1 : array of byte;
q, boff : int;
i, rw, m, n, nr, nb : int;
w = t.w;
w.commit(t);
r = stralloc(BUFSIZE);
b1 = array[MAXRPC] of byte;
n = 0;
q = q0;
boff = 0;
while(q<q1 && n<count(x.fcall)){
nr = q1-q;
if(nr > BUFSIZE)
nr = BUFSIZE;
t.file.buf.read(q, r, 0, nr);
b = array of byte r.s[0:nr];
nb = len b;
m = nb;
if(boff+m > count(x.fcall)){
i = count(x.fcall) - boff;
# copy whole runes only
m = 0;
nr = 0;
while(m < i){
(junk, rw, ok) = sys->byte2char(b, m);
if(m+rw > i)
break;
m += rw;
nr++;
}
if(m == 0)
break;
}
b1[n:] = b[0:m];
b = nil;
n += m;
boff += nb;
q += nr;
}
strfree(r);
r = nil;
fc.count = n;
fc.data = b1;
respond(x, fc, nil);
b1 = nil;
return q-q0;
}
Xfid.eventread(x : self ref Xfid, w : ref Window)
{
fc : Smsg0;
b : string;
i, n : int;
i = 0;
x.flushed = FALSE;
while(w.nevents == 0){
if(i){
if(!x.flushed)
respond(x, fc, "window shut down");
return;
}
w.eventx = x;
w.unlock();
<- x.c;
w.lock('F');
i++;
}
eveb := array of byte w.events;
ne := len eveb;
n = w.nevents;
if(ne > count(x.fcall)) {
ne = count(x.fcall);
while (sys->utfbytes(eveb, ne) != ne)
--ne;
s := string eveb[0:ne];
n = len s;
s = nil;
}
fc.count = ne;
fc.data = eveb;
respond(x, fc, nil);
b = w.events;
w.events = w.events[n:];
b = nil;
w.nevents -= n;
eveb = nil;
}
Xfid.indexread(x : self ref Xfid)
{
fc : Smsg0;
i, j, m, n, nmax, cnt, off : int;
w : ref Window;
b : array of byte;
r : ref Astring;
c : ref Column;
row.qlock.lock();
nmax = 0;
for(j=0; j<row.ncol; j++){
c = row.col[j];
for(i=0; i<c.nw; i++){
w = c.w[i];
nmax += Ctlsize + w.tag.file.buf.nc*UTFmax + 1;
}
}
nmax++;
b = array[nmax] of byte;
r = stralloc(BUFSIZE);
n = 0;
for(j=0; j<row.ncol; j++){
c = row.col[j];
for(i=0; i<c.nw; i++){
w = c.w[i];
# only show the currently active window of a set
if(w.body.file.curtext != w.body)
continue;
ctls := w.ctlprint(0);
ctlb := array of byte ctls;
if (len ctls != Ctlsize || len ctlb != Ctlsize)
error("bad length in indexread");
b[n:] = ctlb[0:];
n += Ctlsize;
ctls = nil;
ctlb = nil;
m = min(BUFSIZE, w.tag.file.buf.nc);
w.tag.file.buf.read(0, r, 0, m);
rb := array of byte r.s[0:m];
b[n:] = rb[0:len rb];
m = n+len rb;
rb = nil;
while(n<m && b[n]!=byte '\n')
n++;
b[n++] = byte '\n';
}
}
row.qlock.unlock();
off = int offset(x.fcall);
cnt = count(x.fcall);
if(off > n)
off = n;
if(off+cnt > n)
cnt = n-off;
fc.count = cnt;
fc.data = b[off:off+cnt];
respond(x, fc, nil);
b = nil;
strfree(r);
r = nil;
}