xref: /inferno-os/appl/lib/dbm.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsythimplement Dbm;
2*37da2899SCharles.Forsyth
3*37da2899SCharles.Forsyth# Copyright © Caldera International Inc.  2001-2002.  All rights reserved.
4*37da2899SCharles.Forsyth# Limbo transliteration (with amendment) Copyright © 2004 Vita Nuova Holdings Limited.
5*37da2899SCharles.Forsyth
6*37da2899SCharles.Forsythinclude "sys.m";
7*37da2899SCharles.Forsyth	sys: Sys;
8*37da2899SCharles.Forsyth	OREAD, OWRITE, ORDWR: import Sys;
9*37da2899SCharles.Forsyth
10*37da2899SCharles.Forsythinclude "dbm.m";
11*37da2899SCharles.Forsyth
12*37da2899SCharles.ForsythBYTESIZ: con 8;	# bits
13*37da2899SCharles.ForsythSHORTSIZ: con 2;	# bytes
14*37da2899SCharles.Forsyth
15*37da2899SCharles.ForsythPBLKSIZ: con 512;
16*37da2899SCharles.ForsythDBLKSIZ: con 8192;	# was 4096
17*37da2899SCharles.Forsyth
18*37da2899SCharles.Forsythinit()
19*37da2899SCharles.Forsyth{
20*37da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
21*37da2899SCharles.Forsyth}
22*37da2899SCharles.Forsyth
23*37da2899SCharles.ForsythDbf.create(file: string, mode: int): ref Dbf
24*37da2899SCharles.Forsyth{
25*37da2899SCharles.Forsyth	pf := sys->create(file+".pag", ORDWR, mode);
26*37da2899SCharles.Forsyth	if(pf == nil)
27*37da2899SCharles.Forsyth		return nil;
28*37da2899SCharles.Forsyth	df := sys->create(file+".dir", ORDWR, mode);
29*37da2899SCharles.Forsyth	if(df == nil)
30*37da2899SCharles.Forsyth		return nil;
31*37da2899SCharles.Forsyth	return alloc(pf, df, ORDWR);
32*37da2899SCharles.Forsyth}
33*37da2899SCharles.Forsyth
34*37da2899SCharles.ForsythDbf.open(file: string, flags: int): ref Dbf
35*37da2899SCharles.Forsyth{
36*37da2899SCharles.Forsyth	if((flags & 3) == OWRITE)
37*37da2899SCharles.Forsyth		flags = (flags & ~3) | ORDWR;
38*37da2899SCharles.Forsyth	pf := sys->open(file+".pag", flags);
39*37da2899SCharles.Forsyth	if(pf == nil)
40*37da2899SCharles.Forsyth		return nil;
41*37da2899SCharles.Forsyth	df := sys->open(file+".dir", flags);
42*37da2899SCharles.Forsyth	if(df == nil)
43*37da2899SCharles.Forsyth		return nil;
44*37da2899SCharles.Forsyth	return alloc(pf, df, flags);
45*37da2899SCharles.Forsyth}
46*37da2899SCharles.Forsyth
47*37da2899SCharles.Forsythalloc(pf: ref Sys->FD, df: ref Sys->FD, flags: int): ref Dbf
48*37da2899SCharles.Forsyth{
49*37da2899SCharles.Forsyth	db := ref Dbf;
50*37da2899SCharles.Forsyth	db.pagf = pf;
51*37da2899SCharles.Forsyth	db.dirf = df;
52*37da2899SCharles.Forsyth	db.flags = flags & 3;
53*37da2899SCharles.Forsyth	db.maxbno = 0;
54*37da2899SCharles.Forsyth	db.bitno = 0;
55*37da2899SCharles.Forsyth	db.hmask = 0;
56*37da2899SCharles.Forsyth	db.blkno = 0;
57*37da2899SCharles.Forsyth	db.pagbno = -1;
58*37da2899SCharles.Forsyth	db.pagbuf = array[PBLKSIZ] of byte;
59*37da2899SCharles.Forsyth	db.dirbno = -1;
60*37da2899SCharles.Forsyth	db.dirbuf = array[DBLKSIZ] of byte;
61*37da2899SCharles.Forsyth	(ok, d) := sys->fstat(db.dirf);
62*37da2899SCharles.Forsyth	if(ok < 0)
63*37da2899SCharles.Forsyth		d.length = big 0;
64*37da2899SCharles.Forsyth	db.maxbno = int (d.length*big BYTESIZ - big 1);
65*37da2899SCharles.Forsyth	return db;
66*37da2899SCharles.Forsyth}
67*37da2899SCharles.Forsyth
68*37da2899SCharles.ForsythDbf.flush(db: self ref Dbf)
69*37da2899SCharles.Forsyth{
70*37da2899SCharles.Forsyth	db.pagbno = db.dirbno = -1;
71*37da2899SCharles.Forsyth}
72*37da2899SCharles.Forsyth
73*37da2899SCharles.ForsythDbf.isrdonly(db: self ref Dbf): int
74*37da2899SCharles.Forsyth{
75*37da2899SCharles.Forsyth	return db.flags == OREAD;
76*37da2899SCharles.Forsyth}
77*37da2899SCharles.Forsyth
78*37da2899SCharles.ForsythDbf.fetch(db: self ref Dbf, key: Datum): Datum
79*37da2899SCharles.Forsyth{
80*37da2899SCharles.Forsyth	access(db, calchash(key));
81*37da2899SCharles.Forsyth	for(i:=0;; i+=2){
82*37da2899SCharles.Forsyth		item := makdatum(db.pagbuf, i);
83*37da2899SCharles.Forsyth		if(item == nil)
84*37da2899SCharles.Forsyth			return item;
85*37da2899SCharles.Forsyth		if(cmpdatum(key, item) == 0){
86*37da2899SCharles.Forsyth			item = makdatum(db.pagbuf, i+1);
87*37da2899SCharles.Forsyth			if(item == nil){
88*37da2899SCharles.Forsyth				sys->fprint(sys->fildes(2), "dbm: items not in pairs\n");
89*37da2899SCharles.Forsyth				raise "dbm: items not in pairs";
90*37da2899SCharles.Forsyth			}
91*37da2899SCharles.Forsyth			return item;
92*37da2899SCharles.Forsyth		}
93*37da2899SCharles.Forsyth	}
94*37da2899SCharles.Forsyth}
95*37da2899SCharles.Forsyth
96*37da2899SCharles.ForsythDbf.delete(db: self ref Dbf, key: Datum): int
97*37da2899SCharles.Forsyth{
98*37da2899SCharles.Forsyth	if(db.isrdonly())
99*37da2899SCharles.Forsyth		return -1;
100*37da2899SCharles.Forsyth	access(db, calchash(key));
101*37da2899SCharles.Forsyth	for(i:=0;; i+=2){
102*37da2899SCharles.Forsyth		item := makdatum(db.pagbuf, i);
103*37da2899SCharles.Forsyth		if(item == nil)
104*37da2899SCharles.Forsyth			return -1;
105*37da2899SCharles.Forsyth		if(cmpdatum(key, item) == 0){
106*37da2899SCharles.Forsyth			delitem(db.pagbuf, i);
107*37da2899SCharles.Forsyth			delitem(db.pagbuf, i);
108*37da2899SCharles.Forsyth			break;
109*37da2899SCharles.Forsyth		}
110*37da2899SCharles.Forsyth	}
111*37da2899SCharles.Forsyth	sys->seek(db.pagf, big db.blkno*big PBLKSIZ, 0);
112*37da2899SCharles.Forsyth	write(db.pagf, db.pagbuf, PBLKSIZ);
113*37da2899SCharles.Forsyth	db.pagbno = db.blkno;
114*37da2899SCharles.Forsyth	return 0;
115*37da2899SCharles.Forsyth}
116*37da2899SCharles.Forsyth
117*37da2899SCharles.ForsythDbf.store(db: self ref Dbf, key: Datum, dat: Datum, replace: int): int
118*37da2899SCharles.Forsyth{
119*37da2899SCharles.Forsyth	if(db.isrdonly())
120*37da2899SCharles.Forsyth		return -1;
121*37da2899SCharles.Forsyth	for(;;){
122*37da2899SCharles.Forsyth		access(db, calchash(key));
123*37da2899SCharles.Forsyth		for(i:=0;; i+=2){
124*37da2899SCharles.Forsyth			item := makdatum(db.pagbuf, i);
125*37da2899SCharles.Forsyth			if(item == nil)
126*37da2899SCharles.Forsyth				break;
127*37da2899SCharles.Forsyth			if(cmpdatum(key, item) == 0){
128*37da2899SCharles.Forsyth				if(!replace)
129*37da2899SCharles.Forsyth					return 1;
130*37da2899SCharles.Forsyth				delitem(db.pagbuf, i);
131*37da2899SCharles.Forsyth				delitem(db.pagbuf, i);
132*37da2899SCharles.Forsyth				break;
133*37da2899SCharles.Forsyth			}
134*37da2899SCharles.Forsyth		}
135*37da2899SCharles.Forsyth		i = additem(db.pagbuf, key);
136*37da2899SCharles.Forsyth		if(i >= 0){
137*37da2899SCharles.Forsyth			if(additem(db.pagbuf, dat) >= 0)
138*37da2899SCharles.Forsyth				break;
139*37da2899SCharles.Forsyth			delitem(db.pagbuf, i);
140*37da2899SCharles.Forsyth		}
141*37da2899SCharles.Forsyth		if(!split(db, key, dat))
142*37da2899SCharles.Forsyth			return -1;
143*37da2899SCharles.Forsyth	}
144*37da2899SCharles.Forsyth	sys->seek(db.pagf, big db.blkno*big PBLKSIZ, 0);
145*37da2899SCharles.Forsyth	write(db.pagf, db.pagbuf, PBLKSIZ);
146*37da2899SCharles.Forsyth	db.pagbno = db.blkno;
147*37da2899SCharles.Forsyth	return 0;
148*37da2899SCharles.Forsyth}
149*37da2899SCharles.Forsyth
150*37da2899SCharles.Forsythsplit(db: ref Dbf, key: Datum, dat: Datum): int
151*37da2899SCharles.Forsyth{
152*37da2899SCharles.Forsyth	if(len key+len dat+3*SHORTSIZ >= PBLKSIZ)
153*37da2899SCharles.Forsyth		return 0;
154*37da2899SCharles.Forsyth	ovfbuf := array[PBLKSIZ] of {* => byte 0};
155*37da2899SCharles.Forsyth	for(i:=0;;){
156*37da2899SCharles.Forsyth		item := makdatum(db.pagbuf, i);
157*37da2899SCharles.Forsyth		if(item == nil)
158*37da2899SCharles.Forsyth			break;
159*37da2899SCharles.Forsyth		if(calchash(item) & (db.hmask+1)){
160*37da2899SCharles.Forsyth			additem(ovfbuf, item);
161*37da2899SCharles.Forsyth			delitem(db.pagbuf, i);
162*37da2899SCharles.Forsyth			item = makdatum(db.pagbuf, i);
163*37da2899SCharles.Forsyth			if(item == nil){
164*37da2899SCharles.Forsyth				sys->fprint(sys->fildes(2), "dbm: split not paired\n");
165*37da2899SCharles.Forsyth				raise "dbm: split not paired";
166*37da2899SCharles.Forsyth				#break;
167*37da2899SCharles.Forsyth			}
168*37da2899SCharles.Forsyth			additem(ovfbuf, item);
169*37da2899SCharles.Forsyth			delitem(db.pagbuf, i);
170*37da2899SCharles.Forsyth			continue;
171*37da2899SCharles.Forsyth		}
172*37da2899SCharles.Forsyth		i += 2;
173*37da2899SCharles.Forsyth	}
174*37da2899SCharles.Forsyth	sys->seek(db.pagf, big db.blkno*big PBLKSIZ, 0);
175*37da2899SCharles.Forsyth	write(db.pagf, db.pagbuf, PBLKSIZ);
176*37da2899SCharles.Forsyth	db.pagbno = db.blkno;
177*37da2899SCharles.Forsyth	sys->seek(db.pagf, (big db.blkno+big db.hmask+big 1)*big PBLKSIZ, 0);
178*37da2899SCharles.Forsyth	write(db.pagf, ovfbuf, PBLKSIZ);
179*37da2899SCharles.Forsyth	setbit(db);
180*37da2899SCharles.Forsyth	return 1;
181*37da2899SCharles.Forsyth}
182*37da2899SCharles.Forsyth
183*37da2899SCharles.ForsythDbf.firstkey(db: self ref Dbf): Datum
184*37da2899SCharles.Forsyth{
185*37da2899SCharles.Forsyth	return copy(firsthash(db, 0));
186*37da2899SCharles.Forsyth}
187*37da2899SCharles.Forsyth
188*37da2899SCharles.ForsythDbf.nextkey(db: self ref Dbf, key: Datum): Datum
189*37da2899SCharles.Forsyth{
190*37da2899SCharles.Forsyth	hash := calchash(key);
191*37da2899SCharles.Forsyth	access(db, hash);
192*37da2899SCharles.Forsyth	item, bitem: Datum;
193*37da2899SCharles.Forsyth	for(i:=0;; i+=2){
194*37da2899SCharles.Forsyth		item = makdatum(db.pagbuf, i);
195*37da2899SCharles.Forsyth		if(item == nil)
196*37da2899SCharles.Forsyth			break;
197*37da2899SCharles.Forsyth		if(cmpdatum(key, item) <= 0)
198*37da2899SCharles.Forsyth			continue;
199*37da2899SCharles.Forsyth		if(bitem == nil || cmpdatum(bitem, item) < 0)
200*37da2899SCharles.Forsyth			bitem = item;
201*37da2899SCharles.Forsyth	}
202*37da2899SCharles.Forsyth	if(bitem != nil)
203*37da2899SCharles.Forsyth		return copy(bitem);
204*37da2899SCharles.Forsyth	hash = hashinc(db, hash);
205*37da2899SCharles.Forsyth	if(hash == 0)
206*37da2899SCharles.Forsyth		return copy(item);
207*37da2899SCharles.Forsyth	return copy(firsthash(db, hash));
208*37da2899SCharles.Forsyth}
209*37da2899SCharles.Forsyth
210*37da2899SCharles.Forsythfirsthash(db: ref Dbf, hash: int): Datum
211*37da2899SCharles.Forsyth{
212*37da2899SCharles.Forsyth	for(;;){
213*37da2899SCharles.Forsyth		access(db, hash);
214*37da2899SCharles.Forsyth		bitem := makdatum(db.pagbuf, 0);
215*37da2899SCharles.Forsyth		item: Datum;
216*37da2899SCharles.Forsyth		for(i:=2;; i+=2){
217*37da2899SCharles.Forsyth			item = makdatum(db.pagbuf, i);
218*37da2899SCharles.Forsyth			if(item == nil)
219*37da2899SCharles.Forsyth				break;
220*37da2899SCharles.Forsyth			if(cmpdatum(bitem, item) < 0)
221*37da2899SCharles.Forsyth				bitem = item;
222*37da2899SCharles.Forsyth		}
223*37da2899SCharles.Forsyth		if(bitem != nil)
224*37da2899SCharles.Forsyth			return bitem;
225*37da2899SCharles.Forsyth		hash = hashinc(db, hash);
226*37da2899SCharles.Forsyth		if(hash == 0)
227*37da2899SCharles.Forsyth			return item;
228*37da2899SCharles.Forsyth	}
229*37da2899SCharles.Forsyth}
230*37da2899SCharles.Forsyth
231*37da2899SCharles.Forsythaccess(db: ref Dbf, hash: int)
232*37da2899SCharles.Forsyth{
233*37da2899SCharles.Forsyth	for(db.hmask=0;; db.hmask=(db.hmask<<1)+1){
234*37da2899SCharles.Forsyth		db.blkno = hash & db.hmask;
235*37da2899SCharles.Forsyth		db.bitno = db.blkno + db.hmask;
236*37da2899SCharles.Forsyth		if(getbit(db) == 0)
237*37da2899SCharles.Forsyth			break;
238*37da2899SCharles.Forsyth	}
239*37da2899SCharles.Forsyth	if(db.blkno != db.pagbno){
240*37da2899SCharles.Forsyth		sys->seek(db.pagf, big db.blkno * big PBLKSIZ, 0);
241*37da2899SCharles.Forsyth		read(db.pagf, db.pagbuf, PBLKSIZ);
242*37da2899SCharles.Forsyth		chkblk(db.pagbuf);
243*37da2899SCharles.Forsyth		db.pagbno = db.blkno;
244*37da2899SCharles.Forsyth	}
245*37da2899SCharles.Forsyth}
246*37da2899SCharles.Forsyth
247*37da2899SCharles.Forsythgetbit(db: ref Dbf): int
248*37da2899SCharles.Forsyth{
249*37da2899SCharles.Forsyth	if(db.bitno > db.maxbno)
250*37da2899SCharles.Forsyth		return 0;
251*37da2899SCharles.Forsyth	n := db.bitno % BYTESIZ;
252*37da2899SCharles.Forsyth	bn := db.bitno / BYTESIZ;
253*37da2899SCharles.Forsyth	i := bn % DBLKSIZ;
254*37da2899SCharles.Forsyth	b := bn / DBLKSIZ;
255*37da2899SCharles.Forsyth	if(b != db.dirbno){
256*37da2899SCharles.Forsyth		sys->seek(db.dirf, big b * big DBLKSIZ, 0);
257*37da2899SCharles.Forsyth		read(db.dirf, db.dirbuf, DBLKSIZ);
258*37da2899SCharles.Forsyth		db.dirbno = b;
259*37da2899SCharles.Forsyth	}
260*37da2899SCharles.Forsyth	if(int db.dirbuf[i] & (1<<n))
261*37da2899SCharles.Forsyth		return 1;
262*37da2899SCharles.Forsyth	return 0;
263*37da2899SCharles.Forsyth}
264*37da2899SCharles.Forsyth
265*37da2899SCharles.Forsythsetbit(db: ref Dbf)
266*37da2899SCharles.Forsyth{
267*37da2899SCharles.Forsyth	if(db.bitno > db.maxbno){
268*37da2899SCharles.Forsyth		db.maxbno = db.bitno;
269*37da2899SCharles.Forsyth		getbit(db);
270*37da2899SCharles.Forsyth	}
271*37da2899SCharles.Forsyth	n := db.bitno % BYTESIZ;
272*37da2899SCharles.Forsyth	bn := db.bitno / BYTESIZ;
273*37da2899SCharles.Forsyth	i := bn % DBLKSIZ;
274*37da2899SCharles.Forsyth	b := bn / DBLKSIZ;
275*37da2899SCharles.Forsyth	db.dirbuf[i] |= byte (1<<n);
276*37da2899SCharles.Forsyth	sys->seek(db.dirf, big b * big DBLKSIZ, 0);
277*37da2899SCharles.Forsyth	write(db.dirf, db.dirbuf, DBLKSIZ);
278*37da2899SCharles.Forsyth	db.dirbno = b;
279*37da2899SCharles.Forsyth}
280*37da2899SCharles.Forsyth
281*37da2899SCharles.Forsythmakdatum(buf: array of byte, n: int): Datum
282*37da2899SCharles.Forsyth{
283*37da2899SCharles.Forsyth	ne := GETS(buf, 0);
284*37da2899SCharles.Forsyth	if(n < 0 || n >= ne)
285*37da2899SCharles.Forsyth		return nil;
286*37da2899SCharles.Forsyth	t := PBLKSIZ;
287*37da2899SCharles.Forsyth	if(n > 0)
288*37da2899SCharles.Forsyth		t = GETS(buf, n+1-1);
289*37da2899SCharles.Forsyth	v := GETS(buf, n+1);
290*37da2899SCharles.Forsyth	return buf[v: t];	# size is t-v
291*37da2899SCharles.Forsyth}
292*37da2899SCharles.Forsyth
293*37da2899SCharles.Forsythcmpdatum(d1: Datum, d2: Datum): int
294*37da2899SCharles.Forsyth{
295*37da2899SCharles.Forsyth	n := len d1;
296*37da2899SCharles.Forsyth	if(n != len d2)
297*37da2899SCharles.Forsyth		return n - len d2;
298*37da2899SCharles.Forsyth	if(n == 0)
299*37da2899SCharles.Forsyth		return 0;
300*37da2899SCharles.Forsyth	for(i := 0; i < len d1; i++)
301*37da2899SCharles.Forsyth		if(d1[i] != d2[i])
302*37da2899SCharles.Forsyth			return int d1[i] - int d2[i];
303*37da2899SCharles.Forsyth	return 0;
304*37da2899SCharles.Forsyth}
305*37da2899SCharles.Forsyth
306*37da2899SCharles.Forsythcopy(d: Datum): Datum
307*37da2899SCharles.Forsyth{
308*37da2899SCharles.Forsyth	if(d == nil)
309*37da2899SCharles.Forsyth		return nil;
310*37da2899SCharles.Forsyth	a := array[len d] of byte;
311*37da2899SCharles.Forsyth	a[0:] = d;
312*37da2899SCharles.Forsyth	return a;
313*37da2899SCharles.Forsyth}
314*37da2899SCharles.Forsyth
315*37da2899SCharles.Forsyth# ken's
316*37da2899SCharles.Forsyth#
317*37da2899SCharles.Forsyth#	055,043,036,054,063,014,004,005,
318*37da2899SCharles.Forsyth#	010,064,077,000,035,027,025,071,
319*37da2899SCharles.Forsyth#
320*37da2899SCharles.Forsyth
321*37da2899SCharles.Forsythhitab := array[16] of {
322*37da2899SCharles.Forsyth         61, 57, 53, 49, 45, 41, 37, 33,
323*37da2899SCharles.Forsyth	29, 25, 21, 17, 13,  9,  5,  1,
324*37da2899SCharles.Forsyth};
325*37da2899SCharles.Forsyth
326*37da2899SCharles.Forsythhltab := array[64] of {
327*37da2899SCharles.Forsyth	8r6100151277,8r6106161736,8r6452611562,8r5001724107,
328*37da2899SCharles.Forsyth	8r2614772546,8r4120731531,8r4665262210,8r7347467531,
329*37da2899SCharles.Forsyth	8r6735253126,8r6042345173,8r3072226605,8r1464164730,
330*37da2899SCharles.Forsyth	8r3247435524,8r7652510057,8r1546775256,8r5714532133,
331*37da2899SCharles.Forsyth	8r6173260402,8r7517101630,8r2431460343,8r1743245566,
332*37da2899SCharles.Forsyth	8r0261675137,8r2433103631,8r3421772437,8r4447707466,
333*37da2899SCharles.Forsyth	8r4435620103,8r3757017115,8r3641531772,8r6767633246,
334*37da2899SCharles.Forsyth	8r2673230344,8r0260612216,8r4133454451,8r0615531516,
335*37da2899SCharles.Forsyth	8r6137717526,8r2574116560,8r2304023373,8r7061702261,
336*37da2899SCharles.Forsyth	8r5153031405,8r5322056705,8r7401116734,8r6552375715,
337*37da2899SCharles.Forsyth	8r6165233473,8r5311063631,8r1212221723,8r1052267235,
338*37da2899SCharles.Forsyth	8r6000615237,8r1075222665,8r6330216006,8r4402355630,
339*37da2899SCharles.Forsyth	8r1451177262,8r2000133436,8r6025467062,8r7121076461,
340*37da2899SCharles.Forsyth	8r3123433522,8r1010635225,8r1716177066,8r5161746527,
341*37da2899SCharles.Forsyth	8r1736635071,8r6243505026,8r3637211610,8r1756474365,
342*37da2899SCharles.Forsyth	8r4723077174,8r3642763134,8r5750130273,8r3655541561,
343*37da2899SCharles.Forsyth};
344*37da2899SCharles.Forsyth
345*37da2899SCharles.Forsythhashinc(db: ref Dbf, hash: int): int
346*37da2899SCharles.Forsyth{
347*37da2899SCharles.Forsyth	hash &= db.hmask;
348*37da2899SCharles.Forsyth	bit := db.hmask+1;
349*37da2899SCharles.Forsyth	for(;;){
350*37da2899SCharles.Forsyth		bit >>= 1;
351*37da2899SCharles.Forsyth		if(bit == 0)
352*37da2899SCharles.Forsyth			return 0;
353*37da2899SCharles.Forsyth		if((hash&bit) == 0)
354*37da2899SCharles.Forsyth			return hash|bit;
355*37da2899SCharles.Forsyth		hash &= ~bit;
356*37da2899SCharles.Forsyth	}
357*37da2899SCharles.Forsyth}
358*37da2899SCharles.Forsyth
359*37da2899SCharles.Forsythcalchash(item: Datum): int
360*37da2899SCharles.Forsyth{
361*37da2899SCharles.Forsyth	hashl := 0;
362*37da2899SCharles.Forsyth	hashi := 0;
363*37da2899SCharles.Forsyth	for(i:=0; i<len item; i++){
364*37da2899SCharles.Forsyth		f := int item[i];
365*37da2899SCharles.Forsyth		for(j:=0; j<BYTESIZ; j+=4){
366*37da2899SCharles.Forsyth			hashi += hitab[f&16rF];
367*37da2899SCharles.Forsyth			hashl += hltab[hashi&16r3F];
368*37da2899SCharles.Forsyth			f >>= 4;
369*37da2899SCharles.Forsyth		}
370*37da2899SCharles.Forsyth	}
371*37da2899SCharles.Forsyth	return hashl;
372*37da2899SCharles.Forsyth}
373*37da2899SCharles.Forsyth
374*37da2899SCharles.Forsythdelitem(buf: array of byte, n: int)
375*37da2899SCharles.Forsyth{
376*37da2899SCharles.Forsyth	ne := GETS(buf, 0);
377*37da2899SCharles.Forsyth	if(n < 0 || n >= ne){
378*37da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "dbm: bad delitem\n");
379*37da2899SCharles.Forsyth		raise "dbm: bad delitem";
380*37da2899SCharles.Forsyth	}
381*37da2899SCharles.Forsyth	i1 := GETS(buf, n+1);
382*37da2899SCharles.Forsyth	i2 := PBLKSIZ;
383*37da2899SCharles.Forsyth	if(n > 0)
384*37da2899SCharles.Forsyth		i2 = GETS(buf, n+1-1);
385*37da2899SCharles.Forsyth	i3 := GETS(buf, ne+1-1);
386*37da2899SCharles.Forsyth	if(i2 > i1)
387*37da2899SCharles.Forsyth		while(i1 > i3){
388*37da2899SCharles.Forsyth			i1--;
389*37da2899SCharles.Forsyth			i2--;
390*37da2899SCharles.Forsyth			buf[i2] = buf[i1];
391*37da2899SCharles.Forsyth			buf[i1] = byte 0;
392*37da2899SCharles.Forsyth		}
393*37da2899SCharles.Forsyth	i2 -= i1;
394*37da2899SCharles.Forsyth	for(i1=n+1; i1<ne; i1++)
395*37da2899SCharles.Forsyth		PUTS(buf, i1+1-1, GETS(buf, i1+1) + i2);
396*37da2899SCharles.Forsyth	PUTS(buf, 0, ne-1);
397*37da2899SCharles.Forsyth	PUTS(buf, ne, 0);
398*37da2899SCharles.Forsyth}
399*37da2899SCharles.Forsyth
400*37da2899SCharles.Forsythadditem(buf: array of byte, item: Datum): int
401*37da2899SCharles.Forsyth{
402*37da2899SCharles.Forsyth	i1 := PBLKSIZ;
403*37da2899SCharles.Forsyth	ne := GETS(buf, 0);
404*37da2899SCharles.Forsyth	if(ne > 0)
405*37da2899SCharles.Forsyth		i1 = GETS(buf, ne+1-1);
406*37da2899SCharles.Forsyth	i1 -= len item;
407*37da2899SCharles.Forsyth	i2 := (ne+2) * SHORTSIZ;
408*37da2899SCharles.Forsyth	if(i1 <= i2)
409*37da2899SCharles.Forsyth		return -1;
410*37da2899SCharles.Forsyth	PUTS(buf, ne+1, i1);
411*37da2899SCharles.Forsyth	buf[i1:] = item;
412*37da2899SCharles.Forsyth	PUTS(buf, 0, ne+1);
413*37da2899SCharles.Forsyth	return ne;
414*37da2899SCharles.Forsyth}
415*37da2899SCharles.Forsyth
416*37da2899SCharles.Forsythchkblk(buf: array of byte)
417*37da2899SCharles.Forsyth{
418*37da2899SCharles.Forsyth	t := PBLKSIZ;
419*37da2899SCharles.Forsyth	ne := GETS(buf, 0);
420*37da2899SCharles.Forsyth	for(i:=0; i<ne; i++){
421*37da2899SCharles.Forsyth		v := GETS(buf, i+1);
422*37da2899SCharles.Forsyth		if(v > t)
423*37da2899SCharles.Forsyth			badblk();
424*37da2899SCharles.Forsyth		t = v;
425*37da2899SCharles.Forsyth	}
426*37da2899SCharles.Forsyth	if(t < (ne+1)*SHORTSIZ)
427*37da2899SCharles.Forsyth		badblk();
428*37da2899SCharles.Forsyth}
429*37da2899SCharles.Forsyth
430*37da2899SCharles.Forsythread(fd: ref Sys->FD, buf: array of byte, n: int)
431*37da2899SCharles.Forsyth{
432*37da2899SCharles.Forsyth	nr := sys->read(fd, buf, n);
433*37da2899SCharles.Forsyth	if(nr == 0){
434*37da2899SCharles.Forsyth		for(i := 0; i < len buf; i++)
435*37da2899SCharles.Forsyth			buf[i] = byte 0;
436*37da2899SCharles.Forsyth	}else if(nr != n)
437*37da2899SCharles.Forsyth		raise "dbm: read error: "+sys->sprint("%r");
438*37da2899SCharles.Forsyth}
439*37da2899SCharles.Forsyth
440*37da2899SCharles.Forsythwrite(fd: ref Sys->FD, buf: array of byte, n: int)
441*37da2899SCharles.Forsyth{
442*37da2899SCharles.Forsyth	if(sys->write(fd, buf, n) != n)
443*37da2899SCharles.Forsyth		raise "dbm: write error: "+sys->sprint("%r");
444*37da2899SCharles.Forsyth}
445*37da2899SCharles.Forsyth
446*37da2899SCharles.Forsythbadblk()
447*37da2899SCharles.Forsyth{
448*37da2899SCharles.Forsyth	sys->fprint(sys->fildes(2), "dbm: bad block\n");
449*37da2899SCharles.Forsyth	raise "dbm: bad block";
450*37da2899SCharles.Forsyth}
451*37da2899SCharles.Forsyth
452*37da2899SCharles.ForsythGETS(buf: array of byte, sh: int): int
453*37da2899SCharles.Forsyth{
454*37da2899SCharles.Forsyth	sh *= SHORTSIZ;
455*37da2899SCharles.Forsyth	return (int buf[sh]<<8) | int buf[sh+1];
456*37da2899SCharles.Forsyth}
457*37da2899SCharles.Forsyth
458*37da2899SCharles.ForsythPUTS(buf: array of byte, sh: int, v: int)
459*37da2899SCharles.Forsyth{
460*37da2899SCharles.Forsyth	sh *= SHORTSIZ;
461*37da2899SCharles.Forsyth	buf[sh] = byte (v>>8);
462*37da2899SCharles.Forsyth	buf[sh+1] = byte v;
463*37da2899SCharles.Forsyth}
464