summaryrefslogtreecommitdiff
path: root/appl/cmd/ndb/mkhash.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/ndb/mkhash.b')
-rw-r--r--appl/cmd/ndb/mkhash.b119
1 files changed, 119 insertions, 0 deletions
diff --git a/appl/cmd/ndb/mkhash.b b/appl/cmd/ndb/mkhash.b
new file mode 100644
index 00000000..f1876355
--- /dev/null
+++ b/appl/cmd/ndb/mkhash.b
@@ -0,0 +1,119 @@
+implement Mkhash;
+
+#
+# for compatibility, this is closely modelled on Plan 9's ndb/mkhash
+#
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "bufio.m";
+include "attrdb.m";
+ attrdb: Attrdb;
+ Db, Dbf, Dbentry, Tuples, Attr: import attrdb;
+ attrhash: Attrhash;
+ NDBPLEN, NDBHLEN, NDBCHAIN, NDBNAP: import Attrhash;
+
+Mkhash: module
+{
+ init: fn(nil: ref Draw->Context, nil: list of string);
+};
+
+init(nil: ref Draw->Context, args: list of string)
+{
+ sys = load Sys Sys->PATH;
+ attrdb = load Attrdb Attrdb->PATH;
+ if(attrdb == nil)
+ error(sys->sprint("can't load %s: %r", Attrdb->PATH));
+ attrdb->init();
+ attrhash = load Attrhash Attrhash->PATH;
+ if(attrhash == nil)
+ error(sys->sprint("can't load %s: %r", Attrhash->PATH));
+
+ if(len args != 3)
+ error("usage: mkhash file attr");
+ args = tl args;
+ dbname := hd args;
+ args = tl args;
+ attr := hd args;
+ dbf := Dbf.open(dbname);
+ if(dbf == nil)
+ error(sys->sprint("can't open %s: %r", dbname));
+ offset := 0;
+ n := 0;
+ for(;;){
+ (e, nil, next) := dbf.readentry(offset, nil, nil, 0);
+ if(e == nil)
+ break;
+ m := len e.find(attr);
+ if(0 && m != 0)
+ sys->fprint(sys->fildes(2), "%ud [%d]\n", offset, m);
+ n += m;
+ offset = next;
+ }
+ hlen := 2*n+1;
+ chains := n*2*NDBPLEN;
+ file := array[NDBHLEN + hlen*NDBPLEN + chains] of byte;
+ tab := file[NDBHLEN:];
+ for(i:=0; i<len tab; i+=NDBPLEN)
+ put3(tab[i:], NDBNAP);
+ offset = 0;
+ chain := hlen*NDBPLEN;
+ for(;;){
+ (e, nil, next) := dbf.readentry(offset, nil, nil, 0);
+ if(e == nil)
+ break;
+ for(l := e.find(attr); l != nil; l = tl l)
+ for((nil, al) := hd l; al != nil; al = tl al)
+ chain = enter(tab, hd al, hlen, chain, offset);
+ offset = next;
+ }
+ hashfile := dbname+"."+attr;
+ hfd := sys->create(hashfile, Sys->OWRITE, 8r666);
+ if(hfd == nil)
+ error(sys->sprint("can't create %s: %r", hashfile));
+ mtime := 0;
+ if(dbf.dir != nil)
+ mtime = dbf.dir.mtime;
+ put4(file, mtime);
+ put4(file[4:], hlen);
+ if(sys->write(hfd, file, NDBHLEN+chain) != NDBHLEN+chain)
+ error(sys->sprint("error writing %s: %r", hashfile));
+}
+
+error(s: string)
+{
+ sys->fprint(sys->fildes(2), "mkhash: %s\n", s);
+ raise "fail:error";
+}
+
+enter(tab: array of byte, a: ref Attr, hlen: int, chain: int, offset: int): int
+{
+ o := attrhash->hash(a.val, hlen)*NDBPLEN;
+ for(; (p := attrhash->get3(tab[o:])) != NDBNAP; o = p & ~NDBCHAIN)
+ if((p & NDBCHAIN) == 0){
+ put3(tab[o:], chain | NDBCHAIN);
+ put3(tab[chain:], p);
+ put3(tab[chain+NDBPLEN:], offset);
+ return chain+2*NDBPLEN;
+ }
+ put3(tab[o:], offset);
+ return chain;
+}
+
+put3(a: array of byte, v: int)
+{
+ a[0] = byte v;
+ a[1] = byte (v>>8);
+ a[2] = byte (v>>16);
+}
+
+put4(a: array of byte, v: int)
+{
+ a[0] = byte v;
+ a[1] = byte (v>>8);
+ a[2] = byte (v>>16);
+ a[3] = byte (v>>24);
+}