# This module handles data for panels, including attributes. # It is not responsible for maintaining the tree and does not update qid.vers fields. # that's done by the file server code, in mero.b, with help from merotree. # The main panel logic is kept here. We load all mero panel modules found, # and link to their impl. Updating of data/ctl, and panel type checking is performed # by delegation to panel implementations loaded. Common attributes and data handling # is managed here. implement Panels; include "sys.m"; sys: Sys; sprint, open, OREAD, fprint: import sys; include "styx.m"; include "styxservers.m"; Styxserver: import Styxservers; include "daytime.m"; include "dat.m"; dat: Dat; mnt, evc, Qdir, debug, appl, slash: import dat; include "string.m"; str: String; include "names.m"; names: Names; dirname: import names; include "error.m"; err: Error; kill, checkload, error, panic, stderr: import err; include "readdir.m"; readdir: Readdir; include "tbl.m"; tbl: Tbl; Table: import tbl; include "mpanel.m"; panels : ref Table[ref Panel]; pgen := 0; # Panel id generator, for qids and hash values Impl: adt { prefs: list of string; mod: Pimpl; }; impls: list of ref Impl; dupwarn(prefs: list of string) { for (pl := prefs; pl != nil; pl = tl pl){ x := findimpl(hd pl); if (x != nil) fprint(stderr, "o/mero: warning: dup panel implementation: %s\n", hd pl); } } init(d: Dat, dir: string) { dat = d; sys = dat->sys; err = dat->err; str = dat->str; names = dat->names; tbl = checkload(load Tbl Tbl->PATH, Tbl->PATH); readdir = checkload(load Readdir Readdir->PATH, Readdir->PATH); np: ref Panel; np = nil; panels = Table[ref Panel].new(101, np); fd := open(dir, OREAD); if (fd == nil) error(sprint("can't open %s: %r", dir)); (dirs, n) := readdir->readall(fd, Readdir->NONE); if (n < 0) error(sprint("reading %s: %r", dir)); impls = nil; for (i := 0; i < n; i++){ nm := dirs[i].name; l := len nm; prefs: list of string; if (l > 7 && nm[0:3] == "omp" && nm[l-4:] == ".dis"){ path := dir + "/" + nm; if (debug) fprint(stderr, "loading %s\n", path); m := load Pimpl path; if (m == nil) fprint(stderr, "%s: %r\n", path); else if ((prefs = m->init(d)) == nil) fprint(stderr, "%s: panel init failed\n", path); else { dupwarn(prefs); impls = ref Impl(prefs, m) :: impls; } } } if (debug) fprint(stderr, "%d panels loaded\n", len impls); } dump() { fprint(stderr, "o/mero panels:\n"); for(i := 0; i < len panels.items; i++){ for (pl := panels.items[i]; pl != nil; pl = tl pl){ (nil, p) := hd pl; fprint(stderr, "%s\n", p.text()); } } } # debugging Panel.text(p: self ref Panel): string { if (p == nil) return "\n"; s := sprint("panel %d:\tcontainer=%d ", p.id, p.container); for (i := 0; i < len p.repl; i++) if ((r := p.repl[i]) != nil){ s += sprint("\n r%d:\tappl=%d path='%s'", r.id, r.tree, r.path); } return s; } Panel.ok(p: self ref Panel) { if (p.impl == nil) panic("no impl"); if (len p.repl > 0 && p.repl[0] == nil) panic("null repl 0"); for (i := 0; i < len p.repl; i++) if (p.repl[i] != nil&& p.repl[i].id != i) panic("bad repl index"); } findimpl(name: string): ref Impl { for (pl := impls; pl != nil; pl = tl pl){ impl := hd pl; for (nl := impl.prefs; nl != nil; nl = tl nl){ pref := hd nl; l := len pref; if (len name >= l && name[0:l] == pref) return impl; } } return nil; } nullpanel: Panel; Panel.new(name: string): ref Panel { i := findimpl(name); if (i == nil){ if (debug) fprint(stderr, "o/mero: bad panel type %s\n", name); return nil; } p := ref nullpanel; p.id = pgen++; p.name = name; p.impl = i.mod; p.impl->pinit(p); if (panels.add(p.id, p) < 0) panic("dup panel id"); if (debug) fprint(stderr, "o/mero: newpanel %s\n", p.name); return p; } Panel.lookup(id: int, rid: int): (ref Panel, ref Repl) { p := panels.find(id); r : ref Repl; if (p != nil){ p.ok(); if (rid >= 0 && rid . (32, 16, and 8 bits) # They are assigned by Panel.newrepl as replicas are being created. mkqid(id, rid, t: int): big { q := big id; q <<= 24; q |= big ((rid&16rFFFF)<<8); q |= big (t&16rFF); return q; } qid2ids(q: big): (int, int, int) { t := int (q & big 16rFF); q >>= 8; rid := int (q & big 16rFFFF); q >>= 16; id := int (q & big 16rFFFFFFFF); return (id, rid, t); } Panel.newrepl(p: self ref Panel, path: string, t: int): ref Repl { l := len p.repl; p.ok(); for (i := 0; i < l; i++) if (p.repl[i] == nil) break; if (i == l){ nr := array[l+3] of ref Repl; nr[0:] = p.repl; p.repl = nr; } q := mkqid(p.id, i, Qdir); attrs := array[] of { "notag", "show", "appl 0 -1"}; r := ref Repl(i, 0, 0, t, path, q, 0, attrs); p.nrepl++; p.repl[i] = r; if (r.id == 0) p.impl->rinit(p, r); else { r.attrs = array[len p.repl[0].attrs] of string; r.attrs[0:] = p.repl[0].attrs; } return r; } Panel.close(p: self ref Panel) { if (debug) fprint(stderr, "o/mero: close panel %s\n", p.name); for (i := 1; i < len p.repl; i++) if ((r := p.repl[i]) != nil) p.closerepl(r); if (p.repl[0] != nil) p.closerepl(p.repl[0]); x := panels.del(p.id); if (x != p) panic("Panel.close: bug"); } Panel.closerepl(p: self ref Panel, r: ref Repl) { p.ok(); if (p.repl[r.id] != r) panic("Panel.closerepl: bug"); p.repl[r.id] = nil; p.nrepl--; if (r.id != 0 && p.nrepl == 1) p.post("close"); } Repl.post(r: self ref Repl, pid: int, s: string) { evc <-= (pid, r.path, s); } Panel.post(p: self ref Panel, s: string) { r0 := p.repl[0]; evc <-= (p.pid, r0.path, sprint("%d %s", p.aid, s)); } Panel.vpost(p: self ref Panel, excl: ref Repl, s: string) { for (i := 0; i < len p.repl; i++) if (p.repl[i] != nil && (excl == nil || i != excl.id) && p.repl[i].tree == Trepl) p.repl[i].post(p.pid, s); } Panel.put(p: self ref Panel, data: array of byte, off: big): (int, string) { if (data == nil){ p.data = array[0] of byte; return (-1, "null data"); } o := int off; max := o + len data; if (max > 64 * 1024 * 1024) return (-1, "max data size exceeded"); if (max > len p.data){ ndata := array[max] of byte; ndata[0:] = p.data; ndata[o:] = data; p.data = ndata; } else p.data[o:] = data; return (len data, nil); } Panel.putimage(p: self ref Panel, data: array of byte, off: big): (int, string) { if (data == nil){ p.image = array[0] of byte; return(-1, "null data"); } o := int off; max := o + len data; if (max > 64 * 1024 * 1024) return (-1, "max data size exceeded"); if (max > len p.image){ ndata := array[max] of byte; ndata[0:] = p.image; ndata[o:] = data; p.image = ndata; } else p.image[o:] = data; return (len data, nil); } Panel.newdata(p: self ref Panel): string { e := p.impl->newdata(p); if (e != nil) p.data = array[0] of byte; return e; } # ins may contain spaces in its argument, and requires careful # processing here. mkinsargs(args: list of string, ctl: string): list of string { i := 0; while(ctl[i] == ' ') # initial blanks, if any i++; i += 3; # "ins" while(ctl[i] == ' ' || ctl[i] == '\t') # white space i++; while(ctl[i] != ' ' && ctl[i] != '\t') # pos i++; i++; # just one blank here! return list of {hd args, hd tl args, ctl[i:] }; } Panel.ctl(p: self ref Panel, r: ref Repl, ctl: string): (int, string) { if (r == nil) r = p.repl[0]; if (debug > 1) fprint(stderr, "o/mero: %s: ctl: %s\n", r.path, ctl); (nargs, args) := sys->tokenize(ctl, " \t\n"); if (nargs < 0 || args == nil) return (0, "no ctl"); if (hd args == "ins") args = mkinsargs(args, ctl); (n,e) := p.impl->ctl(p, r, args); if (e != nil && e == "not mine"){ i := -1; argl := global := 1; case hd args { "interrupt" => if (p.pid != -1) kill(p.pid, "killgrp"); "tag" or "notag" => i = Atag; "show" or "hide" => i = Ashow; global = 0; "layout" => i = Aappl; global = 0; "appl" => argl = 3; i = Aappl; global = 0; * => return (0, "no such attribute"); } if (nargs != argl) return (0, sprint("%d arguments needed", argl)); r.attrs[i] = ctl; # global or not. it's write through if (i == Aappl && argl == 3){ p.aid = int hd tl args; p.pid = int hd tl tl args; } if (r.id == 0 || global){ for (rn := 0; rn < len p.repl; rn++) if ((pr := p.repl[rn]) != nil) pr.attrs[i] = ctl; return (1, nil); } else return (0, nil); } else return (n, e); } # Attributes == actual attributes + copytos Panel.ctlstr(p: self ref Panel, r: ref Repl): string { p.ok(); s := ""; for(i := 0; i < len r.attrs; i++) if (r.attrs[i] != nil) s += r.attrs[i] + "\n"; if (r.id == 0){ for (i = 0; i < len p.repl; i++) if (p.repl[i] != nil && p.repl[i].tree != Tappl){ path := dirname(p.repl[i].path); s += sprint("copyto %s\n", path); } } return s; }