xref: /inferno-os/appl/lib/attrdb.b (revision 9b29ac7ea714507a9c0690620c02c8ca5ab25f90)
137da2899SCharles.Forsythimplement Attrdb;
237da2899SCharles.Forsyth
337da2899SCharles.Forsyth#
437da2899SCharles.Forsyth# Copyright © 2003 Vita Nuova Holdings Limited.  All rights reserved.
537da2899SCharles.Forsyth#
637da2899SCharles.Forsyth
737da2899SCharles.Forsythinclude "sys.m";
837da2899SCharles.Forsyth	sys: Sys;
937da2899SCharles.Forsyth
1037da2899SCharles.Forsythinclude "bufio.m";
1137da2899SCharles.Forsyth	bufio: Bufio;
1237da2899SCharles.Forsyth	Iobuf: import bufio;
1337da2899SCharles.Forsyth
1437da2899SCharles.Forsythinclude "attrdb.m";
1537da2899SCharles.Forsyth
1637da2899SCharles.Forsythinit(): string
1737da2899SCharles.Forsyth{
1837da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
1937da2899SCharles.Forsyth	bufio = load Bufio Bufio->PATH;
2037da2899SCharles.Forsyth	if(bufio == nil)
2137da2899SCharles.Forsyth		return sys->sprint("can't load Bufio: %r");
2237da2899SCharles.Forsyth	return nil;
2337da2899SCharles.Forsyth}
2437da2899SCharles.Forsyth
2537da2899SCharles.Forsythparseentry(s: string, lno: int): (ref Dbentry, int, string)
2637da2899SCharles.Forsyth{
2737da2899SCharles.Forsyth	(nil, flds) := sys->tokenize(s, "\n");
2837da2899SCharles.Forsyth	lines: list of ref Tuples;
2937da2899SCharles.Forsyth	errs: string;
3037da2899SCharles.Forsyth	for(; flds != nil; flds = tl flds){
3137da2899SCharles.Forsyth		(ts, err) := parseline(hd flds, lno);
3237da2899SCharles.Forsyth		if(ts != nil)
3337da2899SCharles.Forsyth			lines = ts :: lines;
3437da2899SCharles.Forsyth		else if(err != nil && errs == nil)
3537da2899SCharles.Forsyth			errs = err;
3637da2899SCharles.Forsyth		lno++;
3737da2899SCharles.Forsyth	}
3837da2899SCharles.Forsyth	return (ref Dbentry(0, lines), lno, errs);
3937da2899SCharles.Forsyth}
4037da2899SCharles.Forsyth
4137da2899SCharles.Forsythparseline(s: string, lno: int): (ref Tuples, string)
4237da2899SCharles.Forsyth{
4337da2899SCharles.Forsyth	attrs: list of ref Attr;
4437da2899SCharles.Forsyth	quote := 0;
4537da2899SCharles.Forsyth	word := "";
4637da2899SCharles.Forsyth	lastword := "";
4737da2899SCharles.Forsyth	name := "";
4837da2899SCharles.Forsyth
4937da2899SCharles.ForsythLine:
5037da2899SCharles.Forsyth	for(i := 0; i < len s; i++) {
5137da2899SCharles.Forsyth		if(quote) {
5237da2899SCharles.Forsyth			if(s[i] == quote) {
5337da2899SCharles.Forsyth				if(i+1 >= len s || s[i+1] != quote){
5437da2899SCharles.Forsyth					quote = 0;
5537da2899SCharles.Forsyth					continue;
5637da2899SCharles.Forsyth				}
5737da2899SCharles.Forsyth				i++;
5837da2899SCharles.Forsyth			}
5937da2899SCharles.Forsyth			word[len word] = s[i];
6037da2899SCharles.Forsyth			continue;
6137da2899SCharles.Forsyth		}
6237da2899SCharles.Forsyth		case s[i] {
6337da2899SCharles.Forsyth		'\'' or '\"' =>
6437da2899SCharles.Forsyth			quote = s[i];
6537da2899SCharles.Forsyth		'#' =>
6637da2899SCharles.Forsyth			break Line;
6737da2899SCharles.Forsyth		' ' or '\t' or '\n' =>
6837da2899SCharles.Forsyth			if(word == nil)
6937da2899SCharles.Forsyth				continue;
7037da2899SCharles.Forsyth			if(lastword != nil) {
7137da2899SCharles.Forsyth				# lastword space word space
7237da2899SCharles.Forsyth				attrs = ref Attr(lastword, nil, 0) :: attrs;
7337da2899SCharles.Forsyth			}
7437da2899SCharles.Forsyth			lastword = word;
7537da2899SCharles.Forsyth			word = nil;
7637da2899SCharles.Forsyth
7737da2899SCharles.Forsyth			if(name != nil) {
7837da2899SCharles.Forsyth				# name = lastword space
7937da2899SCharles.Forsyth				attrs = ref Attr(name, lastword, 0) :: attrs;
8037da2899SCharles.Forsyth				name = lastword = nil;
8137da2899SCharles.Forsyth			}
8237da2899SCharles.Forsyth		'=' =>
8337da2899SCharles.Forsyth			if(lastword == nil) {
8437da2899SCharles.Forsyth				# word=
8537da2899SCharles.Forsyth				lastword = word;
8637da2899SCharles.Forsyth				word = nil;
8737da2899SCharles.Forsyth			}
8837da2899SCharles.Forsyth			if(word != nil) {
8937da2899SCharles.Forsyth				# lastword word=
9037da2899SCharles.Forsyth				attrs = ref Attr(lastword, nil, 0) :: attrs;
9137da2899SCharles.Forsyth				lastword = word;
9237da2899SCharles.Forsyth				word = nil;
9337da2899SCharles.Forsyth			}
9437da2899SCharles.Forsyth			if(lastword == nil)
9537da2899SCharles.Forsyth				return (nil, "empty name");
9637da2899SCharles.Forsyth			name = lastword;
9737da2899SCharles.Forsyth			lastword = nil;
9837da2899SCharles.Forsyth		* =>
9937da2899SCharles.Forsyth			word[len word] = s[i];
10037da2899SCharles.Forsyth		}
10137da2899SCharles.Forsyth	}
10237da2899SCharles.Forsyth	if(quote)
10337da2899SCharles.Forsyth		return (nil, "missing quote");
10437da2899SCharles.Forsyth
10537da2899SCharles.Forsyth	if(lastword == nil) {
10637da2899SCharles.Forsyth		lastword = word;
10737da2899SCharles.Forsyth		word = nil;
10837da2899SCharles.Forsyth	}
10937da2899SCharles.Forsyth
11037da2899SCharles.Forsyth	if(name == nil) {
11137da2899SCharles.Forsyth		name = lastword;
11237da2899SCharles.Forsyth		lastword = nil;
11337da2899SCharles.Forsyth	}
11437da2899SCharles.Forsyth
11537da2899SCharles.Forsyth	if(name != nil)
11637da2899SCharles.Forsyth		attrs = ref Attr(name, lastword, 0) :: attrs;
11737da2899SCharles.Forsyth
11837da2899SCharles.Forsyth	if(attrs == nil)
11937da2899SCharles.Forsyth		return (nil, nil);
12037da2899SCharles.Forsyth
12137da2899SCharles.Forsyth	return (ref Tuples(lno, rev(attrs)), nil);
12237da2899SCharles.Forsyth
12337da2899SCharles.Forsyth}
12437da2899SCharles.Forsyth
12537da2899SCharles.ForsythTuples.hasattr(ts: self ref Tuples, attr: string): int
12637da2899SCharles.Forsyth{
12737da2899SCharles.Forsyth	for(pl := ts.pairs; pl != nil; pl = tl pl){
12837da2899SCharles.Forsyth		a := hd pl;
12937da2899SCharles.Forsyth		if(a.attr == attr)
13037da2899SCharles.Forsyth			return 1;
13137da2899SCharles.Forsyth	}
13237da2899SCharles.Forsyth	return 0;
13337da2899SCharles.Forsyth}
13437da2899SCharles.Forsyth
13537da2899SCharles.ForsythTuples.haspair(ts: self ref Tuples, attr: string, value: string): int
13637da2899SCharles.Forsyth{
13737da2899SCharles.Forsyth	for(pl := ts.pairs; pl != nil; pl = tl pl){
13837da2899SCharles.Forsyth		a := hd pl;
13937da2899SCharles.Forsyth		if(a.attr == attr && a.val == value)
14037da2899SCharles.Forsyth			return 1;
14137da2899SCharles.Forsyth	}
14237da2899SCharles.Forsyth	return 0;
14337da2899SCharles.Forsyth}
14437da2899SCharles.Forsyth
14537da2899SCharles.ForsythTuples.find(ts: self ref Tuples, attr: string): list of ref Attr
14637da2899SCharles.Forsyth{
14737da2899SCharles.Forsyth	ra: list of ref Attr;
14837da2899SCharles.Forsyth	for(pl := ts.pairs; pl != nil; pl = tl pl){
14937da2899SCharles.Forsyth		a := hd pl;
15037da2899SCharles.Forsyth		if(a.attr == attr)
15137da2899SCharles.Forsyth			ra = a :: ra;
15237da2899SCharles.Forsyth	}
15337da2899SCharles.Forsyth	return rev(ra);
15437da2899SCharles.Forsyth}
15537da2899SCharles.Forsyth
15637da2899SCharles.ForsythTuples.findbyattr(ts: self ref Tuples, attr: string, value: string, rattr: string): list of ref Attr
15737da2899SCharles.Forsyth{
15837da2899SCharles.Forsyth	if(ts.haspair(attr, value))
15937da2899SCharles.Forsyth		return ts.find(rattr);
16037da2899SCharles.Forsyth	return nil;
16137da2899SCharles.Forsyth}
16237da2899SCharles.Forsyth
16337da2899SCharles.ForsythDbentry.find(e: self ref Dbentry, attr: string): list of (ref Tuples, list of ref Attr)
16437da2899SCharles.Forsyth{
16537da2899SCharles.Forsyth	rrt: list of (ref Tuples, list of ref Attr);
16637da2899SCharles.Forsyth	for(lines := e.lines; lines != nil; lines = tl lines){
16737da2899SCharles.Forsyth		l := hd lines;
16837da2899SCharles.Forsyth		if((ra := l.find(attr)) != nil)
16937da2899SCharles.Forsyth			rrt = (l, rev(ra)) :: rrt;
17037da2899SCharles.Forsyth	}
17137da2899SCharles.Forsyth	rt: list of (ref Tuples, list of ref Attr);
17237da2899SCharles.Forsyth	for(; rrt != nil; rrt = tl rrt)
17337da2899SCharles.Forsyth		rt = hd rrt :: rt;
17437da2899SCharles.Forsyth	return rt;
17537da2899SCharles.Forsyth}
17637da2899SCharles.Forsyth
17737da2899SCharles.ForsythDbentry.findfirst(e: self ref Dbentry, attr: string): string
17837da2899SCharles.Forsyth{
17937da2899SCharles.Forsyth	for(lines := e.lines; lines != nil; lines = tl lines){
18037da2899SCharles.Forsyth		l := hd lines;
18137da2899SCharles.Forsyth		for(pl := l.pairs; pl != nil; pl = tl pl)
18237da2899SCharles.Forsyth			if((hd pl).attr == attr)
18337da2899SCharles.Forsyth				return (hd pl).val;
18437da2899SCharles.Forsyth	}
18537da2899SCharles.Forsyth	return nil;
18637da2899SCharles.Forsyth}
18737da2899SCharles.Forsyth
18837da2899SCharles.ForsythDbentry.findpair(e: self ref Dbentry, attr: string, value: string): list of ref Tuples
18937da2899SCharles.Forsyth{
19037da2899SCharles.Forsyth	rts: list of ref Tuples;
19137da2899SCharles.Forsyth	for(lines := e.lines; lines != nil; lines = tl lines){
19237da2899SCharles.Forsyth		l := hd lines;
19337da2899SCharles.Forsyth		if(l.haspair(attr, value))
19437da2899SCharles.Forsyth			rts = l :: rts;
19537da2899SCharles.Forsyth	}
19637da2899SCharles.Forsyth	for(; rts != nil; rts = tl rts)
19737da2899SCharles.Forsyth		lines = hd rts :: lines;
19837da2899SCharles.Forsyth	return lines;
19937da2899SCharles.Forsyth}
20037da2899SCharles.Forsyth
20137da2899SCharles.ForsythDbentry.findbyattr(e: self ref Dbentry, attr: string, value: string, rattr: string): list of (ref Tuples, list of ref Attr)
20237da2899SCharles.Forsyth{
20337da2899SCharles.Forsyth	rm: list of (ref Tuples, list of ref Attr);	# lines with attr=value and rattr
20437da2899SCharles.Forsyth	rnm: list of (ref Tuples, list of ref Attr);	# lines with rattr alone
20537da2899SCharles.Forsyth	for(lines := e.lines; lines != nil; lines = tl lines){
20637da2899SCharles.Forsyth		l := hd lines;
20737da2899SCharles.Forsyth		ra: list of ref Attr = nil;
20837da2899SCharles.Forsyth		match := 0;
20937da2899SCharles.Forsyth		for(pl := l.pairs; pl != nil; pl = tl pl){
21037da2899SCharles.Forsyth			a := hd pl;
21137da2899SCharles.Forsyth			if(a.attr == attr && a.val == value)
21237da2899SCharles.Forsyth				match = 1;
21337da2899SCharles.Forsyth			if(a.attr == rattr)
21437da2899SCharles.Forsyth				ra = a :: ra;
21537da2899SCharles.Forsyth		}
21637da2899SCharles.Forsyth		if(ra != nil){
21737da2899SCharles.Forsyth			if(match)
21837da2899SCharles.Forsyth				rm = (l, rev(ra)) :: rm;
21937da2899SCharles.Forsyth			else
22037da2899SCharles.Forsyth				rnm = (l, rev(ra)) :: rnm;
22137da2899SCharles.Forsyth		}
22237da2899SCharles.Forsyth	}
22337da2899SCharles.Forsyth	rt: list of (ref Tuples, list of ref Attr);
22437da2899SCharles.Forsyth	for(; rnm != nil; rnm = tl rnm)
22537da2899SCharles.Forsyth		rt = hd rnm :: rt;
22637da2899SCharles.Forsyth	for(; rm != nil; rm = tl rm)
22737da2899SCharles.Forsyth		rt = hd rm :: rt;
22837da2899SCharles.Forsyth	return rt;
22937da2899SCharles.Forsyth}
23037da2899SCharles.Forsyth
23137da2899SCharles.ForsythDbf.open(path: string): ref Dbf
23237da2899SCharles.Forsyth{
23337da2899SCharles.Forsyth	df := ref Dbf;
23437da2899SCharles.Forsyth	df.lockc = chan[1] of int;
23537da2899SCharles.Forsyth	df.fd = bufio->open(path, Bufio->OREAD);
23637da2899SCharles.Forsyth	if(df.fd == nil)
23737da2899SCharles.Forsyth		return nil;
23837da2899SCharles.Forsyth	df.name = path;
23937da2899SCharles.Forsyth	(ok, d) := sys->fstat(df.fd.fd);
24037da2899SCharles.Forsyth	if(ok >= 0)
24137da2899SCharles.Forsyth		df.dir = ref d;
24237da2899SCharles.Forsyth	# TO DO: indices
24337da2899SCharles.Forsyth	return df;
24437da2899SCharles.Forsyth}
24537da2899SCharles.Forsyth
24637da2899SCharles.ForsythDbf.sopen(data: string): ref Dbf
24737da2899SCharles.Forsyth{
24837da2899SCharles.Forsyth	df := ref Dbf;
24937da2899SCharles.Forsyth	df.lockc = chan[1] of int;
25037da2899SCharles.Forsyth	df.fd = bufio->sopen(data);
25137da2899SCharles.Forsyth	if(df.fd == nil)
25237da2899SCharles.Forsyth		return nil;
25337da2899SCharles.Forsyth	df.name = nil;
25437da2899SCharles.Forsyth	df.dir = nil;
25537da2899SCharles.Forsyth	return df;
25637da2899SCharles.Forsyth}
25737da2899SCharles.Forsyth
25837da2899SCharles.ForsythDbf.reopen(df: self ref Dbf): int
25937da2899SCharles.Forsyth{
26037da2899SCharles.Forsyth	lock(df);
26137da2899SCharles.Forsyth	if(df.name == nil){
26237da2899SCharles.Forsyth		unlock(df);
26337da2899SCharles.Forsyth		return 0;
26437da2899SCharles.Forsyth	}
26537da2899SCharles.Forsyth	fd := bufio->open(df.name, Bufio->OREAD);
26637da2899SCharles.Forsyth	if(fd == nil){
26737da2899SCharles.Forsyth		unlock(df);
26837da2899SCharles.Forsyth		return -1;
26937da2899SCharles.Forsyth	}
27037da2899SCharles.Forsyth	df.fd = fd;
27137da2899SCharles.Forsyth	df.dir = nil;
27237da2899SCharles.Forsyth	(ok, d) := sys->fstat(fd.fd);
27337da2899SCharles.Forsyth	if(ok >= 0)
27437da2899SCharles.Forsyth		df.dir = ref d;
27537da2899SCharles.Forsyth	# TO DO: cache, hash tables
27637da2899SCharles.Forsyth	unlock(df);
27737da2899SCharles.Forsyth	return 0;
27837da2899SCharles.Forsyth}
27937da2899SCharles.Forsyth
28037da2899SCharles.ForsythDbf.changed(df: self ref Dbf): int
28137da2899SCharles.Forsyth{
28237da2899SCharles.Forsyth	r: int;
28337da2899SCharles.Forsyth
28437da2899SCharles.Forsyth	lock(df);
28537da2899SCharles.Forsyth	if(df.name == nil){
28637da2899SCharles.Forsyth		unlock(df);
28737da2899SCharles.Forsyth		return 0;
28837da2899SCharles.Forsyth	}
28937da2899SCharles.Forsyth	(ok, d) := sys->stat(df.name);
29037da2899SCharles.Forsyth	if(ok < 0)
29137da2899SCharles.Forsyth		r = df.fd != nil || df.dir == nil;
29237da2899SCharles.Forsyth	else
29337da2899SCharles.Forsyth		r = df.dir == nil || !samefile(*df.dir, d);
29437da2899SCharles.Forsyth	unlock(df);
29537da2899SCharles.Forsyth	return r;
29637da2899SCharles.Forsyth}
29737da2899SCharles.Forsyth
29837da2899SCharles.Forsythsamefile(d1, d2: Sys->Dir): int
29937da2899SCharles.Forsyth{
30037da2899SCharles.Forsyth	# ``it was black ... it was white!  it was dark ...  it was light! ah yes, i remember it well...''
30137da2899SCharles.Forsyth	return d1.dev==d2.dev && d1.dtype==d2.dtype &&
30237da2899SCharles.Forsyth			d1.qid.path==d2.qid.path && d1.qid.vers==d2.qid.vers &&
30337da2899SCharles.Forsyth			d1.mtime == d2.mtime;
30437da2899SCharles.Forsyth}
30537da2899SCharles.Forsyth
30637da2899SCharles.Forsythflatten(ts: list of (ref Tuples, list of ref Attr), attr: string): list of ref Attr
30737da2899SCharles.Forsyth{
30837da2899SCharles.Forsyth	l: list of ref Attr;
30937da2899SCharles.Forsyth	for(; ts != nil; ts = tl ts){
310*9b29ac7eSCharles.Forsyth		(line, nil) := hd ts;
31137da2899SCharles.Forsyth		t := line.find(attr);
31237da2899SCharles.Forsyth		for(; t != nil; t = tl t)
31337da2899SCharles.Forsyth			l = hd t :: l;
31437da2899SCharles.Forsyth	}
31537da2899SCharles.Forsyth	return rev(l);
31637da2899SCharles.Forsyth}
31737da2899SCharles.Forsyth
31837da2899SCharles.ForsythDb.open(path: string): ref Db
31937da2899SCharles.Forsyth{
32037da2899SCharles.Forsyth	df := Dbf.open(path);
32137da2899SCharles.Forsyth	if(df == nil)
32237da2899SCharles.Forsyth		return nil;
32337da2899SCharles.Forsyth	db := ref Db(df :: nil);
32437da2899SCharles.Forsyth	(e, nil) := db.findpair(nil, "database", "");
32537da2899SCharles.Forsyth	if(e != nil){
32637da2899SCharles.Forsyth		files := flatten(e.find("file"), "file");
32737da2899SCharles.Forsyth		if(files != nil){
32837da2899SCharles.Forsyth			dbs: list of ref Dbf;
32937da2899SCharles.Forsyth			for(; files != nil; files = tl files){
33037da2899SCharles.Forsyth				name := (hd files).val;
33137da2899SCharles.Forsyth				if(name == path && df != nil){
33237da2899SCharles.Forsyth					dbs = df :: dbs;
33337da2899SCharles.Forsyth					df = nil;
33437da2899SCharles.Forsyth				}else if((tf := Dbf.open(name)) != nil)
33537da2899SCharles.Forsyth					dbs = tf :: dbs;
33637da2899SCharles.Forsyth			}
33737da2899SCharles.Forsyth			db.dbs = rev(dbs);
33837da2899SCharles.Forsyth			if(df != nil)
33937da2899SCharles.Forsyth				db.dbs = df :: db.dbs;
34037da2899SCharles.Forsyth		}
34137da2899SCharles.Forsyth	}
34237da2899SCharles.Forsyth	return db;
34337da2899SCharles.Forsyth}
34437da2899SCharles.Forsyth
34537da2899SCharles.ForsythDb.sopen(data: string): ref Db
34637da2899SCharles.Forsyth{
34737da2899SCharles.Forsyth	df := Dbf.sopen(data);
34837da2899SCharles.Forsyth	if(df == nil)
34937da2899SCharles.Forsyth		return nil;
35037da2899SCharles.Forsyth	return ref Db(df :: nil);
35137da2899SCharles.Forsyth}
35237da2899SCharles.Forsyth
35337da2899SCharles.ForsythDb.append(db1: self ref Db, db2: ref Db): ref Db
35437da2899SCharles.Forsyth{
35537da2899SCharles.Forsyth	if(db1 == nil)
35637da2899SCharles.Forsyth		return db2;
35737da2899SCharles.Forsyth	if(db2 == nil)
35837da2899SCharles.Forsyth		return db1;
35937da2899SCharles.Forsyth	dbs := db2.dbs;
36037da2899SCharles.Forsyth	for(rl := rev(db1.dbs); rl != nil; rl = tl rl)
36137da2899SCharles.Forsyth		dbs = hd rl :: dbs;
36237da2899SCharles.Forsyth	return ref Db(dbs);
36337da2899SCharles.Forsyth}
36437da2899SCharles.Forsyth
36537da2899SCharles.ForsythDb.reopen(db: self ref Db): int
36637da2899SCharles.Forsyth{
36737da2899SCharles.Forsyth	f := 0;
36837da2899SCharles.Forsyth	for(dbs := db.dbs; dbs != nil; dbs = tl dbs)
36937da2899SCharles.Forsyth		if((hd dbs).reopen() < 0)
37037da2899SCharles.Forsyth			f = -1;
37137da2899SCharles.Forsyth	return f;
37237da2899SCharles.Forsyth}
37337da2899SCharles.Forsyth
37437da2899SCharles.ForsythDb.changed(db: self ref Db): int
37537da2899SCharles.Forsyth{
37637da2899SCharles.Forsyth	f := 0;
37737da2899SCharles.Forsyth	for(dbs := db.dbs; dbs != nil; dbs = tl dbs)
37837da2899SCharles.Forsyth		f |= (hd dbs).changed();
37937da2899SCharles.Forsyth	return f;
38037da2899SCharles.Forsyth}
38137da2899SCharles.Forsyth
38237da2899SCharles.Forsythisentry(l: string): int
38337da2899SCharles.Forsyth{
38437da2899SCharles.Forsyth	return l!=nil && l[0]!='\t' && l[0]!='\n' && l[0]!=' ' && l[0]!='#';
38537da2899SCharles.Forsyth}
38637da2899SCharles.Forsyth
38737da2899SCharles.ForsythDbf.readentry(dbf: self ref Dbf, offset: int, attr: string, value: string, useval: int): (ref Dbentry, int, int)
38837da2899SCharles.Forsyth{
38937da2899SCharles.Forsyth	lock(dbf);
39037da2899SCharles.Forsyth	fd := dbf.fd;
39137da2899SCharles.Forsyth	fd.seek(big offset, 0);
39237da2899SCharles.Forsyth	lines: list of ref Tuples;
39337da2899SCharles.Forsyth	match := attr == nil;
39437da2899SCharles.Forsyth	while((l := fd.gets('\n')) != nil){
39537da2899SCharles.Forsyth		while(isentry(l)){
39637da2899SCharles.Forsyth			lines = nil;
39737da2899SCharles.Forsyth			do{
39837da2899SCharles.Forsyth				offset = int fd.offset();
39937da2899SCharles.Forsyth				(t, nil) := parseline(l, 0);
40037da2899SCharles.Forsyth				if(t != nil){
40137da2899SCharles.Forsyth					lines = t :: lines;
40237da2899SCharles.Forsyth					if(!match){
40337da2899SCharles.Forsyth						if(useval)
40437da2899SCharles.Forsyth							match = t.haspair(attr, value);
40537da2899SCharles.Forsyth						else
40637da2899SCharles.Forsyth							match = t.hasattr(attr);
40737da2899SCharles.Forsyth					}
40837da2899SCharles.Forsyth				}
40937da2899SCharles.Forsyth				l = fd.gets('\n');
41037da2899SCharles.Forsyth			}while(l != nil && !isentry(l));
41137da2899SCharles.Forsyth			if(match && lines != nil){
41237da2899SCharles.Forsyth				rl := lines;
41337da2899SCharles.Forsyth				for(lines = nil; rl != nil; rl = tl rl)
41437da2899SCharles.Forsyth					lines = hd rl :: lines;
41537da2899SCharles.Forsyth				unlock(dbf);
41637da2899SCharles.Forsyth				return (ref Dbentry(0, lines), 1, offset);
41737da2899SCharles.Forsyth			}
41837da2899SCharles.Forsyth		}
41937da2899SCharles.Forsyth	}
42037da2899SCharles.Forsyth	unlock(dbf);
42137da2899SCharles.Forsyth	return (nil, 0, int fd.offset());
42237da2899SCharles.Forsyth}
42337da2899SCharles.Forsyth
42437da2899SCharles.Forsythnextentry(db: ref Db, ptr: ref Dbptr, attr: string, value: string, useval: int): (ref Dbentry, ref Dbptr)
42537da2899SCharles.Forsyth{
42637da2899SCharles.Forsyth	if(ptr == nil){
42737da2899SCharles.Forsyth		ptr = ref Dbptr.Direct(db.dbs, nil, 0);
42837da2899SCharles.Forsyth		# TO DO: index
42937da2899SCharles.Forsyth	}
43037da2899SCharles.Forsyth	while(ptr.dbs != nil){
43137da2899SCharles.Forsyth		offset: int;
43237da2899SCharles.Forsyth		dbf := hd ptr.dbs;
43337da2899SCharles.Forsyth		pick p := ptr {
43437da2899SCharles.Forsyth		Direct =>
43537da2899SCharles.Forsyth			offset = p.offset;
43637da2899SCharles.Forsyth		Hash =>
43737da2899SCharles.Forsyth			raise "not done yet";
43837da2899SCharles.Forsyth		}
43937da2899SCharles.Forsyth		(e, match, next) := dbf.readentry(offset, attr, value, useval);
44037da2899SCharles.Forsyth		if(match)
44137da2899SCharles.Forsyth			return (e, ref Dbptr.Direct(ptr.dbs, nil, next));
44237da2899SCharles.Forsyth		if(e == nil)
44337da2899SCharles.Forsyth			ptr = ref Dbptr.Direct(tl ptr.dbs, nil, 0);
44437da2899SCharles.Forsyth		else
44537da2899SCharles.Forsyth			ptr = ref Dbptr.Direct(ptr.dbs, nil, next);
44637da2899SCharles.Forsyth	}
44737da2899SCharles.Forsyth	return (nil, ptr);
44837da2899SCharles.Forsyth}
44937da2899SCharles.Forsyth
45037da2899SCharles.ForsythDb.find(db: self ref Db, ptr: ref Dbptr, attr: string): (ref Dbentry, ref Dbptr)
45137da2899SCharles.Forsyth{
45237da2899SCharles.Forsyth	return nextentry(db, ptr, attr, nil, 0);
45337da2899SCharles.Forsyth}
45437da2899SCharles.Forsyth
45537da2899SCharles.ForsythDb.findpair(db: self ref Db, ptr: ref Dbptr, attr: string, value: string): (ref Dbentry, ref Dbptr)
45637da2899SCharles.Forsyth{
45737da2899SCharles.Forsyth	return nextentry(db, ptr, attr, value, 1);
45837da2899SCharles.Forsyth}
45937da2899SCharles.Forsyth
46037da2899SCharles.ForsythDb.findbyattr(db: self ref Db, ptr: ref Dbptr, attr: string, value: string, rattr: string): (ref Dbentry, ref Dbptr)
46137da2899SCharles.Forsyth{
46237da2899SCharles.Forsyth	for(;;){
46337da2899SCharles.Forsyth		e: ref Dbentry;
46437da2899SCharles.Forsyth		(e, ptr) = nextentry(db, ptr, attr, value, 1);
46537da2899SCharles.Forsyth		if(e == nil || e.find(rattr) != nil)
46637da2899SCharles.Forsyth			return (e, ptr);
46737da2899SCharles.Forsyth	}
46837da2899SCharles.Forsyth}
46937da2899SCharles.Forsyth
47037da2899SCharles.Forsythrev[T](l: list of T): list of T
47137da2899SCharles.Forsyth{
47237da2899SCharles.Forsyth	rl: list of T;
47337da2899SCharles.Forsyth	for(; l != nil; l = tl l)
47437da2899SCharles.Forsyth		rl = hd l :: rl;
47537da2899SCharles.Forsyth	return rl;
47637da2899SCharles.Forsyth}
47737da2899SCharles.Forsyth
47837da2899SCharles.Forsythlock(dbf: ref Dbf)
47937da2899SCharles.Forsyth{
48037da2899SCharles.Forsyth	dbf.lockc <-= 1;
48137da2899SCharles.Forsyth}
48237da2899SCharles.Forsyth
48337da2899SCharles.Forsythunlock(dbf: ref Dbf)
48437da2899SCharles.Forsyth{
48537da2899SCharles.Forsyth	<-dbf.lockc;
48637da2899SCharles.Forsyth}
487