diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/acme/exec.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/acme/exec.b')
| -rw-r--r-- | appl/acme/exec.b | 1350 |
1 files changed, 1350 insertions, 0 deletions
diff --git a/appl/acme/exec.b b/appl/acme/exec.b new file mode 100644 index 00000000..204b6c37 --- /dev/null +++ b/appl/acme/exec.b @@ -0,0 +1,1350 @@ +implement Exec; + +include "common.m"; + +sys : Sys; +dat : Dat; +acme : Acme; +utils : Utils; +graph : Graph; +gui : Gui; +lookx : Look; +bufferm : Bufferm; +textm : Textm; +scrl : Scroll; +filem : Filem; +windowm : Windowm; +rowm : Rowm; +columnm : Columnm; +fsys : Fsys; +editm: Edit; + +Dir, OREAD, OWRITE : import Sys; +EVENTSIZE, QWaddr, QWdata, QWevent, Astring : import dat; +Lock, Reffont, Ref, seltext, seq, row : import dat; +warning, error, skipbl, findbl, stralloc, strfree, exec : import utils; +dirname : import lookx; +Body, Text : import textm; +File : import filem; +sprint : import sys; +TRUE, FALSE, XXX, BUFSIZE : import Dat; +Buffer : import bufferm; +Row : import rowm; +Column : import columnm; +Window : import windowm; +setalphabet: import textm; + +# snarfbuf : ref Buffer; + +init(mods : ref Dat->Mods) +{ + sys = mods.sys; + dat = mods.dat; + acme = mods.acme; + utils = mods.utils; + graph = mods.graph; + gui = mods.gui; + lookx = mods.look; + bufferm = mods.bufferm; + textm = mods.textm; + scrl = mods.scroll; + filem = mods.filem; + rowm = mods.rowm; + windowm = mods.windowm; + columnm = mods.columnm; + fsys = mods.fsys; + editm = mods.edit; + + snarfbuf = bufferm->newbuffer(); +} + +Exectab : adt { + name : string; + fun : int; + mark : int; + flag1 : int; + flag2 : int; +}; + +F_ALPHABET, F_CUT, F_DEL, F_DELCOL, F_DUMP, F_EDIT, F_EXITX, F_FONTX, F_GET, F_ID, F_INCL, F_KILL, F_LIMBO, F_LINENO, F_LOCAL, F_LOOK, F_NEW, F_NEWCOL, F_PASTE, F_PUT, F_PUTALL, F_UNDO, F_SEND, F_SORT, F_TAB, F_ZEROX : con iota; + +exectab := array[] of { + Exectab ( "Alphabet", F_ALPHABET, FALSE, XXX, XXX ), + Exectab ( "Cut", F_CUT, TRUE, TRUE, TRUE ), + Exectab ( "Del", F_DEL, FALSE, FALSE, XXX ), + Exectab ( "Delcol", F_DELCOL, FALSE, XXX, XXX ), + Exectab ( "Delete", F_DEL, FALSE, TRUE, XXX ), + Exectab ( "Dump", F_DUMP, FALSE, TRUE, XXX ), + Exectab ( "Edit", F_EDIT, FALSE, XXX, XXX ), + Exectab ( "Exit", F_EXITX, FALSE, XXX, XXX ), + Exectab ( "Font", F_FONTX, FALSE, XXX, XXX ), + Exectab ( "Get", F_GET, FALSE, TRUE, XXX ), + Exectab ( "ID", F_ID, FALSE, XXX, XXX ), + Exectab ( "Incl", F_INCL, FALSE, XXX, XXX ), + Exectab ( "Kill", F_KILL, FALSE, XXX, XXX ), + Exectab ( "Limbo", F_LIMBO, FALSE, XXX, XXX ), + Exectab ( "Lineno", F_LINENO, FALSE, XXX, XXX ), + Exectab ( "Load", F_DUMP, FALSE, FALSE, XXX ), + Exectab ( "Local", F_LOCAL, FALSE, XXX, XXX ), + Exectab ( "Look", F_LOOK, FALSE, XXX, XXX ), + Exectab ( "New", F_NEW, FALSE, XXX, XXX ), + Exectab ( "Newcol", F_NEWCOL, FALSE, XXX, XXX ), + Exectab ( "Paste", F_PASTE, TRUE, TRUE, XXX ), + Exectab ( "Put", F_PUT, FALSE, XXX, XXX ), + Exectab ( "Putall", F_PUTALL, FALSE, XXX, XXX ), + Exectab ( "Redo", F_UNDO, FALSE, FALSE, XXX ), + Exectab ( "Send", F_SEND, TRUE, XXX, XXX ), + Exectab ( "Snarf", F_CUT, FALSE, TRUE, FALSE ), + Exectab ( "Sort", F_SORT, FALSE, XXX, XXX ), + Exectab ( "Tab", F_TAB, FALSE, XXX, XXX ), + Exectab ( "Undo", F_UNDO, FALSE, TRUE, XXX ), + Exectab ( "Zerox", F_ZEROX, FALSE, XXX, XXX ), + Exectab ( nil, 0, 0, 0, 0 ), +}; + +runfun(fun : int, et, t, argt : ref Text, flag1, flag2 : int, arg : string, narg : int) +{ + case (fun) { + F_ALPHABET => alphabet(et, argt, arg, narg); + F_CUT => cut(et, t, flag1, flag2); + F_DEL => del(et, flag1); + F_DELCOL => delcol(et); + F_DUMP => dump(argt, flag1, arg, narg); + F_EDIT => edit(et, argt, arg, narg); + F_EXITX => exitx(); + F_FONTX => fontx(et, t, argt, arg, narg); + F_GET => get(et, t, argt, flag1, arg, narg); + F_ID => id(et); + F_INCL => incl(et, argt, arg, narg); + F_KILL => kill(argt, arg, narg); + F_LIMBO => limbo(et); + F_LINENO => lineno(et); + F_LOCAL => local(et, argt, arg); + F_LOOK => look(et, t, argt); + F_NEW => lookx->new(et, t, argt, flag1, flag2, arg, narg); + F_NEWCOL => newcol(et); + F_PASTE => paste(et, t, flag1, flag2); + F_PUT => put(et, argt, arg, narg); + F_PUTALL => putall(); + F_UNDO => undo(et, flag1); + F_SEND => send(et, t); + F_SORT => sort(et); + F_TAB => tab(et, argt, arg, narg); + F_ZEROX => zerox(et, t); + * => error("bad case in runfun()"); + } +} + +lookup(r : string, n : int) : int +{ + nr : int; + + (r, n) = skipbl(r, n); + if(n == 0) + return -1; + (nil, nr) = findbl(r, n); + nr = n-nr; + for(i := 0; exectab[i].name != nil; i++) + if (r[0:nr] == exectab[i].name) + return i; + return -1; +} + +isexecc(c : int) : int +{ + if(lookx->isfilec(c)) + return 1; + return c=='<' || c=='|' || c=='>'; +} + +execute(t : ref Text, aq0 : int, aq1 : int, external : int, argt : ref Text) +{ + q0, q1 : int; + r : ref Astring; + s, dir, aa, a : string; + e : int; + c, n, f : int; + + q0 = aq0; + q1 = aq1; + if(q1 == q0){ # expand to find word (actually file name) + # if in selection, choose selection + if(t.q1>t.q0 && t.q0<=q0 && q0<=t.q1){ + q0 = t.q0; + q1 = t.q1; + }else{ + while(q1<t.file.buf.nc && isexecc(c=t.readc(q1)) && c!=':') + q1++; + while(q0>0 && isexecc(c=t.readc(q0-1)) && c!=':') + q0--; + if(q1 == q0) + return; + } + } + r = stralloc(q1-q0); + t.file.buf.read(q0, r, 0, q1-q0); + e = lookup(r.s, q1-q0); + if(!external && t.w!=nil && t.w.nopen[QWevent]>byte 0){ + f = 0; + if(e >= 0) + f |= 1; + if(q0!=aq0 || q1!=aq1){ + t.file.buf.read(aq0, r, 0, aq1-aq0); + f |= 2; + } + (aa, a) = getbytearg(argt, TRUE, TRUE); + if(a != nil){ + if(len a > EVENTSIZE){ # too big; too bad + aa = a = nil; + warning(nil, "`argument string too long\n"); + return; + } + f |= 8; + } + c = 'x'; + if(t.what == Body) + c = 'X'; + n = aq1-aq0; + if(n <= EVENTSIZE) + t.w.event(sprint("%c%d %d %d %d %s\n", c, aq0, aq1, f, n, r.s[0:n])); + else + t.w.event(sprint("%c%d %d %d 0 \n", c, aq0, aq1, f)); + if(q0!=aq0 || q1!=aq1){ + n = q1-q0; + t.file.buf.read(q0, r, 0, n); + if(n <= EVENTSIZE) + t.w.event(sprint("%c%d %d 0 %d %s\n", c, q0, q1, n, r.s[0:n])); + else + t.w.event(sprint("%c%d %d 0 0 \n", c, q0, q1)); + } + if(a != nil){ + t.w.event(sprint("%c0 0 0 %d %s\n", c, len a, a)); + if(aa != nil) + t.w.event(sprint("%c0 0 0 %d %s\n", c, len aa, aa)); + else + t.w.event(sprint("%c0 0 0 0 \n", c)); + } + strfree(r); + r = nil; + a = aa = nil; + return; + } + if(e >= 0){ + if(exectab[e].mark && seltext!=nil) + if(seltext.what == Body){ + seq++; + seltext.w.body.file.mark(); + } + (s, n) = skipbl(r.s, q1-q0); + (s, n) = findbl(s, n); + (s, n) = skipbl(s, n); + runfun(exectab[e].fun, t, seltext, argt, exectab[e].flag1, exectab[e].flag2, s, n); + strfree(r); + r = nil; + return; + } + + (dir, n) = dirname(t, nil, 0); + if(n==1 && dir[0]=='.'){ # sigh + dir = nil; + n = 0; + } + (aa, a) = getbytearg(argt, TRUE, TRUE); + if(t.w != nil) + t.w.refx.inc(); + spawn run(t.w, r.s, dir, n, TRUE, aa, a, FALSE); +} + +printarg(argt : ref Text, q0 : int, q1 : int) : string +{ + buf : string; + + if(argt.what!=Body || argt.file.name==nil) + return nil; + if(q0 == q1) + buf = sprint("%s:#%d", argt.file.name, q0); + else + buf = sprint("%s:#%d,#%d", argt.file.name, q0, q1); + return buf; +} + +getarg(argt : ref Text, doaddr : int, dofile : int) : (string, string, int) +{ + r : ref Astring; + n : int; + e : Dat->Expand; + a : string; + ok : int; + + if(argt == nil) + return (nil, nil, 0); + a = nil; + argt.commit(TRUE); + (ok, e) = lookx->expand(argt, argt.q0, argt.q1); + if (ok) { + e.bname = nil; + if(len e.name && dofile){ + if(doaddr) + a = printarg(argt, e.q0, e.q1); + return (a, e.name, len e.name); + } + e.name = nil; + }else{ + e.q0 = argt.q0; + e.q1 = argt.q1; + } + n = e.q1 - e.q0; + r = stralloc(n); + argt.file.buf.read(e.q0, r, 0, n); + if(doaddr) + a = printarg(argt, e.q0, e.q1); + return(a, r.s, n); +} + +getbytearg(argt : ref Text, doaddr : int, dofile : int) : (string, string) +{ + r : string; + n : int; + aa : string; + + (aa, r, n) = getarg(argt, doaddr, dofile); + if(r == nil) + return (nil, nil); + return (aa, r); +} + +newcol(et : ref Text) +{ + c : ref Column; + + c = et.row.add(nil, -1); + if(c != nil) + c.add(nil, nil, -1).settag(); +} + +delcol(et : ref Text) +{ + c := et.col; + if(c==nil || !c.clean(FALSE)) + return; + for(i:=0; i<c.nw; i++){ + w := c.w[i]; + if(int w.nopen[QWevent]+int w.nopen[QWaddr]+int w.nopen[QWdata] > 0){ + warning(nil, sys->sprint("can't delete column; %s is running an external command\n", w.body.file.name)); + return; + } + } + c.row.close(c, TRUE); +} + +del(et : ref Text, flag1 : int) +{ + if(et.col==nil || et.w == nil) + return; + if(flag1 || et.w.body.file.ntext>1 || et.w.clean(FALSE, FALSE)) + et.col.close(et.w, TRUE); +} + +sort(et : ref Text) +{ + if(et.col != nil) + et.col.sort(); +} + +seqof(w: ref Window, isundo: int): int +{ + # if it's undo, see who changed with us + if(isundo) + return w.body.file.seq; + # if it's redo, see who we'll be sync'ed up with + return w.body.file.redoseq(); +} + +undo(et : ref Text, flag1 : int) +{ + i, j: int; + c: ref Column; + w: ref Window; + seq: int; + + if(et==nil || et.w== nil) + return; + seq = seqof(et.w, flag1); + for(i=0; i<row.ncol; i++){ + c = row.col[i]; + for(j=0; j<c.nw; j++){ + w = c.w[j]; + if(seqof(w, flag1) == seq) + w.undo(flag1); + } + } + # et.w.undo(flag1); +} + +getname(t : ref Text, argt : ref Text, arg : string, narg : int, isput : int) : string +{ + r, dir : string; + i, n, ndir, promote : int; + + (nil, r, n) = getarg(argt, FALSE, TRUE); + promote = FALSE; + if(r == nil) + promote = TRUE; + else if(isput){ + # if are doing a Put, want to synthesize name even for non-existent file + # best guess is that file name doesn't contain a slash + promote = TRUE; + for(i=0; i<n; i++) + if(r[i] == '/'){ + promote = FALSE; + break; + } + if(promote){ + t = argt; + arg = r; + narg = n; + } + } + if(promote){ + n = narg; + if(n <= 0) + return t.file.name; + # prefix with directory name if necessary + dir = nil; + ndir = 0; + if(n>0 && arg[0]!='/'){ + (dir, ndir) = dirname(t, nil, 0); + if(n==1 && dir[0]=='.'){ # sigh + dir = nil; + ndir = 0; + } + } + if(dir != nil){ + r = dir[0:ndir] + arg[0:n]; + dir = nil; + n += ndir; + }else + r = arg[0:n]; + } + return r; +} + +zerox(et : ref Text, t : ref Text) +{ + nw : ref Window; + c, locked : int; + + locked = FALSE; + if(t!=nil && t.w!=nil && t.w!=et.w){ + locked = TRUE; + c = 'M'; + if(et.w != nil) + c = et.w.owner; + t.w.lock(c); + } + if(t == nil) + t = et; + if(t==nil || t.w==nil) + return; + t = t.w.body; + if(t.w.isdir) + warning(nil, sprint("%s is a directory; Zerox illegal\n", t.file.name)); + else{ + nw = t.w.col.add(nil, t.w, -1); + # ugly: fix locks so w.unlock works + nw.lock1(t.w.owner); + } + if(locked) + t.w.unlock(); +} + +get(et : ref Text, t : ref Text, argt : ref Text, flag1 : int, arg : string, narg : int) +{ + name : string; + r : string; + i, n, dirty : int; + w : ref Window; + u : ref Text; + d : Dir; + ok : int; + + if(flag1) + if(et==nil || et.w==nil) + return; + if(!et.w.isdir && (et.w.body.file.buf.nc>0 && !et.w.clean(TRUE, FALSE))) + return; + w = et.w; + t = w.body; + name = getname(t, argt, arg, narg, FALSE); + if(name == nil){ + warning(nil, "no file name\n"); + return; + } + if(t.file.ntext>1){ + (ok, d) = sys->stat(name); + if (ok == 0 && d.qid.qtype & Sys->QTDIR) { + warning(nil, sprint("%s is a directory; can't read with multiple windows on it\n", name)); + return; + } + } + r = name; + n = len name; + for(i=0; i<t.file.ntext; i++){ + u = t.file.text[i]; + # second and subsequent calls with zero an already empty buffer, but OK + u.reset(); + u.w.dirfree(); + } + samename := r[0:n] == t.file.name; + t.loadx(0, name, samename); + if(samename){ + t.file.mod = FALSE; + dirty = FALSE; + }else{ + t.file.mod = TRUE; + dirty = TRUE; + } + for(i=0; i<t.file.ntext; i++) + t.file.text[i].w.dirty = dirty; + name = nil; + r = nil; + w.settag(); + t.file.unread = FALSE; + for(i=0; i<t.file.ntext; i++){ + u = t.file.text[i]; + u.w.tag.setselect(u.w.tag.file.buf.nc, u.w.tag.file.buf.nc); + scrl->scrdraw(u); + } +} + +putfile(f: ref File, q0: int, q1: int, name: string) +{ + n : int; + r, s : ref Astring; + w : ref Window; + i, q : int; + fd : ref Sys->FD; + d : Dir; + ok : int; + + w = f.curtext.w; + + { + if(name == f.name){ + (ok, d) = sys->stat(name); + if(ok >= 0 && (f.dev!=d.dev || f.qidpath!=d.qid.path || f.mtime<d.mtime)){ + f.dev = d.dev; + f.qidpath = d.qid.path; + f.mtime = d.mtime; + if(f.unread) + warning(nil, sys->sprint("%s not written; file already exists\n", name)); + else + warning(nil, sys->sprint("%s modified since last read\n", name)); + raise "e"; + } + } + fd = sys->create(name, OWRITE, 8r664); # was 666 + if(fd == nil){ + warning(nil, sprint("can't create file %s: %r\n", name)); + raise "e"; + } + r = stralloc(BUFSIZE); + s = stralloc(BUFSIZE); + + { + (ok, d) = sys->fstat(fd); + if(ok>=0 && (d.mode&Sys->DMAPPEND) && d.length>big 0){ + warning(nil, sprint("%s not written; file is append only\n", name)); + raise "e"; + } + for(q = q0; q < q1; q += n){ + n = q1 - q; + if(n > BUFSIZE) + n = BUFSIZE; + f.buf.read(q, r, 0, n); + ab := array of byte r.s[0:n]; + if(sys->write(fd, ab, len ab) != len ab){ + ab = nil; + warning(nil, sprint("can't write file %s: %r\n", name)); + raise "e"; + } + ab = nil; + } + if(name == f.name){ + d0 : Dir; + + if(q0 != 0 || q1 != f.buf.nc){ + f.mod = TRUE; + w.dirty = TRUE; + f.unread = TRUE; + } + else{ + (ok, d0) = sys->fstat(fd); # use old values if we failed + if (ok >= 0) + d = d0; + f.qidpath = d.qid.path; + f.dev = d.dev; + f.mtime = d.mtime; + f.mod = FALSE; + w.dirty = FALSE; + f.unread = FALSE; + } + for(i=0; i<f.ntext; i++){ + f.text[i].w.putseq = f.seq; + f.text[i].w.dirty = w.dirty; + } + } + strfree(s); + strfree(r); + s = r = nil; + name = nil; + fd = nil; + w.settag(); + } + exception{ + * => + strfree(s); + strfree(r); + s = r = nil; + fd = nil; + raise "e"; + } + } + exception{ + * => + name = nil; + return; + } +} + +put(et : ref Text, argt : ref Text, arg : string, narg : int) +{ + namer : string; + name : string; + w : ref Window; + + if(et==nil || et.w==nil || et.w.isdir) + return; + w = et.w; + f := w.body.file; + + name = getname(w.body, argt, arg, narg, TRUE); + if(name == nil){ + warning(nil, "no file name\n"); + return; + } + namer = name; + putfile(f, 0, f.buf.nc, namer); + name = nil; +} + +dump(argt : ref Text, isdump : int, arg : string, narg : int) +{ + name : string; + + if(narg) + name = arg; + else + (nil, name) = getbytearg(argt, FALSE, TRUE); + if(isdump) + row.dump(name); + else { + if (!row.qlock.locked()) + error("row not locked in dump()"); + row.loadx(name, FALSE); + } + name = nil; +} + +cut(et : ref Text, t : ref Text, dosnarf : int, docut : int) +{ + q0, q1, n, locked, c : int; + r : ref Astring; + + # use current window if snarfing and its selection is non-null + if(et!=t && dosnarf && et.w!=nil){ + if(et.w.body.q1>et.w.body.q0){ + t = et.w.body; + t.file.mark(); # seq has been incremented by execute + } + else if(et.w.tag.q1>et.w.tag.q0) + t = et.w.tag; + } + if(t == nil) + return; + locked = FALSE; + if(t.w!=nil && et.w!=t.w){ + locked = TRUE; + c = 'M'; + if(et.w != nil) + c = et.w.owner; + t.w.lock(c); + } + if(t.q0 == t.q1){ + if(locked) + t.w.unlock(); + return; + } + if(dosnarf){ + q0 = t.q0; + q1 = t.q1; + snarfbuf.delete(0, snarfbuf.nc); + r = stralloc(BUFSIZE); + while(q0 < q1){ + n = q1 - q0; + if(n > BUFSIZE) + n = BUFSIZE; + t.file.buf.read(q0, r, 0, n); + snarfbuf.insert(snarfbuf.nc, r.s, n); + q0 += n; + } + strfree(r); + r = nil; + acme->putsnarf(); + } + if(docut){ + t.delete(t.q0, t.q1, TRUE); + t.setselect(t.q0, t.q0); + if(t.w != nil){ + scrl->scrdraw(t); + t.w.settag(); + } + }else if(dosnarf) # Snarf command + dat->argtext = t; + if(locked) + t.w.unlock(); +} + +paste(et : ref Text, t : ref Text, selectall : int, tobody: int) +{ + c : int; + q, q0, q1, n : int; + r : ref Astring; + + # if(tobody), use body of executing window (Paste or Send command) + if(tobody && et!=nil && et.w!=nil){ + t = et.w.body; + t.file.mark(); # seq has been incremented by execute + } + if(t == nil) + return; + + acme->getsnarf(); + if(t==nil || snarfbuf.nc==0) + return; + if(t.w!=nil && et.w!=t.w){ + c = 'M'; + if(et.w != nil) + c = et.w.owner; + t.w.lock(c); + } + cut(t, t, FALSE, TRUE); + q = 0; + q0 = t.q0; + q1 = t.q0+snarfbuf.nc; + r = stralloc(BUFSIZE); + while(q0 < q1){ + n = q1 - q0; + if(n > BUFSIZE) + n = BUFSIZE; + if(r == nil) + r = stralloc(n); + snarfbuf.read(q, r, 0, n); + t.insert(q0, r.s, n, TRUE, 0); + q += n; + q0 += n; + } + strfree(r); + r = nil; + if(selectall) + t.setselect(t.q0, q1); + else + t.setselect(q1, q1); + if(t.w != nil){ + scrl->scrdraw(t); + t.w.settag(); + } + if(t.w!=nil && et.w!=t.w) + t.w.unlock(); +} + +look(et : ref Text, t : ref Text, argt : ref Text) +{ + r : string; + s : ref Astring; + n : int; + + if(et != nil && et.w != nil){ + t = et.w.body; + (nil, r, n) = getarg(argt, FALSE, FALSE); + if(r == nil){ + n = t.q1-t.q0; + s = stralloc(n); + t.file.buf.read(t.q0, s, 0, n); + r = s.s; + } + lookx->search(t, r, n); + r = nil; + } +} + +send(et : ref Text, t : ref Text) +{ + if(et.w==nil) + return; + t = et.w.body; + if(t.q0 != t.q1) + cut(t, t, TRUE, FALSE); + t.setselect(t.file.buf.nc, t.file.buf.nc); + paste(t, t, TRUE, TRUE); + if(t.readc(t.file.buf.nc-1) != '\n'){ + t.insert(t.file.buf.nc, "\n", 1, TRUE, 0); + t.setselect(t.file.buf.nc, t.file.buf.nc); + } +} + +edit(et: ref Text, argt: ref Text, arg: string, narg: int) +{ + r: string; + leng: int; + + if(et == nil) + return; + (nil, r, leng) = getarg(argt, FALSE, TRUE); + seq++; + if(r != nil){ + editm->editcmd(et, r, leng); + r = nil; + }else + editm->editcmd(et, arg, narg); +} + +exitx() +{ + if(row.clean(TRUE)) + acme->acmeexit(nil); +} + +putall() +{ + i, j, e : int; + w : ref Window; + c : ref Column; + a : string; + + for(i=0; i<row.ncol; i++){ + c = row.col[i]; + for(j=0; j<c.nw; j++){ + w = c.w[j]; + if(w.isscratch || w.isdir || len w.body.file.name==0) + continue; + if(w.nopen[QWevent] > byte 0) + continue; + a = w.body.file.name; + e = utils->access(a); + if(w.body.file.mod || w.body.ncache) + if(e < 0) + warning(nil, sprint("no auto-Put of %s: %r\n", a)); + else{ + w.commit(w.body); + put(w.body, nil, nil, 0); + } + a = nil; + } + } +} + +id(et : ref Text) +{ + if(et != nil && et.w != nil) + warning(nil, sprint("/mnt/acme/%d/\n", et.w.id)); +} + +limbo(et: ref Text) +{ + s := getname(et.w.body, nil, nil, 0, 0); + if(s == nil) + return; + for(l := len s; l > 0 && s[--l] != '/'; ) + ; + if(s[l] == '/') + s = s[l+1: ]; + s = "limbo -gw " + s; + (dir, n) := dirname(et, nil, 0); + if(n==1 && dir[0]=='.'){ # sigh + dir = nil; + n = 0; + } + spawn run(nil, s, dir, n, TRUE, nil, nil, FALSE); +} + +local(et : ref Text, argt : ref Text, arg : string) +{ + a, aa : string; + dir : string; + n : int; + + (aa, a) = getbytearg(argt, TRUE, TRUE); + + (dir, n) = dirname(et, nil, 0); + if(n==1 && dir[0]=='.'){ # sigh + dir = nil; + n = 0; + } + spawn run(nil, arg, dir, n, FALSE, aa, a, FALSE); +} + +kill(argt : ref Text, arg : string, narg : int) +{ + a, cmd, r : string; + na : int; + + (nil, r, na) = getarg(argt, FALSE, FALSE); + if(r != nil) + kill(nil, r, na); + # loop condition: *arg is not a blank + for(;;){ + (a, na) = findbl(arg, narg); + if(a == arg) + break; + cmd = arg[0:narg-na]; + dat->ckill <-= cmd; + (arg, narg) = skipbl(a, na); + } +} + +lineno(et : ref Text) +{ + n : int; + + if (et == nil || et.w == nil || (et = et.w.body) == nil) + return; + q0 := et.q0; + q1 := et.q1; + if (q0 < 0 || q1 < 0 || q0 > q1) + return; + ln0 := 1; + ln1 := 1; + rp := stralloc(BUFSIZE); + nc := et.file.buf.nc; + if (q0 >= nc) + q0 = nc-1; + if (q1 >= nc) + q1 = nc-1; + for (q := 0; q < q1; ) { + if (q+BUFSIZE > nc) + n = nc-q; + else + n = BUFSIZE; + et.file.buf.read(q, rp, 0, n); + for (i := 0; i < n && q < q1; i++) { + if (rp.s[i] == '\n') { + if (q < q0) + ln0++; + if (q < q1-1) + ln1++; + } + q++; + } + } + rp = nil; + if (et.file.name != nil) + file := et.file.name + ":"; + else + file = nil; + if (ln0 == ln1) + warning(nil, sprint("%s%d\n", file, ln0)); + else + warning(nil, sprint("%s%d,%d\n", file, ln0, ln1)); +} + +fontx(et : ref Text, t : ref Text, argt : ref Text, arg : string, narg : int) +{ + a, r, flag, file : string; + na, nf : int; + aa : string; + newfont : ref Reffont; + dp : ref Dat->Dirlist; + i, fix : int; + + if(et==nil || et.w==nil) + return; + t = et.w.body; + flag = nil; + file = nil; + # loop condition: *arg is not a blank + nf = 0; + for(;;){ + (a, na) = findbl(arg, narg); + if(a == arg) + break; + r = arg[0:narg-na]; + if(r == "fix" || r == "var"){ + flag = nil; + flag = r; + }else{ + file = r; + nf = narg-na; + } + (arg, narg) = skipbl(a, na); + } + (nil, r, na) = getarg(argt, FALSE, TRUE); + if(r != nil) + if(r == "fix" || r == "var"){ + flag = nil; + flag = r; + }else{ + file = r; + nf = na; + } + fix = 1; + if(flag != nil) + fix = flag == "fix"; + else if(file == nil){ + newfont = Reffont.get(FALSE, FALSE, FALSE, nil); + if(newfont != nil) + fix = newfont.f.name == t.frame.font.name; + } + if(file != nil){ + aa = file[0:nf]; + newfont = Reffont.get(fix, flag!=nil, FALSE, aa); + aa = nil; + }else + newfont = Reffont.get(fix, FALSE, FALSE, nil); + if(newfont != nil){ + graph->draw(gui->mainwin, t.w.r, acme->textcols[Framem->BACK], nil, (0, 0)); + t.reffont.close(); + t.reffont = newfont; + t.frame.font = newfont.f; + if(t.w.isdir){ + t.all.min.x++; # force recolumnation; disgusting! + for(i=0; i<t.w.ndl; i++){ + dp = t.w.dlp[i]; + aa = dp.r; + dp.wid = graph->strwidth(newfont.f, aa); + aa = nil; + } + } + # avoid shrinking of window due to quantization + t.w.col.grow(t.w, -1, 1); + } + file = nil; + flag = nil; +} + +incl(et : ref Text, argt : ref Text, arg : string, narg : int) +{ + a, r : string; + w : ref Window; + na, n, leng : int; + + if(et==nil || et.w==nil) + return; + w = et.w; + n = 0; + (nil, r, leng) = getarg(argt, FALSE, TRUE); + if(r != nil){ + n++; + w.addincl(r, leng); + } + # loop condition: *arg is not a blank + for(;;){ + (a, na) = findbl(arg, narg); + if(a == arg) + break; + r = arg[0:narg-na]; + n++; + w.addincl(r, narg-na); + (arg, narg) = skipbl(a, na); + } + if(n==0 && w.nincl){ + for(n=w.nincl; --n>=0; ) + warning(nil, sprint("%s ", w.incl[n])); + warning(nil, "\n"); + } +} + +tab(et : ref Text, argt : ref Text, arg : string, narg : int) +{ + a, r, p : string; + w : ref Window; + na, leng, tab : int; + + if(et==nil || et.w==nil) + return; + w = et.w; + (nil, r, leng) = getarg(argt, FALSE, TRUE); + tab = 0; + if(r!=nil && leng>0){ + p = r[0:leng]; + if('0'<=p[0] && p[0]<='9') + tab = int p; + p = nil; + }else{ + (a, na) = findbl(arg, narg); + if(a != arg){ + p = arg[0:narg-na]; + if('0'<=p[0] && p[0]<='9') + tab = int p; + p = nil; + } + } + if(tab > 0){ + if(w.body.tabstop != tab){ + w.body.tabstop = tab; + w.reshape(w.r, 1); + } + }else + warning(nil, sys->sprint("%s: Tab %d\n", w.body.file.name, w.body.tabstop)); +} + +alphabet(et: ref Text, argt: ref Text, arg: string, narg: int) +{ + r: string; + leng: int; + + if(et == nil) + return; + (nil, r, leng) = getarg(argt, FALSE, FALSE); + if(r != nil) + setalphabet(r[0:leng]); + else + setalphabet(arg[0:narg]); +} + +runfeed(p : array of ref Sys->FD, c : chan of int) +{ + n : int; + buf : array of byte; + s : string; + + sys->pctl(Sys->FORKFD, nil); + c <-= 1; + # p[1] = nil; + buf = array[256] of byte; + for(;;){ + if((n = sys->read(p[0], buf, 256)) <= 0) + break; + s = string buf[0:n]; + dat->cerr <-= s; + s = nil; + } + buf = nil; + exit; +} + +run(win : ref Window, s : string, rdir : string, ndir : int, newns : int, argaddr : string, arg : string, iseditcmd: int) +{ + c : ref Dat->Command; + name, dir : string; + e, t : int; + av : list of string; + r : int; + incl : array of string; + inarg, i, nincl : int; + tfd : ref Sys->FD; + p : array of ref Sys->FD; + pc : chan of int; + winid : int; + + c = ref Dat->Command; + t = 0; + while(t < len s && (s[t]==' ' || s[t]=='\n' || s[t]=='\t')) + t++; + for(e=t; e < len s; e++) + if(s[e]==' ' || s[e]=='\n' || s[e]=='\t' ) + break; + name = s[t:e]; + e = utils->strrchr(name, '/'); + if(e >= 0) + name = name[e+1:]; + name += " "; # add blank here for ease in waittask + c.name = name; + name = nil; + pipechar := 0; + if (t < len s && (s[t] == '<' || s[t] == '|' || s[t] == '>')){ + pipechar = s[t++]; + s = s[1: ]; + } + c.pid = sys->pctl(0, nil); + c.iseditcmd = iseditcmd; + c.text = s; + dat->ccommand <-= c; + # + # must pctl() after communication because rendezvous name + # space is part of RFNAMEG. + # + + if(newns){ + wids : string = ""; + filename: string; + + if(win != nil){ + filename = win.body.file.name; + wids = string win.id; + nincl = win.nincl; + incl = array[nincl] of string; + for(i=0; i<nincl; i++) + incl[i] = win.incl[i]; + winid = win.id; + win.close(); + }else{ + winid = 0; + nincl = 0; + incl = nil; + if(dat->activewin != nil) + winid = (dat->activewin).id; + } + # sys->pctl(Sys->FORKNS|Sys->FORKFD|Sys->NEWPGRP, nil); + sys->pctl(Sys->FORKNS|Sys->NEWFD|Sys->FORKENV|Sys->NEWPGRP, 0::1::2::fsys->fsyscfd()::nil); + if(rdir != nil){ + dir = rdir[0:ndir]; + sys->chdir(dir); # ignore error: probably app. window + dir = nil; + } + if(filename != nil) + utils->setenv("%", filename); + c.md = fsys->fsysmount(rdir, ndir, incl, nincl); + if(c.md == nil){ + # error("child: can't mount /mnt/acme"); + warning(nil, "can't mount /mnt/acme"); + exit; + } + if(winid > 0 && (pipechar=='|' || pipechar=='>')){ + buf := sys->sprint("/mnt/acme/%d/rdsel", winid); + tfd = sys->open(buf, OREAD); + } + else + tfd = sys->open("/dev/null", OREAD); + sys->dup(tfd.fd, 0); + tfd = nil; + if((winid > 0 || iseditcmd) && (pipechar=='|' || pipechar=='<')){ + buf: string; + + if(iseditcmd){ + if(winid > 0) + buf = sprint("/mnt/acme/%d/editout", winid); + else + buf = sprint("/mnt/acme/editout"); + } + else + buf = sys->sprint("/mnt/acme/%d/wrsel", winid); + tfd = sys->open(buf, OWRITE); + } + else + tfd = sys->open("/dev/cons", OWRITE); + sys->dup(tfd.fd, 1); + tfd = nil; + if(winid > 0 && (pipechar=='|' || pipechar=='<')){ + tfd = sys->open("/dev/cons", OWRITE); + sys->dup(tfd.fd, 2); + } + else + sys->dup(1, 2); + tfd = nil; + utils->setenv("acmewin", wids); + }else{ + if(win != nil) + win.close(); + sys->pctl(Sys->FORKFD|Sys->NEWPGRP, nil); + if(rdir != nil){ + dir = rdir[0:ndir]; + sys->chdir(dir); # ignore error: probably app. window + dir = nil; + } + p = array[2] of ref Sys->FD; + if(sys->pipe(p) < 0){ + error("child: can't pipe"); + exit; + } + pc = chan of int; + spawn runfeed(p, pc); + <-pc; + pc = nil; + fsys->fsysclose(); + tfd = sys->open("/dev/null", OREAD); + sys->dup(tfd.fd, 0); + tfd = nil; + sys->dup(p[1].fd, 1); + sys->dup(1, 2); + p[0] = p[1] = nil; + } + + if(argaddr != nil) + utils->setenv("acmeaddr", argaddr); + hard := 0; + if(len s > 512-10) # may need to print into stack + hard = 1; + else { + inarg = FALSE; + for(e=0; e < len s; e++){ + r = s[e]; + if(r==' ' || r=='\t') + continue; + if(r < ' ') { + hard = 1; + break; + } + if(utils->strchr("#;&|^$=`'{}()<>[]*?^~`", r) >= 0) { + hard = 1; + break; + } + inarg = TRUE; + } + if (!hard) { + if(!inarg) + exit; + av = nil; + sa := -1; + for(e=0; e < len s; e++){ + r = s[e]; + if(r==' ' || r=='\t'){ + if (sa >= 0) { + av = s[sa:e] :: av; + sa = -1; + } + continue; + } + if (sa < 0) + sa = e; + } + if (sa >= 0) + av = s[sa:e] :: av; + if (arg != nil) + av = arg :: av; + av = utils->reverse(av); + c.av = av; + exec(hd av, av); + dat->cwait <-= string c.pid + " \"Exec\":"; + exit; + } + } + + if(arg != nil){ + s = sprint("%s '%s'", s, arg); # BUG: what if quote in arg? + c.text = s; + } + av = nil; + av = s :: av; + av = "-c" :: av; + av = "/dis/sh" :: av; + exec(hd av, av); + dat->cwait <-= string c.pid + " \"Exec\":"; + exit; +} + +# Nasty bug causes +# Edit ,|nonexistentcommand +# (or ,> or ,<) to lock up acme. Easy fix. Add these two lines +# to the failure case of runwaittask(): +# +# /sys/src/cmd/acme/exec.c:1287 a exec.c:1288,1289 +# else{ +# if(c->iseditcmd) +# sendul(cedit, 0); +# free(c->name); +# free(c->text); +# free(c); +# } + + |
