ref: 82a3f55c5fb7b9f7a82449e4eb943c535ec3e491
parent: 8a788aea84aad3bfbd5b39d78c1925654f3b9e14
author: henesy <devnull@localhost>
date: Tue Mar 12 21:19:12 EDT 2019
add missing files ;; add pete whois/tac
--- /dev/null
+++ b/appl/cmd/disdep.b
@@ -1,0 +1,250 @@
+implement Disdep;
+
+#
+# Copyright © 2000 Vita Nuova Limited. All rights reserved.
+#
+
+include "sys.m";
+ sys: Sys;
+ print, sprint: import sys;
+
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+
+include "draw.m";
+
+include "string.m";
+ str: String;
+
+include "arg.m";
+ arg: Arg;
+
+include "dis.m";
+ dis: Dis;
+ Mod: import dis;
+
+include "hash.m";
+ hash: Hash;
+ HashTable, HashVal: import hash;
+
+Disdep: module
+{
+ init: fn(ctxt: ref Draw->Context, argv: list of string);
+};
+
+Item: adt {
+ name: string;
+ needs: cyclic list of ref Item;
+ visited: int;
+
+ find: fn(s: string): ref Item;
+};
+
+bout: ref Iobuf;
+pending: list of ref Item;
+roots: list of ref Item;
+tab: ref HashTable;
+aflag := 0; # display all non-recursive dependencies
+oflag := 0; # only list the immediate (outer) dependencies
+sflag := 0; # include $system modules
+pflag := 0; # show dependency sets as pairs, one per line
+showdepth := 0; # indent to show the dependency structure
+
+noload(mod: string)
+{
+ sys->fprint(sys->fildes(2), "disdep: can't load %s: %r\n", mod);
+ raise "fail:load";
+}
+
+usage()
+{
+ sys->fprint(sys->fildes(2), "Usage: disdep [-a] [-d] [-o] [-p] [-s] file.dis ...\n");
+ raise "fail:usage";
+}
+
+init(nil: ref Draw->Context, argv: list of string)
+{
+ sys = load Sys Sys->PATH;
+ bufio = load Bufio Bufio->PATH;
+ if(bufio == nil)
+ noload(Bufio->PATH);
+
+ str = load String String->PATH;
+ if(str == nil)
+ noload(String->PATH);
+
+ hash = load Hash Hash->PATH;
+ if(hash == nil)
+ noload(Hash->PATH);
+
+ arg = load Arg Arg->PATH;
+ if(arg == nil)
+ noload(Arg->PATH);
+
+ dis = load Dis Dis->PATH;
+ if(dis == nil)
+ noload(Dis->PATH);
+ dis->init();
+
+ arg->init(argv);
+ while((opt := arg->opt()) != 0)
+ case opt {
+ 'a' => aflag = 1; showdepth = 1;
+ 'o' => oflag = 1;
+ 's' => sflag = 1;
+ 'd' => showdepth = 1;
+ 'p' => pflag = 1;
+ * => usage();
+ }
+
+ argv = arg->argv();
+ if(argv == nil)
+ usage();
+
+ tab = hash->new(521);
+
+ bout = bufio->fopen(sys->fildes(1), Sys->OWRITE);
+ for(l := rev(argv); l != nil; l = tl l)
+ roots = Item.find(hd l) :: roots;
+ pending = roots;
+ while(pending != nil){
+ f := hd pending;
+ pending = tl pending;
+ (m, s) := dis->loadobj(f.name);
+ if(s != nil){
+ sys->fprint(sys->fildes(2), "disdep: can't open %s: %s\n", f.name, s);
+ continue;
+ }
+ f.needs = disfind(m);
+ for(nl := f.needs; nl != nil; nl = tl nl){
+ n := hd nl;
+ if(!n.visited){
+ n.visited = 1;
+ if(!oflag && !isdol(n.name))
+ pending = n :: pending;
+ }
+ }
+ }
+
+ if(pflag){
+ for(i := 0; i < nextitem; i++){
+ f := items[i];
+ if(f.needs != nil){
+ for(nl := f.needs; nl != nil; nl = tl nl){
+ bout.puts(f.name);
+ bout.putc(' ');
+ bout.puts((hd nl).name);
+ bout.putc('\n');
+ }
+ }else{
+ bout.puts(f.name);
+ bout.putc('\n');
+ }
+ }
+ }else{
+ unvisited();
+ for(; roots != nil; roots = tl roots){
+ if(aflag)
+ unvisited();
+ f := hd roots;
+ depth := 0;
+ if(showdepth){
+ bout.puts(f.name);
+ bout.putc('\n');
+ depth = 1;
+ }
+ prdep(hd roots, depth);
+ }
+ }
+ bout.flush();
+}
+
+disfind(m: ref Mod): list of ref Item
+{
+ needs: list of ref Item;
+ for(d := m.data; d != nil; d = tl d) {
+ pick dat := hd d {
+ String =>
+ if(isdisfile(dat.str) || sflag && isdol(dat.str))
+ needs = Item.find(dat.str) :: needs;
+ }
+ }
+ return rev(needs);
+}
+
+prdep(f: ref Item, depth: int)
+{
+ f.visited = 1; # short-circuit self-reference
+ for(nl := f.needs; nl != nil; nl = tl nl){
+ n := hd nl;
+ if(!n.visited){
+ n.visited = 1;
+ name(n.name, depth);
+ prdep(n, depth+1);
+ }else if(aflag)
+ name(n.name, depth);
+ }
+}
+
+items := array[100] of ref Item;
+nextitem := 0;
+
+Item.find(name: string): ref Item
+{
+ k := tab.find(name);
+ if(k != nil)
+ return items[k.i];
+ if(nextitem >= len items){
+ a := array[len items + 100] of ref Item;
+ a[0:] = items;
+ items = a;
+ }
+ f := ref Item;
+ f.name = name;
+ f.visited = 0;
+ items[nextitem] = f;
+ tab.insert(name, HashVal(nextitem, 0.0, nil));
+ nextitem++;
+ return f;
+}
+
+unvisited()
+{
+ for(i := 0; i < nextitem; i++)
+ items[i].visited = 0;
+}
+
+name(s: string, depth: int)
+{
+ if(showdepth)
+ for(i:=0; i<depth; i++)
+ bout.putc('\t');
+ bout.puts(s);
+ bout.putc('\n');
+}
+
+isdisfile(s: string): int
+{
+ if(len s > 4 && s[len s-4:]==".dis"){ # worth a look
+ for(i := 0; i < len s; i++)
+ if(s[i] <= ' ' || s[i] == '%')
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+isdol(s: string): int
+{
+ return len s > 1 && s[0] == '$' && s[1]>='A' && s[1]<='Z'; # reasonable guess
+}
+
+rev[T](l: list of T): list of T
+{
+ t: list of T;
+ for(; l != nil; l = tl l)
+ t = hd l :: t;
+ return t;
+}
+
--- /dev/null
+++ b/appl/cmd/disdump.b
@@ -1,0 +1,52 @@
+implement Disdump;
+
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "dis.m";
+ dis: Dis;
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+
+Disdump: module {
+ init: fn(nil: ref Draw->Context, argv: list of string);
+};
+
+init(nil: ref Draw->Context, argv: list of string)
+{
+ sys = load Sys Sys->PATH;
+ stderr := sys->fildes(2);
+ bufio = load Bufio Bufio->PATH;
+ if (bufio == nil) {
+ sys->fprint(stderr, "dis: cannot load %s: %r\n", Bufio->PATH);
+ raise "fail:bad module";
+ }
+
+ dis = load Dis Dis->PATH;
+ if (dis == nil) {
+ sys->fprint(stderr, "dis: cannot load %s: %r\n", Dis->PATH);
+ raise "fail:bad module";
+ }
+
+ if (len argv < 2) {
+ sys->fprint(stderr, "usage: dis module...\n");
+ raise "fail:usage";
+ }
+ dis->init();
+ out := bufio->fopen(sys->fildes(1), Sys->OWRITE);
+ errs := 0;
+ for (argv = tl argv; argv != nil; argv = tl argv) {
+ (mod, err) := dis->loadobj(hd argv);
+ if (mod == nil) {
+ sys->fprint(stderr, "dis: failed to load %s: %s\n", hd argv, err);
+ errs++;
+ continue;
+ }
+ for (i := 0; i < len mod.inst; i++)
+ out.puts(dis->inst2s(mod.inst[i])+"\n");
+ }
+ out.close();
+ if (errs)
+ raise "fail:errors";
+}
--- /dev/null
+++ b/appl/cmd/limbo/dis.b
@@ -1,0 +1,560 @@
+
+NAMELEN: con 28;
+
+cache: array of byte;
+ncached: int;
+ndatum: int;
+startoff: int;
+lastoff: int;
+lastkind: int;
+
+discon(val: int)
+{
+ if(val >= -64 && val <= 63){
+ bout.putb(byte (val & ~16r80));
+ return;
+ }
+ if(val >= -8192 && val <= 8191){
+ bout.putb(byte ((val>>8) & ~16rC0 | 16r80));
+ bout.putb(byte val);
+ return;
+ }
+ if(val < 0 && ((val >> 29) & 7) != 7
+ || val > 0 && (val >> 29) != 0)
+ fatal("overflow in constant 16r"+hex(val, 0));
+ bout.putb(byte(val>>24 | 16rC0));
+ bout.putb(byte(val>>16));
+ bout.putb(byte(val>>8));
+ bout.putb(byte val);
+}
+
+disword(w: int)
+{
+ bout.putb(byte(w >> 24));
+ bout.putb(byte(w >> 16));
+ bout.putb(byte(w >> 8));
+ bout.putb(byte w);
+}
+
+disdata(kind, n: int)
+{
+ if(n < DMAX && n != 0)
+ bout.putb(byte((kind << DBYTE) | n));
+ else{
+ bout.putb(byte kind << DBYTE);
+ discon(n);
+ }
+}
+
+dismod(m: ref Decl)
+{
+ fileoff := bout.seek(big 0, 1);
+ name := array of byte m.sym.name;
+ n := len name;
+ if(n > NAMELEN-1)
+ n = NAMELEN-1;
+ bout.write(name, n);
+ bout.putb(byte 0);
+ for(m = m.ty.tof.ids; m != nil; m = m.next){
+ case m.store{
+ Dglobal =>
+ discon(-1);
+ discon(-1);
+ disword(sign(m));
+ bout.puts(".mp");
+ bout.putb(byte 0);
+ Dfn =>
+ discon(m.pc.pc);
+ discon(m.desc.id);
+ disword(sign(m));
+ if(m.dot.ty.kind == Tadt){
+ bout.puts(m.dot.sym.name);
+ bout.putb(byte '.');
+ }
+ bout.puts(m.sym.name);
+ bout.putb(byte 0);
+ * =>
+ fatal("unknown kind in dismod: "+declconv(m));
+ }
+ }
+ if(debug['s'])
+ print("%bd linkage bytes start %bd\n", bout.seek(big 0, 1) - fileoff, fileoff);
+}
+
+dispath()
+{
+ sp := array of byte srcpath();
+ bout.write(sp, len sp);
+ bout.putb(byte 0);
+}
+
+disentry(e: ref Decl)
+{
+ if(e == nil){
+ discon(-1);
+ discon(-1);
+ return;
+ }
+ discon(e.pc.pc);
+ discon(e.desc.id);
+}
+
+disdesc(d: ref Desc)
+{
+ fileoff := bout.seek(big 0, 1);
+ for(; d != nil; d = d.next){
+ discon(d.id);
+ discon(d.size);
+ discon(d.nmap);
+ bout.write(d.map, d.nmap);
+ }
+ if(debug['s'])
+ print("%bd type descriptor bytes start %bd\n", bout.seek(big 0, 1) - fileoff, fileoff);
+}
+
+disvar(nil: int, ids: ref Decl)
+{
+ fileoff := bout.seek(big 0, 1);
+ lastkind = -1;
+ ncached = 0;
+ ndatum = 0;
+
+ for(d := ids; d != nil; d = d.next)
+ if(d.store == Dglobal && d.init != nil)
+ disdatum(d.offset, d.init);
+
+ disflush(-1, -1, 0);
+
+ bout.putb(byte 0);
+
+ if(debug['s'])
+ print("%bd data bytes start %bd\n", bout.seek(big 0, 1) - fileoff, fileoff);
+}
+
+disldt(size: int, ds: ref Decl)
+{
+ if(0){
+ discon(size);
+ disvar(size, ds);
+ return;
+ }
+
+ m := 0;
+ for(d := ds; d != nil; d = d.next)
+ if(d.store == Dglobal && d.init != nil)
+ m++;
+ discon(m);
+ n: ref Node;
+ for(d = ds; d != nil; d = d.next){
+ if(d.store == Dglobal && d.init != nil){
+ n = d.init;
+ if(n.ty.kind != Tiface)
+ nerror(n, "disldt: not Tiface");
+ discon(int n.c.val);
+ for(id := n.decl.ty.ids; id != nil; id = id.next){
+ disword(sign(id));
+ if(id.dot.ty.kind == Tadt){
+ s := array of byte id.dot.sym.name;
+ bout.write(s, len s);
+ bout.putb(byte '.');
+ }
+ s := array of byte id.sym.name;
+ bout.write(s, len s);
+ bout.putb(byte 0);
+ }
+ }
+ }
+ discon(0);
+}
+
+disdatum(offset: int, n: ref Node)
+{
+ c: ref Case;
+ lab: Label;
+ id: ref Decl;
+ wild: ref Node;
+ i, e: int;
+
+ case n.ty.kind{
+ Tbyte =>
+ disbyte(offset, byte n.c.val);
+ Tint or
+ Tfix =>
+ disint(offset, int n.c.val);
+ Tbig =>
+ disbig(offset, n.c.val);
+ Tstring =>
+ disstring(offset, n.decl.sym);
+ Treal =>
+ disreal(offset, n.c.rval);
+ Tadt or
+ Tadtpick or
+ Ttuple =>
+ id = n.ty.ids;
+ for(n = n.left; n != nil; n = n.right){
+ disdatum(offset + id.offset, n.left);
+ id = id.next;
+ }
+ Tany =>
+ break;
+ Tcase =>
+ c = n.ty.cse;
+ disint(offset, c.nlab);
+ offset += IBY2WD;
+ for(i = 0; i < c.nlab; i++){
+ lab = c.labs[i];
+ disint(offset, int lab.start.c.val);
+ offset += IBY2WD;
+ disint(offset, int lab.stop.c.val+1);
+ offset += IBY2WD;
+ disint(offset, lab.inst.pc);
+ offset += IBY2WD;
+ }
+ if(c.iwild != nil)
+ disint(offset, c.iwild.pc);
+ else
+ disint(offset, -1);
+ Tcasel =>
+ c = n.ty.cse;
+ disint(offset, c.nlab);
+ offset += 2*IBY2WD;
+ for(i = 0; i < c.nlab; i++){
+ lab = c.labs[i];
+ disbig(offset, lab.start.c.val);
+ offset += IBY2LG;
+ disbig(offset, lab.stop.c.val+big 1);
+ offset += IBY2LG;
+ disint(offset, lab.inst.pc);
+ offset += 2*IBY2WD;
+ }
+ if(c.iwild != nil)
+ disint(offset, c.iwild.pc);
+ else
+ disint(offset, -1);
+ Tcasec =>
+ c = n.ty.cse;
+ disint(offset, c.nlab);
+ offset += IBY2WD;
+ for(i = 0; i < c.nlab; i++){
+ lab = c.labs[i];
+ disstring(offset, lab.start.decl.sym);
+ offset += IBY2WD;
+ if(lab.stop != lab.start)
+ disstring(offset, lab.stop.decl.sym);
+ offset += IBY2WD;
+ disint(offset, lab.inst.pc);
+ offset += IBY2WD;
+ }
+ if(c.iwild != nil)
+ disint(offset, c.iwild.pc);
+ else
+ disint(offset, -1);
+ Tgoto =>
+ c = n.ty.cse;
+ disint(offset, n.ty.size/IBY2WD-1);
+ offset += IBY2WD;
+ for(i = 0; i < c.nlab; i++){
+ disint(offset, c.labs[i].inst.pc);
+ offset += IBY2WD;
+ }
+ if(c.iwild != nil)
+ disint(offset, c.iwild.pc);
+ Tarray =>
+ disflush(-1, -1, 0);
+ disdata(DEFA, 1); # 1 is ignored
+ discon(offset);
+ disword(n.ty.tof.decl.desc.id);
+ disword(int n.left.c.val);
+
+ if(n.right == nil)
+ break;
+
+ disdata(DIND, 1); # 1 is ignored
+ discon(offset);
+ disword(0);
+
+ c = n.right.ty.cse;
+ wild = nil;
+ if(c.wild != nil)
+ wild = c.wild.right;
+ last := 0;
+ esz := n.ty.tof.size;
+ for(i = 0; i < c.nlab; i++){
+ e = int c.labs[i].start.c.val;
+ if(wild != nil){
+ for(; last < e; last++)
+ disdatum(esz * last, wild);
+ }
+ last = e;
+ e = int c.labs[i].stop.c.val;
+ elem := c.labs[i].node.right;
+ for(; last <= e; last++)
+ disdatum(esz * last, elem);
+ }
+ if(wild != nil)
+ for(e = int n.left.c.val; last < e; last++)
+ disdatum(esz * last, wild);
+
+ disflush(-1, -1, 0);
+ disdata(DAPOP, 1); # 1 is ignored
+ discon(0);
+ Tiface =>
+ disint(offset, int n.c.val);
+ offset += IBY2WD;
+ for(id = n.decl.ty.ids; id != nil; id = id.next){
+ offset = align(offset, IBY2WD);
+ disint(offset, sign(id));
+ offset += IBY2WD;
+
+ name: array of byte;
+ if(id.dot.ty.kind == Tadt){
+ name = array of byte id.dot.sym.name;
+ disbytes(offset, name);
+ offset += len name;
+ disbyte(offset, byte '.');
+ offset++;
+ }
+ name = array of byte id.sym.name;
+ disbytes(offset, name);
+ offset += len name;
+ disbyte(offset, byte 0);
+ offset++;
+ }
+ * =>
+ fatal("can't gen global "+nodeconv(n));
+ }
+}
+
+disexc(es: ref Except)
+{
+ e: ref Except;
+
+ n := 0;
+ for(e = es; e != nil; e = e.next)
+ if(int e.p1.reach || int e.p2.reach)
+ n++;
+ discon(n);
+ for(e = es; e != nil; e = e.next){
+ if(!int e.p1.reach && !int e.p2.reach)
+ continue;
+ c := e.c;
+ discon(e.d.offset);
+ discon(getpc(e.p1));
+ discon(getpc(e.p2));
+ if(e.desc != nil)
+ discon(e.desc.id);
+ else
+ discon(-1);
+ discon(c.nlab|(e.ne<<16));
+ for(i := 0; i < c.nlab; i++){
+ lab := c.labs[i];
+ d := lab.start.decl;
+ if(lab.start.ty.kind == Texception)
+ d = d.init.decl;
+ bout.puts(d.sym.name);
+ bout.putb(byte 0);
+ discon(lab.inst.pc);
+ }
+ if(c.iwild == nil)
+ discon(-1);
+ else
+ discon(c.iwild.pc);
+ }
+ discon(0);
+}
+
+disbyte(off: int, v: byte)
+{
+ disflush(DEFB, off, 1);
+ cache[ncached++] = v;
+ ndatum++;
+}
+
+disbytes(off: int, v: array of byte)
+{
+ n := len v;
+ disflush(DEFB, off, n);
+ cache[ncached:] = v;
+ ncached += n;
+ ndatum += n;
+}
+
+disint(off, v: int)
+{
+ disflush(DEFW, off, IBY2WD);
+ cache[ncached++] = byte(v >> 24);
+ cache[ncached++] = byte(v >> 16);
+ cache[ncached++] = byte(v >> 8);
+ cache[ncached++] = byte(v);
+ ndatum++;
+}
+
+disbig(off: int, v: big)
+{
+ disflush(DEFL, off, IBY2LG);
+ iv := int(v >> 32);
+ cache[ncached++] = byte(iv >> 24);
+ cache[ncached++] = byte(iv >> 16);
+ cache[ncached++] = byte(iv >> 8);
+ cache[ncached++] = byte(iv);
+ iv = int v;
+ cache[ncached++] = byte(iv >> 24);
+ cache[ncached++] = byte(iv >> 16);
+ cache[ncached++] = byte(iv >> 8);
+ cache[ncached++] = byte(iv);
+ ndatum++;
+}
+
+disreal(off: int, v: real)
+{
+ disflush(DEFF, off, IBY2LG);
+ export_real(cache[ncached:ncached+8], array[] of {v});
+ ncached += IBY2LG;
+ ndatum++;
+}
+
+disstring(offset: int, sym: ref Sym)
+{
+ disflush(-1, -1, 0);
+ d := array of byte sym.name;
+ disdata(DEFS, len d);
+ discon(offset);
+ bout.write(d, len d);
+}
+
+disflush(kind, off, size: int)
+{
+ if(kind != lastkind || off != lastoff){
+ if(lastkind != -1 && ncached){
+ disdata(lastkind, ndatum);
+ discon(startoff);
+ bout.write(cache, ncached);
+ }
+ startoff = off;
+ lastkind = kind;
+ ncached = 0;
+ ndatum = 0;
+ }
+ lastoff = off + size;
+ while(kind >= 0 && ncached + size >= len cache){
+ c := array[ncached + 1024] of byte;
+ c[0:] = cache;
+ cache = c;
+ }
+}
+
+dismode := array[int Aend] of
+{
+ int Aimm => byte AIMM,
+ int Amp => byte AMP,
+ int Ampind => byte(AMP|AIND),
+ int Afp => byte AFP,
+ int Afpind => byte(AFP|AIND),
+ int Apc => byte AIMM,
+ int Adesc => byte AIMM,
+ int Aoff => byte AIMM,
+ int Anoff => byte AIMM,
+ int Aerr => byte AXXX,
+ int Anone => byte AXXX,
+ int Aldt => byte AIMM,
+};
+
+disregmode := array[int Aend] of
+{
+ int Aimm => byte AXIMM,
+ int Amp => byte AXINM,
+ int Ampind => byte AXNON,
+ int Afp => byte AXINF,
+ int Afpind => byte AXNON,
+ int Apc => byte AXIMM,
+ int Adesc => byte AXIMM,
+ int Aoff => byte AXIMM,
+ int Anoff => byte AXIMM,
+ int Aerr => byte AXNON,
+ int Anone => byte AXNON,
+ int Aldt => byte AXIMM,
+};
+
+MAXCON: con 4;
+MAXADDR: con 2*MAXCON;
+MAXINST: con 3*MAXADDR+2;
+NIBUF: con 1024;
+
+ibuf: array of byte;
+nibuf: int;
+
+disinst(in: ref Inst)
+{
+ fileoff := bout.seek(big 0, 1);
+ ibuf = array[NIBUF] of byte;
+ nibuf = 0;
+ for(; in != nil; in = in.next){
+ if(in.op == INOOP)
+ continue;
+ if(nibuf >= NIBUF-MAXINST){
+ bout.write(ibuf, nibuf);
+ nibuf = 0;
+ }
+ ibuf[nibuf++] = byte in.op;
+ o := dismode[int in.sm] << SRC;
+ o |= dismode[int in.dm] << DST;
+ o |= disregmode[int in.mm];
+ ibuf[nibuf++] = o;
+ if(in.mm != Anone)
+ disaddr(in.mm, in.m);
+ if(in.sm != Anone)
+ disaddr(in.sm, in.s);
+ if(in.dm != Anone)
+ disaddr(in.dm, in.d);
+ }
+ if(nibuf > 0)
+ bout.write(ibuf, nibuf);
+ ibuf = nil;
+
+ if(debug['s'])
+ print("%bd instruction bytes start %bd\n", bout.seek(big 0, 1) - fileoff, fileoff);
+}
+
+disaddr(m: byte, a: Addr)
+{
+ val := 0;
+ case int m{
+ int Aimm or
+ int Apc or
+ int Adesc =>
+ val = a.offset;
+ int Aoff =>
+ val = a.decl.iface.offset;
+ int Anoff =>
+ val = -(a.decl.iface.offset+1);
+ int Afp or
+ int Amp or
+ int Aldt =>
+ val = a.reg;
+ int Afpind or
+ int Ampind =>
+ disbcon(a.reg);
+ val = a.offset;
+ }
+ disbcon(val);
+}
+
+disbcon(val: int)
+{
+ if(val >= -64 && val <= 63){
+ ibuf[nibuf++] = byte(val & ~16r80);
+ return;
+ }
+ if(val >= -8192 && val <= 8191){
+ ibuf[nibuf++] = byte(val>>8 & ~16rC0 | 16r80);
+ ibuf[nibuf++] = byte val;
+ return;
+ }
+ if(val < 0 && ((val >> 29) & 7) != 7
+ || val > 0 && (val >> 29) != 0)
+ fatal("overflow in constant 16r"+hex(val, 0));
+ ibuf[nibuf++] = byte(val>>24 | 16rC0);
+ ibuf[nibuf++] = byte(val>>16);
+ ibuf[nibuf++] = byte(val>>8);
+ ibuf[nibuf++] = byte val;
+}
--- /dev/null
+++ b/appl/cmd/limbo/disoptab.m
@@ -1,0 +1,355 @@
+movetab:= array [Mend]of
+{
+ Mas => array[Tend] of
+ {
+ Tadt => IMOVM,
+ Tadtpick => IMOVM,
+ Tarray => IMOVP,
+ Tbig => IMOVL,
+ Tbyte => IMOVB,
+ Tchan => IMOVP,
+ Treal => IMOVF,
+ Tint => IMOVW,
+ Tlist => IMOVP,
+ Tmodule => IMOVP,
+ Tref => IMOVP,
+ Tstring => IMOVP,
+ Ttuple => IMOVM,
+ Texception => IMOVM,
+ Tfix => IMOVW,
+ Tpoly => IMOVP,
+
+ Tany => IMOVP,
+
+ * => 0
+ },
+ Mcons => array[Tend] of
+ {
+ Tadt => ICONSM,
+ Tadtpick => 0,
+ Tarray => ICONSP,
+ Tbig => ICONSL,
+ Tbyte => ICONSB,
+ Tchan => ICONSP,
+ Treal => ICONSF,
+ Tint => ICONSW,
+ Tlist => ICONSP,
+ Tmodule => ICONSP,
+ Tref => ICONSP,
+ Tstring => ICONSP,
+ Ttuple => ICONSM,
+ Texception => ICONSM,
+ Tfix => ICONSW,
+ Tpoly => ICONSP,
+
+ Tany => ICONSP,
+
+ * => 0
+ },
+ Mhd => array[Tend] of
+ {
+ Tadt => IHEADM,
+ Tadtpick => 0,
+ Tarray => IHEADP,
+ Tbig => IHEADL,
+ Tbyte => IHEADB,
+ Tchan => IHEADP,
+ Treal => IHEADF,
+ Tint => IHEADW,
+ Tlist => IHEADP,
+ Tmodule => IHEADP,
+ Tref => IHEADP,
+ Tstring => IHEADP,
+ Ttuple => IHEADM,
+ Texception => IHEADM,
+ Tfix => IHEADW,
+ Tpoly => IHEADP,
+
+ Tany => IHEADP,
+
+ * => 0
+ },
+ Mtl => array[Tend] of
+ {
+ Tlist => ITAIL,
+
+ * => 0
+ },
+};
+
+chantab := array[Tend] of
+{
+ Tadt => INEWCM,
+ Tadtpick => 0,
+ Tarray => INEWCP,
+ Tbig => INEWCL,
+ Tbyte => INEWCB,
+ Tchan => INEWCP,
+ Treal => INEWCF,
+ Tint => INEWCW,
+ Tlist => INEWCP,
+ Tmodule => INEWCP,
+ Tref => INEWCP,
+ Tstring => INEWCP,
+ Ttuple => INEWCM,
+ Texception => INEWCM,
+ Tfix => INEWCW,
+ Tpoly => INEWCP,
+
+ Tany => INEWCP,
+
+ * => 0
+};
+
+opind := array[Tend] of
+{
+ Tbyte => 1,
+ Tint => 2,
+ Tbig => 3,
+ Treal => 4,
+ Tstring => 5,
+ Tfix => 6,
+
+ * => 0
+};
+
+disoptab := array[Oend+1] of
+{
+ # opcode default byte word big real string fixed
+ Oadd => array[7] of {0, IADDB, IADDW, IADDL, IADDF, IADDC, IADDW,},
+ Oaddas => array[7] of {0, IADDB, IADDW, IADDL, IADDF, IADDC, IADDW,},
+ Oand => array[7] of {0, IANDB, IANDW, IANDL, 0, 0, 0,},
+ Oandas => array[7] of {0, IANDB, IANDW, IANDL, 0, 0, 0,},
+ Odec => array[7] of {0, ISUBB, ISUBW, ISUBL, ISUBF, 0, ISUBW,},
+ Odiv => array[7] of {0, IDIVB, IDIVW, IDIVL, IDIVF, 0, IDIVX,},
+ Odivas => array[7] of {0, IDIVB, IDIVW, IDIVL, IDIVF, 0, IDIVX,},
+ Oeq => array[7] of {IBEQW, IBEQB, IBEQW, IBEQL, IBEQF, IBEQC, IBEQW,},
+ Oexp => array[7] of {0, 0, IEXPW, IEXPL, IEXPF, 0, 0,},
+ Oexpas => array[7] of {0, 0, IEXPW, IEXPL, IEXPF, 0, 0,},
+ Ogeq => array[7] of {0, IBGEB, IBGEW, IBGEL, IBGEF, IBGEC, IBGEW,},
+ Ogt => array[7] of {0, IBGTB, IBGTW, IBGTL, IBGTF, IBGTC, IBGTW,},
+ Oinc => array[7] of {0, IADDB, IADDW, IADDL, IADDF, 0, IADDW,},
+ Oinds => array[7] of {0, 0, IINDC, 0, 0, 0, 0,},
+ Oindx => array[7] of {0, 0, IINDX, 0, 0, 0, 0,},
+ Olen => array[7] of {ILENA, 0, 0, 0, 0, ILENC, 0,},
+ Oleq => array[7] of {0, IBLEB, IBLEW, IBLEL, IBLEF, IBLEC, IBLEW,},
+ Olsh => array[7] of {0, ISHLB, ISHLW, ISHLL, 0, 0, 0,},
+ Olshas => array[7] of {0, ISHLB, ISHLW, ISHLL, 0, 0, 0,},
+ Olt => array[7] of {0, IBLTB, IBLTW, IBLTL, IBLTF, IBLTC, IBLTW,},
+ Omod => array[7] of {0, IMODB, IMODW, IMODL, 0, 0, 0,},
+ Omodas => array[7] of {0, IMODB, IMODW, IMODL, 0, 0, 0,},
+ Omul => array[7] of {0, IMULB, IMULW, IMULL, IMULF, 0, IMULX,},
+ Omulas => array[7] of {0, IMULB, IMULW, IMULL, IMULF, 0, IMULX,},
+ Oneg => array[7] of {0, 0, 0, 0, INEGF, 0, 0, },
+ Oneq => array[7] of {IBNEW, IBNEB, IBNEW, IBNEL, IBNEF, IBNEC, IBNEW,},
+ Oor => array[7] of {0, IORB, IORW, IORL, 0, 0, 0,},
+ Ooras => array[7] of {0, IORB, IORW, IORL, 0, 0, 0,},
+ Orsh => array[7] of {0, ISHRB, ISHRW, ISHRL, 0, 0, 0,},
+ Orshas => array[7] of {0, ISHRB, ISHRW, ISHRL, 0, 0, 0,},
+ Oslice => array[7] of {ISLICEA,0, 0, 0, 0, ISLICEC, 0,},
+ Osub => array[7] of {0, ISUBB, ISUBW, ISUBL, ISUBF, 0, ISUBW,},
+ Osubas => array[7] of {0, ISUBB, ISUBW, ISUBL, ISUBF, 0, ISUBW,},
+ Oxor => array[7] of {0, IXORB, IXORW, IXORL, 0, 0, 0,},
+ Oxoras => array[7] of {0, IXORB, IXORW, IXORL, 0, 0, 0,},
+};
+
+isbyteinst := array [256] of
+{
+ IMULB => 1,
+ ISUBB => 1,
+ IADDB => 1,
+ IDIVB => 1,
+ IORB => 1,
+ IXORB => 1,
+ ISHLB => 1,
+ ISHRB => 1,
+ IMODB => 1,
+ IANDB => 1,
+ IBEQB => 1,
+ IBNEB => 1,
+ IBLTB => 1,
+ IBLEB => 1,
+ IBGTB => 1,
+ IBGEB => 1,
+
+ * => 0,
+};
+
+instname := array[256] of
+{
+ "nop",
+ "alt",
+ "nbalt",
+ "goto",
+ "call",
+ "frame",
+ "spawn",
+ "runt",
+ "load",
+ "mcall",
+ "mspawn",
+ "mframe",
+ "ret",
+ "jmp",
+ "case",
+ "exit",
+ "new",
+ "newa",
+ "newcb",
+ "newcw",
+ "newcf",
+ "newcp",
+ "newcm",
+ "newcmp",
+ "send",
+ "recv",
+ "consb",
+ "consw",
+ "consp",
+ "consf",
+ "consm",
+ "consmp",
+ "headb",
+ "headw",
+ "headp",
+ "headf",
+ "headm",
+ "headmp",
+ "tail",
+ "lea",
+ "indx",
+ "movp",
+ "movm",
+ "movmp",
+ "movb",
+ "movw",
+ "movf",
+ "cvtbw",
+ "cvtwb",
+ "cvtfw",
+ "cvtwf",
+ "cvtca",
+ "cvtac",
+ "cvtwc",
+ "cvtcw",
+ "cvtfc",
+ "cvtcf",
+ "addb",
+ "addw",
+ "addf",
+ "subb",
+ "subw",
+ "subf",
+ "mulb",
+ "mulw",
+ "mulf",
+ "divb",
+ "divw",
+ "divf",
+ "modw",
+ "modb",
+ "andb",
+ "andw",
+ "orb",
+ "orw",
+ "xorb",
+ "xorw",
+ "shlb",
+ "shlw",
+ "shrb",
+ "shrw",
+ "insc",
+ "indc",
+ "addc",
+ "lenc",
+ "lena",
+ "lenl",
+ "beqb",
+ "bneb",
+ "bltb",
+ "bleb",
+ "bgtb",
+ "bgeb",
+ "beqw",
+ "bnew",
+ "bltw",
+ "blew",
+ "bgtw",
+ "bgew",
+ "beqf",
+ "bnef",
+ "bltf",
+ "blef",
+ "bgtf",
+ "bgef",
+ "beqc",
+ "bnec",
+ "bltc",
+ "blec",
+ "bgtc",
+ "bgec",
+ "slicea",
+ "slicela",
+ "slicec",
+ "indw",
+ "indf",
+ "indb",
+ "negf",
+ "movl",
+ "addl",
+ "subl",
+ "divl",
+ "modl",
+ "mull",
+ "andl",
+ "orl",
+ "xorl",
+ "shll",
+ "shrl",
+ "bnel",
+ "bltl",
+ "blel",
+ "bgtl",
+ "bgel",
+ "beql",
+ "cvtlf",
+ "cvtfl",
+ "cvtlw",
+ "cvtwl",
+ "cvtlc",
+ "cvtcl",
+ "headl",
+ "consl",
+ "newcl",
+ "casec",
+ "indl",
+ "movpc",
+ "tcmp",
+ "mnewz",
+ "cvtrf",
+ "cvtfr",
+ "cvtws",
+ "cvtsw",
+ "lsrw",
+ "lsrl",
+ "eclr",
+ "newz",
+ "newaz",
+ "raise",
+ "casel",
+ "mulx",
+ "divx",
+ "cvtxx",
+ "mulx0",
+ "divx0",
+ "cvtxx0",
+ "mulx1",
+ "divx1",
+ "cvtxx1",
+ "cvtfx",
+ "cvtxf",
+ "expw",
+ "expl",
+ "expf",
+ "self",
+};
--- /dev/null
+++ b/appl/cmd/limbo/sbl.b
@@ -1,0 +1,397 @@
+
+sbltname := array[Tend] of
+{
+ Tnone => byte 'n',
+ Tadt => byte 'a',
+ Tadtpick => byte 'a',
+ Tarray => byte 'A',
+ Tbig => byte 'B',
+ Tbyte => byte 'b',
+ Tchan => byte 'C',
+ Treal => byte 'f',
+ Tfn => byte 'F',
+ Tint => byte 'i',
+ Tlist => byte 'L',
+ Tmodule => byte 'm',
+ Tref => byte 'R',
+ Tstring => byte 's',
+ Ttuple => byte 't',
+ Texception => byte 't',
+ Tfix => byte 'i',
+ Tpoly => byte 'P',
+
+ Tainit => byte '?',
+ Talt => byte '?',
+ Tany => byte 'N',
+ Tarrow => byte '?',
+ Tcase => byte '?',
+ Tcasel => byte '?',
+ Tcasec => byte '?',
+ Tdot => byte '?',
+ Terror => byte '?',
+ Tgoto => byte '?',
+ Tid => byte '?',
+ Tiface => byte '?',
+ Texcept => byte '?',
+ Tinst => byte '?',
+};
+sbltadtpick: con byte 'p';
+
+sfiles: ref Sym;
+ftail: ref Sym;
+nsfiles: int;
+blockid: int;
+lastf: int;
+lastline: int;
+
+MAXSBLINT: con 12;
+MAXSBLSRC: con 6*(MAXSBLINT+1);
+
+sblmod(m: ref Decl)
+{
+ bsym.puts("limbo .sbl 2.1\n");
+ bsym.puts(m.sym.name);
+ bsym.putb(byte '\n');
+
+ blockid = 0;
+ nsfiles = 0;
+ sfiles = ftail = nil;
+ lastf = 0;
+ lastline = 0;
+}
+
+sblfile(name: string): int
+{
+ i := 0;
+ for(s := sfiles; s != nil; s = s.next){
+ if(s.name == name)
+ return i;
+ i++;
+ }
+ s = ref Sym;
+ s.name = name;
+ s.next = nil;
+ if(sfiles == nil)
+ sfiles = s;
+ else
+ ftail.next = s;
+ ftail = s;
+ nsfiles = i + 1;
+ return i;
+}
+
+filename(s: string): string
+{
+ (nil, file) := str->splitr(s, "/ \\");
+ return file;
+}
+
+sblfiles()
+{
+ for(i := 0; i < nfiles; i++)
+ files[i].sbl = sblfile(files[i].name);
+ bsym.puts(string nsfiles);
+ bsym.putb(byte '\n');
+ for(s := sfiles; s != nil; s = s.next){
+ bsym.puts(filename(s.name));
+ bsym.putb(byte '\n');
+ }
+}
+
+sblint(buf: array of byte, off, v: int): int
+{
+ if(v == 0){
+ buf[off++] = byte '0';
+ return off;
+ }
+ stop := off + MAXSBLINT;
+ if(v < 0){
+ buf[off++] = byte '-';
+ v = -v;
+ }
+ n := stop;
+ while(v > 0){
+ buf[n -= 1] = byte(v % 10 + '0');
+ v = v / 10;
+ }
+ while(n < stop)
+ buf[off++] = buf[n++];
+ return off;
+}
+
+sblsrcconvb(buf: array of byte, off: int, src: Src): int
+{
+ (startf, startl) := fline(src.start >> PosBits);
+ (stopf, stopl) := fline(src.stop >> PosBits);
+ if(lastf != startf.sbl){
+ off = sblint(buf, off, startf.sbl);
+ buf[off++] = byte ':';
+ }
+ if(lastline != startl){
+ off = sblint(buf, off, startl);
+ buf[off++] = byte '.';
+ }
+ off = sblint(buf, off, (src.start & PosMask));
+ buf[off++] = byte ',';
+ if(startf.sbl != stopf.sbl){
+ off = sblint(buf, off, stopf.sbl);
+ buf[off++] = byte ':';
+ }
+ if(startl != stopl){
+ off = sblint(buf, off, stopl);
+ buf[off++] = byte '.';
+ }
+ off = sblint(buf, off, (src.stop & PosMask));
+ buf[off++] = byte ' ';
+ lastf = stopf.sbl;
+ lastline = stopl;
+ return off;
+}
+
+sblsrcconv(src: Src): string
+{
+ s := "";
+ (startf, startl) := fline(src.start >> PosBits);
+ (stopf, stopl) := fline(src.stop >> PosBits);
+ if(lastf != startf.sbl){
+ s += string startf.sbl;
+ s[len s] = ':';
+ }
+ if(lastline != startl){
+ s += string startl;
+ s[len s] = '.';
+ }
+ s += string (src.start & PosMask);
+ s[len s] = ',';
+ if(startf.sbl != stopf.sbl){
+ s += string stopf.sbl;
+ s[len s] = ':';
+ }
+ if(startl != stopl){
+ s += string stopl;
+ s[len s] = '.';
+ }
+ s += string (src.stop & PosMask);
+ s[len s] = ' ';
+ lastf = stopf.sbl;
+ lastline = stopl;
+ return s;
+}
+
+isnilsrc(s: Src): int
+{
+ return s.start == 0 && s.stop == 0;
+}
+
+isnilstopsrc(s: Src): int
+{
+ return s.stop == 0;
+}
+
+sblinst(in: ref Inst, ninst: int)
+{
+ src: Src;
+
+ MAXSBL: con 8*1024;
+ buf := array[MAXSBL] of byte;
+ n := 0;
+ bsym.puts(string ninst);
+ bsym.putb(byte '\n');
+ sblblocks := array[nblocks] of {* => -1};
+ for(; in != nil; in = in.next){
+ if(in.op == INOOP)
+ continue;
+ if(in.src.start < 0)
+ fatal("no file specified for "+instconv(in));
+ if(n >= (MAXSBL - MAXSBLSRC - MAXSBLINT - 1)){
+ bsym.write(buf, n);
+ n = 0;
+ }
+ if(isnilsrc(in.src))
+ in.src = src;
+ else if(isnilstopsrc(in.src)){ # how does this happen ?
+ in.src.stop = in.src.start;
+ in.src.stop++;
+ }
+ n = sblsrcconvb(buf, n, in.src);
+ src = in.src;
+ b := sblblocks[in.block];
+ if(b < 0)
+ sblblocks[in.block] = b = blockid++;
+ n = sblint(buf, n, b);
+ buf[n++] = byte '\n';
+ }
+ if(n > 0)
+ bsym.write(buf, n);
+}
+
+sblty(tys: array of ref Decl, ntys: int)
+{
+ bsym.puts(string ntys);
+ bsym.putb(byte '\n');
+ for(i := 0; i < ntys; i++){
+ d := tys[i];
+ d.ty.sbl = i;
+ }
+ for(i = 0; i < ntys; i++){
+ d := tys[i];
+ sbltype(d.ty, 1);
+ }
+}
+
+sblfn(fns: array of ref Decl, nfns: int)
+{
+ bsym.puts(string nfns);
+ bsym.putb(byte '\n');
+ for(i := 0; i < nfns; i++){
+ f := fns[i];
+ if(ispoly(f))
+ rmfnptrs(f);
+ bsym.puts(string f.pc.pc);
+ bsym.putb(byte ':');
+ if(f.dot != nil && f.dot.ty.kind == Tadt){
+ bsym.puts(f.dot.sym.name);
+ bsym.putb(byte '.');
+ }
+ bsym.puts(f.sym.name);
+ bsym.putb(byte '\n');
+ sbldecl(f.ty.ids, Darg);
+ sbldecl(f.locals, Dlocal);
+ sbltype(f.ty.tof, 0);
+ }
+}
+
+sblvar(vars: ref Decl)
+{
+ sbldecl(vars, Dglobal);
+}
+
+isvis(id: ref Decl): int
+{
+ if(!tattr[id.ty.kind].vis
+ || id.sym == nil
+ || id.sym.name == ""
+ || id.sym.name[0] == '.')
+ return 0;
+ if(id.ty == tstring && id.init != nil && id.init.op == Oconst)
+ return 0;
+ if(id.src.start < 0 || id.src.stop < 0)
+ return 0;
+ return 1;
+}
+
+sbldecl(ids: ref Decl, store: int)
+{
+ n := 0;
+ for(id := ids; id != nil; id = id.next){
+ if(id.store != store || !isvis(id))
+ continue;
+ n++;
+ }
+ bsym.puts(string n);
+ bsym.putb(byte '\n');
+ for(id = ids; id != nil; id = id.next){
+ if(id.store != store || !isvis(id))
+ continue;
+ bsym.puts(string id.offset);
+ bsym.putb(byte ':');
+ bsym.puts(id.sym.name);
+ bsym.putb(byte ':');
+ bsym.puts(sblsrcconv(id.src));
+ sbltype(id.ty, 0);
+ bsym.putb(byte '\n');
+ }
+}
+
+sbltype(t: ref Type, force: int)
+{
+ if(t.kind == Tadtpick)
+ t = t.decl.dot.ty;
+
+ d := t.decl;
+ if(!force && d != nil && d.ty.sbl >= 0){
+ bsym.putb(byte '@');
+ bsym.puts(string d.ty.sbl);
+ bsym.putb(byte '\n');
+ return;
+ }
+
+ if(t.rec != byte 0)
+ fatal("recursive sbl type: "+typeconv(t));
+
+ t.rec = byte 1;
+ case t.kind{
+ * =>
+ fatal("bad type in sbltype: "+typeconv(t));
+ Tnone or
+ Tany or
+ Tint or
+ Tbig or
+ Tbyte or
+ Treal or
+ Tstring or
+ Tfix or
+ Tpoly =>
+ bsym.putb(sbltname[t.kind]);
+ Tfn =>
+ bsym.putb(sbltname[t.kind]);
+ sbldecl(t.ids, Darg);
+ sbltype(t.tof, 0);
+ Tarray or
+ Tlist or
+ Tchan or
+ Tref =>
+ bsym.putb(sbltname[t.kind]);
+ if(t.kind == Tref && t.tof.kind == Tfn){
+ tattr[Tany].vis = 1;
+ sbltype(tfnptr, 0);
+ tattr[Tany].vis = 0;
+ }
+ else
+ sbltype(t.tof, 0);
+ Ttuple or
+ Texception =>
+ bsym.putb(sbltname[t.kind]);
+ bsym.puts(string t.size);
+ bsym.putb(byte '.');
+ sbldecl(t.ids, Dfield);
+ Tadt =>
+ if(t.tags != nil)
+ bsym.putb(sbltadtpick);
+ else
+ bsym.putb(sbltname[t.kind]);
+ if(d.dot != nil && !isimpmod(d.dot.sym))
+ bsym.puts(d.dot.sym.name + "->");
+ bsym.puts(d.sym.name);
+ bsym.putb(byte ' ');
+ bsym.puts(sblsrcconv(d.src));
+ bsym.puts(string d.ty.size);
+ bsym.putb(byte '\n');
+ sbldecl(t.ids, Dfield);
+ if(t.tags != nil){
+ bsym.puts(string t.decl.tag);
+ bsym.putb(byte '\n');
+ lastt : ref Type = nil;
+ for(tg := t.tags; tg != nil; tg = tg.next){
+ bsym.puts(tg.sym.name);
+ bsym.putb(byte ':');
+ bsym.puts(sblsrcconv(tg.src));
+ if(lastt == tg.ty){
+ bsym.putb(byte '\n');
+ }else{
+ bsym.puts(string tg.ty.size);
+ bsym.putb(byte '\n');
+ sbldecl(tg.ty.ids, Dfield);
+ }
+ lastt = tg.ty;
+ }
+ }
+ Tmodule =>
+ bsym.putb(sbltname[t.kind]);
+ bsym.puts(d.sym.name);
+ bsym.putb(byte '\n');
+ bsym.puts(sblsrcconv(d.src));
+ sbldecl(t.ids, Dglobal);
+ }
+ t.rec = byte 0;
+}
--- /dev/null
+++ b/appl/cmd/tac.b
@@ -1,0 +1,58 @@
+implement Tac;
+
+include "sys.m"; sys: Sys;
+include "bufio.m"; bufio: Bufio; Iobuf: import bufio;
+include "draw.m";
+
+Tac: module {
+ init: fn(nil: ref Draw->Context, args: list of string);
+};
+
+
+stdout: ref Sys->FD;
+
+init(nil: ref Draw->Context, args: list of string)
+{
+ sys = load Sys Sys->PATH;
+ bufio = load Bufio Bufio->PATH;
+ stdout = sys->fildes(1);
+ args = tl args;
+
+ if(args == nil)
+ args = "-" :: nil;
+
+ for(; args != nil; args = tl args) {
+ file := hd args;
+ if(file != "-") {
+ fd := sys->open(file, Sys->OREAD);
+ if(fd == nil){
+ sys->fprint(sys->fildes(2), "tac: cannot open %s: %r\n", file);
+ raise "fail:bad open";
+ }
+ tac(fd, file);
+ } else {
+ tac(sys->fildes(0), "<stdin>");
+ }
+ }
+}
+
+tac(fd: ref Sys->FD, file: string)
+{
+ lines: list of string = nil;
+ line: string;
+
+ fio := bufio->fopen(fd, bufio->OREAD);
+ if(fio == nil) {
+ sys->fprint(sys->fildes(2), "tac: Couldn't create a bufio for %s: %r\n", file);
+ raise "fail:bufio";
+ }
+
+ while((line = fio.gets('\n')) != nil)
+ lines = line :: lines;
+
+ while(lines != nil) {
+ buf := array of byte (hd lines);
+ sys->write(stdout, buf, len buf);
+ lines = tl lines;
+ }
+}
--- /dev/null
+++ b/appl/cmd/whois.b
@@ -1,0 +1,89 @@
+implement Whois;
+
+include "sys.m"; sys: Sys;
+include "draw.m";
+include "dial.m"; dial: Dial;
+include "arg.m";
+
+Whois: module {
+ init: fn(nil: ref Draw->Context, args: list of string);
+};
+
+init(nil: ref Draw->Context, args: list of string) {
+ sys = load Sys Sys->PATH;
+ dial = load Dial Dial->PATH;
+ arg := load Arg Arg->PATH;
+
+ addr := "tcp!whois.iana.org!43";
+ expect_refer := 5;
+
+ arg->init(args);
+ arg->setusage("whois [-a addr] [-n] host");
+ while((opt := arg->opt()) != 0) {
+ case opt {
+ 'a' =>
+ addr = dial->netmkaddr(arg->earg(), "tcp", "43");
+ 'n' =>
+ expect_refer = 0;
+ * =>
+ arg->usage();
+ }
+ }
+
+ args = arg->argv();
+ if(len args != 1)
+ arg->usage();
+
+ host := hd args;
+ fd := whois(addr, host);
+
+ buf := array[512] of byte;
+ stdout := sys->fildes(1);
+ while((i := sys->read(fd, buf, len buf)) > 0) {
+ if(expect_refer) {
+ ls := sys->tokenize(string buf[0:i], "\n").t1;
+ newaddr: string = nil;
+ while(ls != nil) {
+ l := hd ls;
+ (n, rs) := sys->tokenize(l, " \t");
+ if(n == 2 && hd rs == "refer:") {
+ newaddr = dial->netmkaddr(hd tl rs, "tcp", "43");
+ break;
+ } else if(n == 3 && hd rs == "Whois" && hd tl rs == "Server:") {
+ newaddr = dial->netmkaddr(hd tl tl rs, "tcp", "43");
+ break;
+ }
+ ls = tl ls;
+ }
+ if(newaddr != nil) {
+ fd = whois(newaddr, host);
+ expect_refer--;
+ continue;
+ }
+ }
+ sys->write(stdout, buf, i);
+ }
+ if(i < 0) {
+ sys->fprint(sys->fildes(2), "whois: reading info: %r\n");
+ raise "fail:errors";
+ }
+}
+
+whois(addr: string, host: string): ref Sys->FD
+{
+ sys->print("[using server %s]\n", addr);
+ conn := dial->dial(addr, nil);
+ if(conn == nil) {
+ sys->fprint(sys->fildes(2), "whois: dialing %s: %r\n", addr);
+ raise "fail:errors";
+ }
+
+ fd := conn.dfd;
+ i := sys->fprint(fd, "%s\r\n", host);
+ if(i != len host + 2) {
+ sys->fprint(sys->fildes(2), "whois: sending name: %r\n");
+ raise "fail:errors";
+ }
+
+ return fd;
+}
--- /dev/null
+++ b/appl/lib/dis.b
@@ -1,0 +1,609 @@
+implement Dis;
+
+#
+# Derived by Vita Nuova Limited 1998 from /appl/wm/rt.b, which is
+# Copyright © 1996-1999 Lucent Technologies Inc. All rights reserved.
+#
+
+include "sys.m";
+ sys: Sys;
+ sprint: import sys;
+
+include "math.m";
+ math: Math;
+
+include "dis.m";
+
+disptr: int;
+disobj: array of byte;
+
+optab := array[] of {
+ "nop",
+ "alt",
+ "nbalt",
+ "goto",
+ "call",
+ "frame",
+ "spawn",
+ "runt",
+ "load",
+ "mcall",
+ "mspawn",
+ "mframe",
+ "ret",
+ "jmp",
+ "case",
+ "exit",
+ "new",
+ "newa",
+ "newcb",
+ "newcw",
+ "newcf",
+ "newcp",
+ "newcm",
+ "newcmp",
+ "send",
+ "recv",
+ "consb",
+ "consw",
+ "consp",
+ "consf",
+ "consm",
+ "consmp",
+ "headb",
+ "headw",
+ "headp",
+ "headf",
+ "headm",
+ "headmp",
+ "tail",
+ "lea",
+ "indx",
+ "movp",
+ "movm",
+ "movmp",
+ "movb",
+ "movw",
+ "movf",
+ "cvtbw",
+ "cvtwb",
+ "cvtfw",
+ "cvtwf",
+ "cvtca",
+ "cvtac",
+ "cvtwc",
+ "cvtcw",
+ "cvtfc",
+ "cvtcf",
+ "addb",
+ "addw",
+ "addf",
+ "subb",
+ "subw",
+ "subf",
+ "mulb",
+ "mulw",
+ "mulf",
+ "divb",
+ "divw",
+ "divf",
+ "modw",
+ "modb",
+ "andb",
+ "andw",
+ "orb",
+ "orw",
+ "xorb",
+ "xorw",
+ "shlb",
+ "shlw",
+ "shrb",
+ "shrw",
+ "insc",
+ "indc",
+ "addc",
+ "lenc",
+ "lena",
+ "lenl",
+ "beqb",
+ "bneb",
+ "bltb",
+ "bleb",
+ "bgtb",
+ "bgeb",
+ "beqw",
+ "bnew",
+ "bltw",
+ "blew",
+ "bgtw",
+ "bgew",
+ "beqf",
+ "bnef",
+ "bltf",
+ "blef",
+ "bgtf",
+ "bgef",
+ "beqc",
+ "bnec",
+ "bltc",
+ "blec",
+ "bgtc",
+ "bgec",
+ "slicea",
+ "slicela",
+ "slicec",
+ "indw",
+ "indf",
+ "indb",
+ "negf",
+ "movl",
+ "addl",
+ "subl",
+ "divl",
+ "modl",
+ "mull",
+ "andl",
+ "orl",
+ "xorl",
+ "shll",
+ "shrl",
+ "bnel",
+ "bltl",
+ "blel",
+ "bgtl",
+ "bgel",
+ "beql",
+ "cvtlf",
+ "cvtfl",
+ "cvtlw",
+ "cvtwl",
+ "cvtlc",
+ "cvtcl",
+ "headl",
+ "consl",
+ "newcl",
+ "casec",
+ "indl",
+ "movpc",
+ "tcmp",
+ "mnewz",
+ "cvtrf",
+ "cvtfr",
+ "cvtws",
+ "cvtsw",
+ "lsrw",
+ "lsrl",
+ "eclr",
+ "newz",
+ "newaz",
+ "raise",
+ "casel",
+ "mulx",
+ "divx",
+ "cvtxx",
+ "mulx0",
+ "divx0",
+ "cvtxx0",
+ "mulx1",
+ "divx1",
+ "cvtxx1",
+ "cvtfx",
+ "cvtxf",
+ "expw",
+ "expl",
+ "expf",
+ "self",
+};
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ math = load Math Math->PATH; # optional
+}
+
+loadobj(disfile: string): (ref Mod, string)
+{
+ fd := sys->open(disfile, sys->OREAD);
+ if(fd == nil)
+ return (nil, "open failed: "+sprint("%r"));
+
+ (ok, d) := sys->fstat(fd);
+ if(ok < 0)
+ return (nil, "stat failed: "+sprint("%r"));
+
+ objlen := int d.length;
+ disobj = array[objlen] of byte;
+
+ if(sys->read(fd, disobj, objlen) != objlen){
+ disobj = nil;
+ return (nil, "read failed: "+sprint("%r"));
+ }
+
+ disptr = 0;
+ m := ref Mod;
+ m.magic = operand();
+ if(m.magic == SMAGIC) {
+ n := operand();
+ m.sign = disobj[disptr:disptr+n];
+ disptr += n;
+ m.magic = operand();
+ }
+ if(m.magic != XMAGIC){
+ disobj = nil;
+ return (nil, "bad magic number");
+ }
+
+ m.rt = operand();
+ m.ssize = operand();
+ m.isize = operand();
+ m.dsize = operand();
+ m.tsize = operand();
+ m.lsize = operand();
+ m.entry = operand();
+ m.entryt = operand();
+
+ m.inst = array[m.isize] of ref Inst;
+ for(i := 0; i < m.isize; i++) {
+ o := ref Inst;
+ o.op = int disobj[disptr++];
+ o.addr = int disobj[disptr++];
+ case o.addr & ARM {
+ AXIMM or
+ AXINF or
+ AXINM =>
+ o.mid = operand();
+ }
+
+ case (o.addr>>3) & 7 {
+ AFP or
+ AMP or
+ AIMM =>
+ o.src = operand();
+ AIND|AFP or
+ AIND|AMP =>
+ o.src = operand()<<16;
+ o.src |= operand();
+ }
+
+ case o.addr & 7 {
+ AFP or
+ AMP or
+ AIMM =>
+ o.dst = operand();
+ AIND|AFP or
+ AIND|AMP =>
+ o.dst = operand()<<16;
+ o.dst |= operand();
+ }
+ m.inst[i] = o;
+ }
+
+ m.types = array[m.tsize] of ref Type;
+ for(i = 0; i < m.tsize; i++) {
+ h := ref Type;
+ id := operand();
+ h.size = operand();
+ h.np = operand();
+ h.map = disobj[disptr:disptr+h.np];
+ disptr += h.np;
+ m.types[i] = h;
+ }
+
+ for(;;) {
+ op := int disobj[disptr++];
+ if(op == 0)
+ break;
+
+ n := op & (DMAX-1);
+ if(n == 0)
+ n = operand();
+
+ offset := operand();
+
+ dat: ref Data;
+ case op>>4 {
+ DEFB =>
+ dat = ref Data.Bytes(op, n, offset, disobj[disptr:disptr+n]);
+ disptr += n;
+ DEFW =>
+ words := array[n] of int;
+ for(i = 0; i < n; i++)
+ words[i] = getw();
+ dat = ref Data.Words(op, n, offset, words);
+ DEFS =>
+ dat = ref Data.String(op, n, offset, string disobj[disptr:disptr+n]);
+ disptr += n;
+ DEFF =>
+ if(math != nil){
+ reals := array[n] of real;
+ for(i = 0; i < n; i++)
+ reals[i] = math->bits64real(getl());
+ dat = ref Data.Reals(op, n, offset, reals);
+ } else {
+ disptr += 8*n; # skip it
+ dat = ref Data.Reals(op, n, offset, nil);
+ }
+ break;
+ DEFA =>
+ typex := getw();
+ length := getw();
+ dat = ref Data.Array(op, n, offset, typex, length);
+ DIND =>
+ dat = ref Data.Aindex(op, n, offset, getw());
+ DAPOP =>
+ dat = ref Data.Arestore(op, n, offset);
+ DEFL =>
+ bigs := array[n] of big;
+ for(i = 0; i < n; i++)
+ bigs[i] = getl();
+ dat = ref Data.Bigs(op, n, offset, bigs);
+ * =>
+ dat = ref Data.Zero(op, n, offset);
+ }
+ m.data = dat :: m.data;
+ }
+
+ m.data = revdat(m.data);
+
+ m.name = gets();
+
+ m.links = array[m.lsize] of ref Link;
+ for(i = 0; i < m.lsize; i++) {
+ l := ref Link;
+ l.pc = operand();
+ l.desc = operand();
+ l.sig = getw();
+ l.name = gets();
+
+ m.links[i] = l;
+ }
+
+ if(m.rt & Dis->HASLDT0)
+ raise "obsolete dis";
+
+ if(m.rt & Dis->HASLDT){
+ nl := operand();
+ imps := array[nl] of array of ref Import;
+ for(i = 0; i < nl; i++){
+ n := operand();
+ imps[i] = array[n] of ref Import;
+ for(j := 0; j < n; j++){
+ imps[i][j] = im := ref Import;
+ im.sig = getw();
+ im.name = gets();
+ }
+ }
+ disptr++;
+ m.imports = imps;
+ }
+
+ if(m.rt & Dis->HASEXCEPT){
+ nh := operand(); # number of handlers
+ hs := array[nh] of ref Handler;
+ for(i = 0; i < nh; i++){
+ h := hs[i] = ref Handler;
+ h.eoff = operand();
+ h.pc1 = operand();
+ h.pc2 = operand();
+ t := operand();
+ if(t >= 0)
+ h.t = m.types[t];
+ n := operand();
+ h.ne = n>>16;
+ n &= 16rffff; # number of cases
+ h.etab = array[n+1] of ref Except;
+ for(j := 0; j < n; j++){
+ e := h.etab[j] = ref Except;
+ k := disptr;
+ while(int disobj[disptr++]) # pattern
+ ;
+ e.s = string disobj[k: disptr-1];
+ e.pc = operand();
+ }
+ e := h.etab[j] = ref Except;
+ e.pc = operand(); # * pc
+ }
+ disptr++; # 0 byte
+ m.handlers = hs;
+ }
+
+ m.srcpath = gets();
+
+ disobj = nil;
+ return (m, nil);
+}
+
+operand(): int
+{
+ if(disptr >= len disobj)
+ return -1;
+
+ b := int disobj[disptr++];
+
+ case b & 16rC0 {
+ 16r00 =>
+ return b;
+ 16r40 =>
+ return b | ~16r7F;
+ 16r80 =>
+ if(disptr >= len disobj)
+ return -1;
+ if(b & 16r20)
+ b |= ~16r3F;
+ else
+ b &= 16r3F;
+ return (b<<8) | int disobj[disptr++];
+ 16rC0 =>
+ if(disptr+2 >= len disobj)
+ return -1;
+ if(b & 16r20)
+ b |= ~16r3F;
+ else
+ b &= 16r3F;
+ b = b<<24 |
+ (int disobj[disptr]<<16) |
+ (int disobj[disptr+1]<<8)|
+ int disobj[disptr+2];
+ disptr += 3;
+ return b;
+ }
+ return 0;
+}
+
+get4(a: array of byte, i: int): int
+{
+ return (int a[i+0] << 24) | (int a[i+1] << 16) | (int a[i+2] << 8) | int a[i+3];
+}
+
+getw(): int
+{
+ if(disptr+3 >= len disobj)
+ return -1;
+ i := (int disobj[disptr+0]<<24) |
+ (int disobj[disptr+1]<<16) |
+ (int disobj[disptr+2]<<8) |
+ int disobj[disptr+3];
+
+ disptr += 4;
+ return i;
+}
+
+getl(): big
+{
+ if(disptr+7 >= len disobj)
+ return big -1;
+ i := (big disobj[disptr+0]<<56) |
+ (big disobj[disptr+1]<<48) |
+ (big disobj[disptr+2]<<40) |
+ (big disobj[disptr+3]<<32) |
+ (big disobj[disptr+4]<<24) |
+ (big disobj[disptr+5]<<16) |
+ (big disobj[disptr+6]<<8) |
+ big disobj[disptr+7];
+
+ disptr += 8;
+ return i;
+}
+
+gets(): string
+{
+ s := disptr;
+ while(disptr < len disobj && disobj[disptr] != byte 0)
+ disptr++;
+
+ v := string disobj[s:disptr];
+ disptr++;
+ return v;
+}
+
+revdat(d: list of ref Data): list of ref Data
+{
+ t: list of ref Data;
+
+ while(d != nil) {
+ t = hd d :: t;
+ d = tl d;
+ }
+ return t;
+}
+
+op2s(op: int): string
+{
+ if(op < 0 || op >= len optab)
+ return sys->sprint("OP%d", op);
+ return optab[op];
+}
+
+inst2s(o: ref Inst): string
+{
+ fi := 0;
+ si := 0;
+ s := sprint("%-10s", optab[o.op]);
+ src := "";
+ dst := "";
+ mid := "";
+ case (o.addr>>3) & 7 {
+ AFP =>
+ src = sprint("%d(fp)", o.src);
+ AMP =>
+ src = sprint("%d(mp)", o.src);
+ AIMM =>
+ src = sprint("$%d", o.src);
+ AIND|AFP =>
+ fi = (o.src>>16) & 16rFFFF;
+ si = o.src & 16rFFFF;
+ src = sprint("%d(%d(fp))", si, fi);
+ AIND|AMP =>
+ fi = (o.src>>16) & 16rFFFF;
+ si = o.src & 16rFFFF;
+ src = sprint("%d(%d(mp))", si, fi);
+ }
+
+ case o.addr & ARM {
+ AXIMM =>
+ mid = sprint("$%d", o.mid);
+ AXINF =>
+ mid = sprint("%d(fp)", o.mid);
+ AXINM =>
+ mid = sprint("%d(mp)", o.mid);
+ }
+
+ case o.addr & 7 {
+ AFP =>
+ dst = sprint("%d(fp)", o.dst);
+ AMP =>
+ dst = sprint("%d(mp)", o.dst);
+ AIMM =>
+ dst = sprint("$%d", o.dst);
+ AIND|AFP =>
+ fi = (o.dst>>16) & 16rFFFF;
+ si = o.dst & 16rFFFF;
+ dst = sprint("%d(%d(fp))", si, fi);
+ AIND|AMP =>
+ fi = (o.dst>>16) & 16rFFFF;
+ si = o.dst & 16rFFFF;
+ dst = sprint("%d(%d(mp))", si, fi);
+ }
+ if(mid == "") {
+ if(src == "")
+ s += sprint("%s", dst);
+ else if(dst == "")
+ s += sprint("%s", src);
+ else
+ s += sprint("%s, %s", src, dst);
+ }
+ else
+ s += sprint("%s, %s, %s", src, mid, dst);
+
+ return s;
+}
+
+getsb(fd: ref Sys->FD, o: int): (string, int)
+{
+ b := array[1] of byte;
+ buf := array[8192] of byte;
+ p := len buf;
+ for( ; ; o++){
+ sys->seek(fd, big -o, Sys->SEEKEND);
+ if(sys->read(fd, b, 1) != 1)
+ return (nil, 0);
+ if(b[0] == byte 0){
+ if(p < len buf)
+ break;
+ }
+ else if(p > 0)
+ buf[--p] = b[0];
+ }
+ return (string buf[p: ], o);
+}
+
+src(disf: string): string
+{
+ fd := sys->open(disf, sys->OREAD);
+ if(fd == nil)
+ return nil;
+ (s, nil) := getsb(fd, 1);
+ if(s != nil && s[0] == '/')
+ return s;
+ return nil;
+}
--- /dev/null
+++ b/appl/lib/diskblocks.b
@@ -1,0 +1,122 @@
+implement Diskblocks;
+
+#
+# adapted from Acme's disk.b
+#
+
+include "sys.m";
+ sys: Sys;
+
+include "diskblocks.m";
+
+init()
+{
+ sys = load Sys Sys->PATH;
+}
+
+tempfile(): ref Sys->FD
+{
+ user := "inferno";
+ fd := sys->open("/dev/user", Sys->OREAD);
+ if(fd != nil){
+ b := array[Sys->NAMEMAX] of byte;
+ n := sys->read(fd, b, len b);
+ if(n > 0)
+ user = string b[0:n];
+ }
+ fd = nil;
+ buf := sys->sprint("/tmp/X%d.%.4sblks", sys->pctl(0, nil), user);
+ for(i:='A'; i<='Z'; i++){
+ buf[5] = i;
+ if(sys->stat(buf).t0 == 0)
+ continue;
+ fd = sys->create(buf, Sys->ORDWR|Sys->ORCLOSE|Sys->OEXCL, 8r600);
+ if(fd != nil)
+ return fd;
+ }
+ return nil;
+}
+
+Disk.init(fd: ref Sys->FD, gran: int, maxblock: int): ref Disk
+{
+ d := ref Disk;
+ if(gran == 0 || maxblock%gran != 0)
+ return nil;
+ d.maxblock = maxblock;
+ d.gran = gran;
+ d.free = array[maxblock/gran+1] of list of ref Block;
+ d.addr = big 0;
+ d.fd = fd;
+ d.lock = chan[1] of int;
+ return d;
+}
+
+ntosize(d: ref Disk, n: int): (int, int)
+{
+ if (n > d.maxblock)
+ return (-1, -1);
+ size := n;
+ if((size % d.gran) != 0)
+ size += d.gran - size%d.gran;
+ # last bucket holds blocks of exactly d.maxblock
+ return (size, size/d.gran);
+}
+
+Disk.new(d: self ref Disk, n: int): ref Block
+{
+ (size, i) := ntosize(d, n);
+ if(i < 0){
+ sys->werrstr("illegal Disk allocation");
+ return nil;
+ }
+ b: ref Block;
+ d.lock <-= 1;
+ if(d.free[i] != nil){
+ b = hd d.free[i];
+ d.free[i] = tl d.free[i];
+ }else{
+ b = ref Block(d.addr, 0);
+ d.addr += big size;
+ }
+ <-d.lock;
+ b.n = n;
+ return b;
+}
+
+Disk.release(d: self ref Disk, b: ref Block)
+{
+ (nil, i) := ntosize(d, b.n);
+ d.lock <-= 1;
+ d.free[i] = b :: d.free[i];
+ <-d.lock;
+}
+
+Disk.write(d: self ref Disk, b: ref Block, a: array of byte, n: int): ref Block
+{
+ if(b != nil){
+ (size, nil) := ntosize(d, b.n);
+ (nsize, nil) := ntosize(d, n);
+ if(size != nsize){
+ d.release(b);
+ b = d.new(n);
+ }
+ }else
+ b = d.new(n);
+ if(b == nil)
+ return nil;
+ if(sys->pwrite(d.fd, a, n, b.addr) != n){
+ sys->werrstr(sys->sprint("Disk write error: %r"));
+ return nil;
+ }
+ b.n = n;
+ return b;
+}
+
+Disk.read(d: self ref Disk, b: ref Block, a: array of byte, n: int): int
+{
+ if(b == nil || n > b.n){
+ sys->werrstr("read request bigger than block");
+ return -1;
+ }
+ return sys->pread(d.fd, a, n, b.addr);
+}
--- /dev/null
+++ b/appl/lib/disks.b
@@ -1,0 +1,363 @@
+implement Disks;
+
+# adapted from /sys/src/libdisk on Plan 9: subject to Lucent Public License 1.02
+
+include "sys.m";
+ sys: Sys;
+
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+
+include "disks.m";
+
+scsiverbose := 0;
+
+Codefile: con "/lib/scsicodes";
+
+Code: adt {
+ v: int; # (asc<<8) | ascq
+ s: string;
+};
+codes: array of Code;
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ bufio = load Bufio Bufio->PATH;
+}
+
+#
+# Discover the disk geometry by various sleazeful means.
+#
+# First, if there is a partition table in sector 0,
+# see if all the partitions have the same end head
+# and sector; if so, we'll assume that that's the
+# right count.
+#
+# If that fails, we'll try looking at the geometry that the ATA
+# driver supplied, if any, and translate that as a
+# BIOS might.
+#
+# If that too fails, which should only happen on a SCSI
+# disk with no currently defined partitions, we'll try
+# various common (h, s) pairs used by BIOSes when faking
+# the geometries.
+#
+
+# table entry:
+ Oactive, # active flag
+ Ostarth, # starting head
+ Ostarts, # starting sector
+ Ostartc, # starting cylinder
+ Otype, # partition type
+ Oendh, # ending head
+ Oends, # ending sector
+ Oendc: con iota; # ending cylinder
+ Oxlba: con Oendc+1; # starting LBA from start of disc or partition [4]
+ Oxsize: con Oxlba+4; # size in sectors[4]
+
+# Table: entry[NTentry][TentrySize] magic[2]
+Omagic: con NTentry*TentrySize;
+
+partitiongeometry(d: ref Disk): int
+{
+ buf := array[512] of byte;
+ t := buf[Toffset:];
+
+ #
+ # look for an MBR first in the /dev/sdXX/data partition, otherwise
+ # attempt to fall back on the current partition.
+ #
+ rawfd := sys->open(d.prefix+"data", Sys->OREAD);
+ if(rawfd != nil
+ && sys->seek(rawfd, big 0, 0) == big 0
+ && sys->readn(rawfd, buf, 512) == 512
+ && int t[Omagic] == Magic0
+ && int t[Omagic+1] == Magic1) {
+ rawfd = nil;
+ }else{
+ rawfd = nil;
+ if(sys->seek(d.fd, big 0, 0) < big 0
+ || sys->readn(d.fd, buf, 512) != 512
+ || int t[Omagic] != Magic0
+ || int t[Omagic+1] != Magic1)
+ return -1;
+ }
+
+ h := s := -1;
+ for(i:=0; i<NTentry*TentrySize; i += TentrySize) {
+ if(t[i+Otype] == byte 0)
+ continue;
+
+ t[i+Oends] &= byte 63;
+ if(h == -1) {
+ h = int t[i+Oendh];
+ s = int t[i+Oends];
+ } else {
+ #
+ # Only accept the partition info if every
+ # partition is consistent.
+ #
+ if(h != int t[i+Oendh] || s != int t[i+Oends])
+ return -1;
+ }
+ }
+
+ if(h == -1)
+ return -1;
+
+ d.h = h+1; # heads count from 0
+ d.s = s; # sectors count from 1
+ d.c = int (d.secs / big (d.h*d.s));
+ d.chssrc = "part";
+ return 0;
+}
+
+#
+# If there is ATA geometry, use it, perhaps massaged
+#
+drivergeometry(d: ref Disk): int
+{
+ if(d.c == 0 || d.h == 0 || d.s == 0)
+ return -1;
+
+ d.chssrc = "disk";
+ if(d.c < 1024)
+ return 0;
+
+ case d.h {
+ 15 =>
+ d.h = 255;
+ d.c /= 17;
+
+ * =>
+ for(m := 2; m*d.h < 256; m *= 2) {
+ if(d.c/m < 1024) {
+ d.c /= m;
+ d.h *= m;
+ return 0;
+ }
+ }
+
+ # set to 255, 63 and be done with it
+ d.h = 255;
+ d.s = 63;
+ d.c = int (d.secs / big(d.h * d.s));
+ }
+ return 0;
+}
+
+#
+# There's no ATA geometry and no partitions.
+# Our guess is as good as anyone's.
+#
+Guess: adt {
+ h: int;
+ s: int;
+};
+guess: array of Guess = array[] of {
+ (64, 32),
+ (64, 63),
+ (128, 63),
+ (255, 63),
+};
+
+guessgeometry(d: ref Disk)
+{
+ d.chssrc = "guess";
+ c := 1024;
+ for(i:=0; i<len guess; i++)
+ if(big(c*guess[i].h*guess[i].s) >= d.secs) {
+ d.h = guess[i].h;
+ d.s = guess[i].s;
+ d.c = int(d.secs / big(d.h * d.s));
+ return;
+ }
+
+ # use maximum values
+ d.h = 255;
+ d.s = 63;
+ d.c = int(d.secs / big(d.h * d.s));
+}
+
+findgeometry(disk: ref Disk)
+{
+ disk.h = disk.s = disk.c = 0;
+ if(partitiongeometry(disk) < 0 &&
+ drivergeometry(disk) < 0)
+ guessgeometry(disk);
+}
+
+openfile(d: ref Disk): ref Disk
+{
+ (ok, db) := sys->fstat(d.fd);
+ if(ok < 0)
+ return nil;
+
+ d.secsize = 512;
+ d.size = db.length;
+ d.secs = d.size / big d.secsize;
+ d.offset = big 0;
+
+ findgeometry(d);
+ return mkwidth(d);
+}
+
+opensd(d: ref Disk): ref Disk
+{
+ b := bufio->fopen(d.ctlfd, Bufio->OREAD);
+ while((p := b.gets('\n')) != nil){
+ p = p[0:len p - 1];
+ (nf, f) := sys->tokenize(p, " \t"); # might need str->unquote
+ if(nf >= 3 && hd f == "geometry") {
+ d.secsize = int hd tl tl f;
+ if(nf >= 6) {
+ d.c = int hd tl tl tl f;
+ d.h = int hd tl tl tl tl f;
+ d.s = int hd tl tl tl tl tl f;
+ }
+ }
+ if(nf >= 4 && hd f == "part" && hd tl f == d.part) {
+ d.offset = big hd tl tl f;
+ d.secs = big hd tl tl tl f - d.offset;
+ }
+ }
+
+
+ d.size = d.secs * big d.secsize;
+ if(d.size <= big 0) {
+ d.part = "";
+ d.dtype = "file";
+ return openfile(d);
+ }
+
+ findgeometry(d);
+ return mkwidth(d);
+}
+
+Disk.open(name: string, mode: int, noctl: int): ref Disk
+{
+ d := ref Disk;
+ d.rdonly = mode == Sys->OREAD;
+ d.fd = sys->open(name, Sys->OREAD);
+ if(d.fd == nil)
+ return nil;
+
+ if(mode != Sys->OREAD){
+ d.wfd = sys->open(name, Sys->OWRITE);
+ if(d.wfd == nil)
+ d.rdonly = 1;
+ }
+
+ if(noctl)
+ return openfile(d);
+
+ # check for floppy(3) disk
+ if(len name >= 7) {
+ q := name[len name-7:];
+ if(q[0] == 'f' && q[1] == 'd' && isdigit(q[2]) && q[3:] == "disk") {
+ if((d.ctlfd = sys->open(name[0:len name-4]+"ctl", Sys->ORDWR)) != nil) {
+ d.prefix = name[0:len name-4]; # fdN (unlike Plan 9)
+ d.dtype = "floppy";
+ return openfile(d);
+ }
+ }
+ }
+
+ # attempt to find sd(3) disk or partition
+ d.prefix = name;
+ for(i := len name; --i >= 0;)
+ if(name[i] == '/'){
+ d.prefix = name[0:i+1];
+ break;
+ }
+
+ if((d.ctlfd = sys->open(d.prefix+"ctl", Sys->ORDWR)) != nil) {
+ d.dtype = "sd";
+ d.part = name[len d.prefix:];
+ return opensd(d);
+ }
+
+ # assume we have just a normal file
+ d.dtype = "file";
+ return openfile(d);
+}
+
+mkwidth(d: ref Disk): ref Disk
+{
+ d.width = len sys->sprint("%bd", d.size);
+ return d;
+}
+
+isdigit(c: int): int
+{
+ return c >= '0' && c <= '9';
+}
+
+putchs(d: ref Disk, p: array of byte, lba: big)
+{
+ s := int (lba % big d.s);
+ h := int (lba / big d.s % big d.h);
+ c := int (lba / (big d.s * big d.h));
+
+ if(c >= 1024) {
+ c = 1023;
+ h = d.h - 1;
+ s = d.s - 1;
+ }
+
+ p[0] = byte h;
+ p[1] = byte (((s+1) & 16r3F) | ((c>>2) & 16rC0));
+ p[2] = byte c;
+}
+
+PCpart.bytes(p: self PCpart, d: ref Disk): array of byte
+{
+ a := array[TentrySize] of byte;
+ a[Oactive] = byte p.active;
+ a[Otype] = byte p.ptype;
+ putchs(d, a[Ostarth:], p.base+p.offset);
+ putchs(d, a[Oendh:], p.base+p.offset+p.size-big 1);
+ putle32(a[Oxlba:], p.offset);
+ putle32(a[Oxsize:], p.size);
+ return a;
+}
+
+PCpart.extract(a: array of byte, nil: ref Disk): PCpart
+{
+ p: PCpart;
+ p.active = int a[Oactive];
+ p.ptype = int a[Otype];
+ p.base = big 0;
+ p.offset = getle32(a[Oxlba:]);
+ p.size = getle32(a[Oxsize:]);
+ return p;
+}
+
+getle32(p: array of byte): big
+{
+ return (big p[3]<<24) | (big p[2]<<16) | (big p[1] << 8) | big p[0];
+}
+
+putle32(p: array of byte, i: big)
+{
+ p[0] = byte i;
+ p[1] = byte (i>>8);
+ p[2] = byte (i>>16);
+ p[3] = byte (i>>24);
+}
+
+Disk.readn(d: self ref Disk, buf: array of byte, nb: int): int
+{
+ return sys->readn(d.fd, buf, nb);
+}
+
+chstext(p: array of byte): string
+{
+ h := int p[0];
+ c := int p[2];
+ c |= (int p[1]&16rC0)<<2;
+ s := (int p[1] & 16r3F);
+ return sys->sprint("%d/%d/%d", c, h, s);
+}
binary files /dev/null b/appl/lib/ida/idatab.dist differ