xref: /inferno-os/appl/grid/lib/srvbrowse.b (revision 170ff9d45744c9a94d26be32709fb3f616ba141a)
137da2899SCharles.Forsythimplement Srvbrowse;
237da2899SCharles.Forsyth
337da2899SCharles.Forsyth#
437da2899SCharles.Forsyth# Copyright © 2003 Vita Nuova Holdings Limited.  All rights reserved.
537da2899SCharles.Forsyth#
637da2899SCharles.Forsyth
737da2899SCharles.Forsyth
837da2899SCharles.Forsythinclude "sys.m";
937da2899SCharles.Forsyth	sys : Sys;
1037da2899SCharles.Forsythinclude "draw.m";
1137da2899SCharles.Forsyth	draw: Draw;
1237da2899SCharles.Forsyth	Rect: import draw;
1337da2899SCharles.Forsythinclude "tk.m";
1437da2899SCharles.Forsyth	tk: Tk;
1537da2899SCharles.Forsythinclude "tkclient.m";
1637da2899SCharles.Forsyth	tkclient: Tkclient;
1737da2899SCharles.Forsythinclude "grid/srvbrowse.m";
1837da2899SCharles.Forsythinclude "registries.m";
1937da2899SCharles.Forsyth	registries: Registries;
2037da2899SCharles.Forsyth	Registry, Attributes, Service: import registries;
2137da2899SCharles.Forsyth
2237da2899SCharles.Forsythinit()
2337da2899SCharles.Forsyth{
2437da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
2537da2899SCharles.Forsyth	if (sys == nil)
2637da2899SCharles.Forsyth		badmod(Sys->PATH);
2737da2899SCharles.Forsyth	draw = load Draw Draw->PATH;
2837da2899SCharles.Forsyth	if (draw == nil)
2937da2899SCharles.Forsyth		badmod(Draw->PATH);
3037da2899SCharles.Forsyth	tk = load Tk Tk->PATH;
3137da2899SCharles.Forsyth	if (tk == nil)
3237da2899SCharles.Forsyth		badmod(Tk->PATH);
3337da2899SCharles.Forsyth	tkclient = load Tkclient Tkclient->PATH;
3437da2899SCharles.Forsyth	if (tkclient == nil)
3537da2899SCharles.Forsyth		badmod(Tkclient->PATH);
3637da2899SCharles.Forsyth	tkclient->init();
3737da2899SCharles.Forsyth	registries = load Registries Registries->PATH;
3837da2899SCharles.Forsyth	if (registries == nil)
3937da2899SCharles.Forsyth		badmod(Registries->PATH);
4037da2899SCharles.Forsyth	registries->init();
4137da2899SCharles.Forsyth	reg = Registry.new("/mnt/registry");
4237da2899SCharles.Forsyth	if (reg == nil) {
4337da2899SCharles.Forsyth		reg = Registry.connect(nil, nil, nil);
4437da2899SCharles.Forsyth		if (reg == nil)
4537da2899SCharles.Forsyth			error("Could not find registry");
4637da2899SCharles.Forsyth	}
4737da2899SCharles.Forsyth	qids = array[511] of { * => "" };
4837da2899SCharles.Forsyth}
4937da2899SCharles.Forsyth
5037da2899SCharles.Forsythreg : ref Registry;
5137da2899SCharles.Forsythqids : array of string;
5237da2899SCharles.Forsyth
5337da2899SCharles.Forsyth# Qid stuff is a bit rubbish at the mo but waiting for registries to change:
5437da2899SCharles.Forsyth#	currently address is unique but will not be in the future so waiting
5537da2899SCharles.Forsyth#	for another id to uniquely identify a resource
5637da2899SCharles.Forsyth
5737da2899SCharles.Forsythaddqid(srvc: ref Service): int
5837da2899SCharles.Forsyth{
5937da2899SCharles.Forsyth	addr := srvc.addr;
6037da2899SCharles.Forsyth	qid := addr2qid(addr);
6137da2899SCharles.Forsyth	for (;;) {
6237da2899SCharles.Forsyth		if (qids[qid] == nil)
6337da2899SCharles.Forsyth			break;
6437da2899SCharles.Forsyth		else if (qids[qid] == addr)
6537da2899SCharles.Forsyth			return qid;
6637da2899SCharles.Forsyth		qid++;
6737da2899SCharles.Forsyth		if (qid >= len qids)
6837da2899SCharles.Forsyth			qid = 0;
6937da2899SCharles.Forsyth	}
7037da2899SCharles.Forsyth	qids[qid] = addr;
7137da2899SCharles.Forsyth#	sys->print("adding %s (%s) to %d\n",srvc.attrs.get("resource"), addr, qid);
7237da2899SCharles.Forsyth	return qid;
7337da2899SCharles.Forsyth}
7437da2899SCharles.Forsyth
7537da2899SCharles.Forsythgetqid(srvc: ref Service): string
7637da2899SCharles.Forsyth{
7737da2899SCharles.Forsyth	addr := srvc.addr;
7837da2899SCharles.Forsyth	qid := addr2qid(addr);
7937da2899SCharles.Forsyth	startqid := qid;
8037da2899SCharles.Forsyth	for (;;) {
8137da2899SCharles.Forsyth		if (qids[qid] == addr)
8237da2899SCharles.Forsyth			return string qid;
8337da2899SCharles.Forsyth		qid++;
8437da2899SCharles.Forsyth		if (qid == startqid)
8537da2899SCharles.Forsyth			break;
8637da2899SCharles.Forsyth		if (qid >= len qids)
8737da2899SCharles.Forsyth			qid = 0;
8837da2899SCharles.Forsyth	}
8937da2899SCharles.Forsyth	return nil;
9037da2899SCharles.Forsyth}
9137da2899SCharles.Forsyth
9237da2899SCharles.Forsythaddr2qid(addr: string): int
9337da2899SCharles.Forsyth{
9437da2899SCharles.Forsyth	qid := 0;
9537da2899SCharles.Forsyth	# assume addr starts 'tcp!...'
9637da2899SCharles.Forsyth	for (i := 4; i < len addr; i++) {
9737da2899SCharles.Forsyth		qid += addr[i] * 2**(i%10);
9837da2899SCharles.Forsyth		qid = qid % len qids;
9937da2899SCharles.Forsyth	}
10037da2899SCharles.Forsyth	return qid;
10137da2899SCharles.Forsyth}
10237da2899SCharles.Forsyth
10337da2899SCharles.Forsythaddservice(srvc: ref Service)
10437da2899SCharles.Forsyth{
10537da2899SCharles.Forsyth	services = srvc :: services;
10637da2899SCharles.Forsyth	addqid(srvc);
10737da2899SCharles.Forsyth}
10837da2899SCharles.Forsyth
10937da2899SCharles.Forsythfind(filter: list of list of (string, string)): list of ref Service
11037da2899SCharles.Forsyth{
11137da2899SCharles.Forsyth	lsrv : list of ref Service = nil;
11237da2899SCharles.Forsyth	if (filter == nil)
11337da2899SCharles.Forsyth		(lsrv, nil) = reg.services();
11437da2899SCharles.Forsyth	else {
11537da2899SCharles.Forsyth		for (; filter != nil; filter = tl filter) {
11637da2899SCharles.Forsyth			attr := hd filter;
117*170ff9d4SCharles Forsyth			(s, nil) := reg.find(attr);
11837da2899SCharles.Forsyth			for (; s != nil; s = tl s)
11937da2899SCharles.Forsyth				lsrv = hd s :: lsrv;
12037da2899SCharles.Forsyth		}
12137da2899SCharles.Forsyth	}
12237da2899SCharles.Forsyth	return sortservices(lsrv);
12337da2899SCharles.Forsyth}
12437da2899SCharles.Forsyth
12537da2899SCharles.Forsythrefreshservices(filter: list of list of (string, string))
12637da2899SCharles.Forsyth{
12737da2899SCharles.Forsyth	services = find(filter);
12837da2899SCharles.Forsyth}
12937da2899SCharles.Forsyth
13037da2899SCharles.Forsythservicepath2Service(path, qid: string): list of ref Service
13137da2899SCharles.Forsyth{
13237da2899SCharles.Forsyth	srvl : list of ref Service = nil;
13337da2899SCharles.Forsyth	(nil, lst) := sys->tokenize(path, "/");
13437da2899SCharles.Forsyth	pname: string;
13537da2899SCharles.Forsyth	l := len lst;
13637da2899SCharles.Forsyth	if (l < 2 || l > 3)
13737da2899SCharles.Forsyth		return nil;
13837da2899SCharles.Forsyth	presource := hd tl lst;
13937da2899SCharles.Forsyth	if (l == 3)
14037da2899SCharles.Forsyth		pname = hd tl tl lst;
14137da2899SCharles.Forsyth
14237da2899SCharles.Forsyth	for (tmpl := services; tmpl != nil; tmpl = tl tmpl) {
14337da2899SCharles.Forsyth		srvc := hd tmpl;
14437da2899SCharles.Forsyth		(resource, name) := getresname(srvc);
14537da2899SCharles.Forsyth		if (l == 2) {
14637da2899SCharles.Forsyth			if (resource == presource)
14737da2899SCharles.Forsyth				srvl = srvc :: srvl;
14837da2899SCharles.Forsyth		}
14937da2899SCharles.Forsyth		else if (l == 3) {
15037da2899SCharles.Forsyth			if (resource == presource) {
15137da2899SCharles.Forsyth				if (name == pname && qid == getqid(srvc)) {
15237da2899SCharles.Forsyth					srvl = srvc :: srvl;
15337da2899SCharles.Forsyth					break;
15437da2899SCharles.Forsyth				}
15537da2899SCharles.Forsyth			}
15637da2899SCharles.Forsyth		}
15737da2899SCharles.Forsyth	}
15837da2899SCharles.Forsyth	return srvl;
15937da2899SCharles.Forsyth}
16037da2899SCharles.Forsyth
16137da2899SCharles.Forsythservicepath2Dir(path: string, qid: int): (array of ref sys->Dir, int)
16237da2899SCharles.Forsyth{
16337da2899SCharles.Forsyth	# sys->print("srvcPath2Dir: '%s' %d\n",path, qid);
16437da2899SCharles.Forsyth	res : list of (string, string) = nil;
16537da2899SCharles.Forsyth	(nil, lst) := sys->tokenize(path, "/");
16637da2899SCharles.Forsyth	presource, pname: string;
16737da2899SCharles.Forsyth	pattrib := 0;
16837da2899SCharles.Forsyth	l := len lst;
16937da2899SCharles.Forsyth	if (l > 1)
17037da2899SCharles.Forsyth		presource = hd tl lst;
17137da2899SCharles.Forsyth	if (l > 2)
17237da2899SCharles.Forsyth		pname = hd tl tl lst;
17337da2899SCharles.Forsyth	if (l == 4 && hd tl tl tl lst == "attributes")
17437da2899SCharles.Forsyth			pattrib = 1;
17537da2899SCharles.Forsyth	for (tmpl := services; tmpl != nil; tmpl = tl tmpl) {
17637da2899SCharles.Forsyth		srvc := hd tmpl;
17737da2899SCharles.Forsyth		(resource, name) := getresname(srvc);
17837da2899SCharles.Forsyth		if (l == 1) {
17937da2899SCharles.Forsyth			if (!isin(res, resource))
18037da2899SCharles.Forsyth				res = (resource, nil) :: res;
18137da2899SCharles.Forsyth		}
18237da2899SCharles.Forsyth		else if (l == 2) {
18337da2899SCharles.Forsyth			if (resource == presource)
18437da2899SCharles.Forsyth				res = (name, string getqid(srvc)) :: res;
18537da2899SCharles.Forsyth		}
18637da2899SCharles.Forsyth		else if (l == 3) {
18737da2899SCharles.Forsyth			if (resource == presource && name == pname) {
18837da2899SCharles.Forsyth				if (qid == int getqid(srvc)) {
18937da2899SCharles.Forsyth					if (srvc.addr[0] == '@')
19037da2899SCharles.Forsyth						res = (srvc.addr[1:], string getqid(srvc)) :: res;
19137da2899SCharles.Forsyth					else {
19237da2899SCharles.Forsyth						if (srvc.attrs != nil)
19337da2899SCharles.Forsyth							res = ("attributes", string getqid(srvc)) :: res;
19437da2899SCharles.Forsyth						res = ("address:\0"+srvc.addr+"}", string getqid(srvc)) :: res;
19537da2899SCharles.Forsyth					}
19637da2899SCharles.Forsyth					break;
19737da2899SCharles.Forsyth				}
19837da2899SCharles.Forsyth			}
19937da2899SCharles.Forsyth		}
20037da2899SCharles.Forsyth		else if (l == 4) {
20137da2899SCharles.Forsyth			if (resource == presource && name == pname && pattrib) {
20237da2899SCharles.Forsyth				if (qid == int getqid(srvc)) {
20337da2899SCharles.Forsyth					for (tmpl2 := srvc.attrs.attrs; tmpl2 != nil; tmpl2 = tl tmpl2) {
20437da2899SCharles.Forsyth						(attrib, val) := hd tmpl2;
20537da2899SCharles.Forsyth						if (attrib != "name" && attrib != "resource")
20637da2899SCharles.Forsyth							res = (attrib+":\0"+val, string getqid(srvc)) :: res;
20737da2899SCharles.Forsyth					}
20837da2899SCharles.Forsyth					break;
20937da2899SCharles.Forsyth				}
21037da2899SCharles.Forsyth			}
21137da2899SCharles.Forsyth		}
21237da2899SCharles.Forsyth	}
21337da2899SCharles.Forsyth	resa := array [len res] of ref sys->Dir;
21437da2899SCharles.Forsyth	i := len resa - 1;
21537da2899SCharles.Forsyth	for (; res != nil; res = tl res) {
21637da2899SCharles.Forsyth		dir : sys->Dir;
21737da2899SCharles.Forsyth		qid: string;
21837da2899SCharles.Forsyth		(dir.name, qid) = hd res;
21937da2899SCharles.Forsyth		if (l < 3 || dir.name == "attributes")
22037da2899SCharles.Forsyth			dir.mode = 8r777 | sys->DMDIR;
22137da2899SCharles.Forsyth		else
22237da2899SCharles.Forsyth			dir.mode = 8r777;
22337da2899SCharles.Forsyth		if (qid != nil)
22437da2899SCharles.Forsyth			dir.qid.path = big qid;
22537da2899SCharles.Forsyth		resa[i--] = ref dir;
22637da2899SCharles.Forsyth	}
22737da2899SCharles.Forsyth	dups := 0;
22837da2899SCharles.Forsyth	if (l >= 2)
22937da2899SCharles.Forsyth		dups = 1;
23037da2899SCharles.Forsyth	return (resa, dups);
23137da2899SCharles.Forsyth}
23237da2899SCharles.Forsyth
23337da2899SCharles.Forsythisin(l: list of (string, string), s: string): int
23437da2899SCharles.Forsyth{
23537da2899SCharles.Forsyth	for (; l != nil; l = tl l)
23637da2899SCharles.Forsyth		if ((hd l).t0 == s)
23737da2899SCharles.Forsyth			return 1;
23837da2899SCharles.Forsyth	return 0;
23937da2899SCharles.Forsyth}
24037da2899SCharles.Forsyth
24137da2899SCharles.Forsythgetresname(srvc: ref Service): (string, string)
24237da2899SCharles.Forsyth{
24337da2899SCharles.Forsyth	resource := srvc.attrs.get("resource");
24437da2899SCharles.Forsyth	if (resource == nil)
24537da2899SCharles.Forsyth		resource = "Other";
24637da2899SCharles.Forsyth	name := srvc.attrs.get("name");
24737da2899SCharles.Forsyth	if (name == nil)
24837da2899SCharles.Forsyth		name = "?????";
24937da2899SCharles.Forsyth	return (resource,name);
25037da2899SCharles.Forsyth}
25137da2899SCharles.Forsyth
25237da2899SCharles.Forsythbadmod(path: string)
25337da2899SCharles.Forsyth{
25437da2899SCharles.Forsyth	sys->print("Srvbrowse: failed to load: %s\n",path);
25537da2899SCharles.Forsyth	exit;
25637da2899SCharles.Forsyth}
25737da2899SCharles.Forsyth
25837da2899SCharles.Forsythsortservices(lsrv: list of ref Service): list of ref Service
25937da2899SCharles.Forsyth{
26037da2899SCharles.Forsyth	a := array[len lsrv] of ref Service;
26137da2899SCharles.Forsyth	i := 0;
26237da2899SCharles.Forsyth	for (; lsrv != nil; lsrv = tl lsrv) {
26337da2899SCharles.Forsyth		addqid(hd lsrv);
26437da2899SCharles.Forsyth		a[i++] = hd lsrv;
26537da2899SCharles.Forsyth	}
26637da2899SCharles.Forsyth	heapsort(a);
26737da2899SCharles.Forsyth	lsrvsorted: list of ref Service = nil;
26837da2899SCharles.Forsyth	for (i = len a - 1; i >= 0; i--)
26937da2899SCharles.Forsyth		lsrvsorted = a[i] :: lsrvsorted;
27037da2899SCharles.Forsyth	return lsrvsorted;
27137da2899SCharles.Forsyth}
27237da2899SCharles.Forsyth
27337da2899SCharles.Forsyth
27437da2899SCharles.Forsythheapsort(a: array of ref Service)
27537da2899SCharles.Forsyth{
27637da2899SCharles.Forsyth	for (i := (len a / 2) - 1; i >= 0; i--)
27737da2899SCharles.Forsyth		movedownheap(a, i, len a - 1);
27837da2899SCharles.Forsyth
27937da2899SCharles.Forsyth	for (i = len a - 1; i > 0; i--) {
28037da2899SCharles.Forsyth		tmp := a[0];
28137da2899SCharles.Forsyth		a[0] = a[i];
28237da2899SCharles.Forsyth		a[i] = tmp;
28337da2899SCharles.Forsyth		movedownheap(a, 0, i - 1);
28437da2899SCharles.Forsyth	}
28537da2899SCharles.Forsyth}
28637da2899SCharles.Forsyth
28737da2899SCharles.Forsythmovedownheap(a: array of ref Service, root, end: int)
28837da2899SCharles.Forsyth{
28937da2899SCharles.Forsyth	max: int;
29037da2899SCharles.Forsyth	while (2*root <= end) {
29137da2899SCharles.Forsyth		r2 := root * 2;
29237da2899SCharles.Forsyth		if (2*root == end || comp(a[r2], a[r2+1]) == GT)
29337da2899SCharles.Forsyth			max = r2;
29437da2899SCharles.Forsyth		else
29537da2899SCharles.Forsyth			max = r2 + 1;
29637da2899SCharles.Forsyth
29737da2899SCharles.Forsyth		if (comp(a[root], a[max]) == LT) {
29837da2899SCharles.Forsyth			tmp := a[root];
29937da2899SCharles.Forsyth			a[root] = a[max];
30037da2899SCharles.Forsyth			a[max] = tmp;
30137da2899SCharles.Forsyth			root = max;
30237da2899SCharles.Forsyth		}
30337da2899SCharles.Forsyth		else
30437da2899SCharles.Forsyth			break;
30537da2899SCharles.Forsyth	}
30637da2899SCharles.Forsyth}
30737da2899SCharles.Forsyth
30837da2899SCharles.ForsythLT: con -1;
30937da2899SCharles.ForsythEQ: con 0;
31037da2899SCharles.ForsythGT: con 1;
31137da2899SCharles.Forsyth
31237da2899SCharles.Forsythcomp(a1, a2: ref Service): int
31337da2899SCharles.Forsyth{
31437da2899SCharles.Forsyth	(resource1, name1) := getresname(a1);
31537da2899SCharles.Forsyth	(resource2, name2) := getresname(a2);
31637da2899SCharles.Forsyth	if (resource1 < resource2)
31737da2899SCharles.Forsyth		return LT;
31837da2899SCharles.Forsyth	if (resource1 > resource2)
31937da2899SCharles.Forsyth		return GT;
32037da2899SCharles.Forsyth	if (name1 < name2)
32137da2899SCharles.Forsyth		return LT;
32237da2899SCharles.Forsyth	if (name1 > name2)
32337da2899SCharles.Forsyth		return GT;
32437da2899SCharles.Forsyth	return EQ;
32537da2899SCharles.Forsyth}
32637da2899SCharles.Forsyth
32737da2899SCharles.Forsytherror(e: string)
32837da2899SCharles.Forsyth{
32937da2899SCharles.Forsyth	sys->fprint(sys->fildes(2), "Srvbrowse: %s\n", e);
33037da2899SCharles.Forsyth	raise "fail:error";
33137da2899SCharles.Forsyth}
33237da2899SCharles.Forsyth
33337da2899SCharles.Forsythsearchscr := array[] of {
33437da2899SCharles.Forsyth	"frame .f",
33537da2899SCharles.Forsyth	"scrollbar .f.sy -command {.f.c yview}",
33637da2899SCharles.Forsyth	"scrollbar .f.sx -command {.f.c xview} -orient horizontal",
33737da2899SCharles.Forsyth	"canvas .f.c -yscrollcommand {.f.sy set} -xscrollcommand {.f.sx set} -bg white -width 414 -borderwidth 2 -relief sunken -height 180 -xscrollincrement 10 -yscrollincrement 19",
33837da2899SCharles.Forsyth	"grid .f.sy -row 0 -column 0 -sticky ns -rowspan 2",
33937da2899SCharles.Forsyth	"grid .f.sx -row 1 -column 1 -sticky ew",
34037da2899SCharles.Forsyth	"grid .f.c -row 0 -column 1",
34137da2899SCharles.Forsyth	"pack .f -fill both -expand 1 ; pack propagate . 0; update",
34237da2899SCharles.Forsyth};
34337da2899SCharles.Forsyth
34437da2899SCharles.ForsythSEARCH, RESULTS: con iota;
34537da2899SCharles.Forsyth
34637da2899SCharles.Forsythsearchwin(ctxt: ref Draw->Context, chanout: chan of string, filter: list of list of (string, string))
34737da2899SCharles.Forsyth{
34837da2899SCharles.Forsyth	(top, titlebar) := tkclient->toplevel(ctxt,"","Search", tkclient->Appl);
34937da2899SCharles.Forsyth	butchan := chan of string;
35037da2899SCharles.Forsyth	tk->namechan(top, butchan, "butchan");
35137da2899SCharles.Forsyth	tkcmds(top, searchscr);
35237da2899SCharles.Forsyth	makesearchframe(top);
35337da2899SCharles.Forsyth	flid := setframe(top, ".fsearch", nil);
35437da2899SCharles.Forsyth	selected := "";
35537da2899SCharles.Forsyth	lresults : list of ref Service = nil;
35637da2899SCharles.Forsyth	resultstart := 0;
35737da2899SCharles.Forsyth	resize(top, 368,220);
35837da2899SCharles.Forsyth	maxresults := getmaxresults(top);
35937da2899SCharles.Forsyth	currmode := SEARCH;
36037da2899SCharles.Forsyth	tkclient->onscreen(top, nil);
36137da2899SCharles.Forsyth	tkclient->startinput(top, "kbd"::"ptr"::nil);
36237da2899SCharles.Forsyth
36337da2899SCharles.Forsyth	main: for (;;) {
36437da2899SCharles.Forsyth		alt {
36537da2899SCharles.Forsyth		s := <-top.ctxt.kbd =>
36637da2899SCharles.Forsyth			tk->keyboard(top, s);
36737da2899SCharles.Forsyth		s := <-top.ctxt.ptr =>
36837da2899SCharles.Forsyth			tk->pointer(top, *s);
36937da2899SCharles.Forsyth		inp := <-butchan =>
37037da2899SCharles.Forsyth			(nil, lst) := sys->tokenize(inp, " ");
37137da2899SCharles.Forsyth			case hd lst {
37237da2899SCharles.Forsyth				"key" =>
37337da2899SCharles.Forsyth					s := " ";
37437da2899SCharles.Forsyth					id := hd tl lst;
37537da2899SCharles.Forsyth					nv := hd tl tl lst;
37637da2899SCharles.Forsyth					tkp : string;
37737da2899SCharles.Forsyth					if (id != "-1")
37837da2899SCharles.Forsyth						tkp = ".fsearch.ea"+nv+id;
37937da2899SCharles.Forsyth					else
38037da2899SCharles.Forsyth						tkp = ".fsearch.e"+nv;
38137da2899SCharles.Forsyth					char := int hd tl tl tl lst;
38237da2899SCharles.Forsyth					s[0] = char;
38337da2899SCharles.Forsyth					if (char == '\n' || char == '\t') {
38437da2899SCharles.Forsyth						newtkp := ".fsearch";
38537da2899SCharles.Forsyth						if (nv == "n")
38637da2899SCharles.Forsyth							newtkp += ".eav"+id;
38737da2899SCharles.Forsyth						else if (nv == "v") {
38837da2899SCharles.Forsyth							newid := string ((int id)+1);
38937da2899SCharles.Forsyth							e := tk->cmd(top, ".fsearch.ean"+newid+" cget -width");
39037da2899SCharles.Forsyth							if (e == "" || e[0] == '!') {
39137da2899SCharles.Forsyth								insertattribrow(top);
39237da2899SCharles.Forsyth								newtkp += ".ean"+newid;
39337da2899SCharles.Forsyth							}
39437da2899SCharles.Forsyth							else
39537da2899SCharles.Forsyth								newtkp += ".ean"+newid;
39637da2899SCharles.Forsyth						}
39737da2899SCharles.Forsyth						focus(top, newtkp);
39837da2899SCharles.Forsyth					}
39937da2899SCharles.Forsyth					else {
40037da2899SCharles.Forsyth						tkcmd(top, tkp+" insert insert {"+s+"}");
40137da2899SCharles.Forsyth						tkcmd(top, tkp+" see "+tkcmd(top, tkp+" index insert"));
40237da2899SCharles.Forsyth					}
40337da2899SCharles.Forsyth				"go" =>
40437da2899SCharles.Forsyth					lresults = search(top, filter);
40537da2899SCharles.Forsyth					resultstart = 0;
40637da2899SCharles.Forsyth					makeresultsframe(top, lresults, 0, maxresults);
40737da2899SCharles.Forsyth					selected = nil;
40837da2899SCharles.Forsyth					flid = setframe(top, ".fresults", flid);
40937da2899SCharles.Forsyth					currmode = RESULTS;
41037da2899SCharles.Forsyth					if (chanout != nil)
41137da2899SCharles.Forsyth						chanout <-= "search search";
41237da2899SCharles.Forsyth				"prev" =>
41337da2899SCharles.Forsyth					selected = nil;
41437da2899SCharles.Forsyth					resultstart -= maxresults;
41537da2899SCharles.Forsyth					if (resultstart < 0)
41637da2899SCharles.Forsyth						resultstart = 0;
41737da2899SCharles.Forsyth					makeresultsframe(top, lresults, resultstart, maxresults);
41837da2899SCharles.Forsyth					flid = setframe(top, ".fresults", flid);
41937da2899SCharles.Forsyth				"next" =>
42037da2899SCharles.Forsyth					selected = nil;
42137da2899SCharles.Forsyth					if (resultstart < 0)
42237da2899SCharles.Forsyth						resultstart = 0;
42337da2899SCharles.Forsyth					resultstart += maxresults;
42437da2899SCharles.Forsyth					if (resultstart >= len lresults)
42537da2899SCharles.Forsyth						resultstart -= maxresults;
42637da2899SCharles.Forsyth					makeresultsframe(top, lresults, resultstart, maxresults);
42737da2899SCharles.Forsyth					flid = setframe(top, ".fresults", flid);
42837da2899SCharles.Forsyth				"backto" =>
42937da2899SCharles.Forsyth					flid = setframe(top, ".fsearch", flid);
43037da2899SCharles.Forsyth					tkcmd(top, ".f.c see 0 "+tkcmd(top, ".fsearch cget -height"));
43137da2899SCharles.Forsyth					currmode = SEARCH;
43237da2899SCharles.Forsyth				"new" =>
43337da2899SCharles.Forsyth					resetsearchscr(top);
43437da2899SCharles.Forsyth					tkcmd(top, ".f.c see 0 0");
43537da2899SCharles.Forsyth					setscrollr(top, ".fsearch");
43637da2899SCharles.Forsyth				"select" =>
43737da2899SCharles.Forsyth					if (selected != nil)
43837da2899SCharles.Forsyth						tkcmd(top, selected+" configure -bg white");
43937da2899SCharles.Forsyth					if (selected == hd tl lst)
44037da2899SCharles.Forsyth						selected = nil;
44137da2899SCharles.Forsyth					else {
44237da2899SCharles.Forsyth						selected = hd tl lst;
44337da2899SCharles.Forsyth						tkcmd(top, hd tl lst+" configure -bg #5555FF");
44437da2899SCharles.Forsyth						if (chanout != nil)
44537da2899SCharles.Forsyth							chanout <-= "search select " +
44637da2899SCharles.Forsyth										tkcmd(top, selected+" cget -text") +													" " + hd tl tl lst;
44737da2899SCharles.Forsyth					}
44837da2899SCharles.Forsyth			}
44937da2899SCharles.Forsyth			tkcmd(top, "update");
45037da2899SCharles.Forsyth		title := <-top.ctxt.ctl or
45137da2899SCharles.Forsyth		title = <-top.wreq or
45237da2899SCharles.Forsyth		title = <-titlebar =>
45337da2899SCharles.Forsyth			if (title == "exit" || title == "ok")
45437da2899SCharles.Forsyth				break main;
45537da2899SCharles.Forsyth			e := tkclient->wmctl(top, title);
45637da2899SCharles.Forsyth			if (e == nil && title[0] == '!') {
45737da2899SCharles.Forsyth				(nil, lst) := sys->tokenize(title, " \t\n");
45837da2899SCharles.Forsyth				if (len lst >= 2 && hd lst == "!size" && hd tl lst == ".") {
45937da2899SCharles.Forsyth					resize(top, -1,-1);
46037da2899SCharles.Forsyth					maxresults = getmaxresults(top);
46137da2899SCharles.Forsyth					if (currmode == RESULTS) {
46237da2899SCharles.Forsyth						makeresultsframe(top, lresults, resultstart, maxresults);
46337da2899SCharles.Forsyth						flid = setframe(top, ".fresults", flid);
46437da2899SCharles.Forsyth						tkcmd(top, "update");
46537da2899SCharles.Forsyth					}
46637da2899SCharles.Forsyth				}
46737da2899SCharles.Forsyth			}
46837da2899SCharles.Forsyth		}
46937da2899SCharles.Forsyth	}
47037da2899SCharles.Forsyth
47137da2899SCharles.Forsyth}
47237da2899SCharles.Forsyth
47337da2899SCharles.Forsythgetmaxresults(top: ref Tk->Toplevel): int
47437da2899SCharles.Forsyth{
47537da2899SCharles.Forsyth	val := ((int tkcmd(top, ".f.c cget -height")) - 65)/17;
47637da2899SCharles.Forsyth	if (val < 1)
47737da2899SCharles.Forsyth		return 1;
47837da2899SCharles.Forsyth	return val;
47937da2899SCharles.Forsyth}
48037da2899SCharles.Forsyth
48137da2899SCharles.Forsythsetframe(top: ref Tk->Toplevel, f, oldflid: string): string
48237da2899SCharles.Forsyth{
48337da2899SCharles.Forsyth	if (oldflid != nil)
48437da2899SCharles.Forsyth		tkcmd(top, ".f.c delete " + oldflid);
48537da2899SCharles.Forsyth	newflid := tkcmd(top, ".f.c create window 0 0 -window "+f+" -anchor nw");
48637da2899SCharles.Forsyth	setscrollr(top, f);
48737da2899SCharles.Forsyth	return newflid;
48837da2899SCharles.Forsyth}
48937da2899SCharles.Forsyth
49037da2899SCharles.Forsythsetscrollr(top: ref Tk->Toplevel, f: string)
49137da2899SCharles.Forsyth{
49237da2899SCharles.Forsyth	h := tkcmd(top, f+" cget -height");
49337da2899SCharles.Forsyth	w := tkcmd(top, f+" cget -width");
49437da2899SCharles.Forsyth	tkcmd(top, ".f.c configure -scrollregion {0 0 "+w+" "+h+"}");
49537da2899SCharles.Forsyth}
49637da2899SCharles.Forsyth
49737da2899SCharles.Forsythresize(top: ref Tk->Toplevel, width, height: int)
49837da2899SCharles.Forsyth{
49937da2899SCharles.Forsyth	if (width == -1) {
50037da2899SCharles.Forsyth		width = int tkcmd(top, ". cget -width");
50137da2899SCharles.Forsyth		height = int tkcmd(top, ". cget -height");
50237da2899SCharles.Forsyth	}
50337da2899SCharles.Forsyth	else
50437da2899SCharles.Forsyth		tkcmd(top, sys->sprint(". configure -width %d -height %d", width, height));
50537da2899SCharles.Forsyth	htitle := int tkcmd(top, ".f cget -acty") - int tkcmd(top, ". cget -acty");
50637da2899SCharles.Forsyth	height -= htitle;
50737da2899SCharles.Forsyth	ws := int tkcmd(top, ".f.sy cget -width");
50837da2899SCharles.Forsyth	hs := int tkcmd(top, ".f.sx cget -height");
50937da2899SCharles.Forsyth
51037da2899SCharles.Forsyth	tkcmd(top, ".f.c configure -width "+string (width - ws - 8)+
51137da2899SCharles.Forsyth			" -height "+string (height - hs - 8));
51237da2899SCharles.Forsyth
51337da2899SCharles.Forsyth	tkcmd(top, "update");
51437da2899SCharles.Forsyth}
51537da2899SCharles.Forsyth
51637da2899SCharles.Forsythmakesearchframe(top: ref Tk->Toplevel)
51737da2899SCharles.Forsyth{
51837da2899SCharles.Forsyth	font := " -font /fonts/charon/plain.normal.font";
51937da2899SCharles.Forsyth	fontb := " -font /fonts/charon/bold.normal.font";
52037da2899SCharles.Forsyth	f := ".fsearch";
52137da2899SCharles.Forsyth
52237da2899SCharles.Forsyth	tkcmd(top, "frame "+f+" -bg white");
52337da2899SCharles.Forsyth	tkcmd(top, "label "+f+".l -text {Search for Resource Attributes} -bg white" + fontb);
52437da2899SCharles.Forsyth	tkcmd(top, "grid "+f+".l -row 0 -column 0 -columnspan 3 -sticky nw");
52537da2899SCharles.Forsyth
52637da2899SCharles.Forsyth	tkcmd(top, "grid rowconfigure "+f+" 0 -minsize 30");
52737da2899SCharles.Forsyth	tkcmd(top, "frame "+f+".fgo -bg white");
52837da2899SCharles.Forsyth	tkcmd(top, "button "+f+".bs -text {Search} -command {send butchan go} "+font);
52937da2899SCharles.Forsyth	tkcmd(top, "button "+f+".bc -text {Clear} -command {send butchan new} "+font);
53037da2899SCharles.Forsyth	tkcmd(top, "grid "+f+".bs -row 3 -column 0 -sticky e -padx 2 -pady 5");
53137da2899SCharles.Forsyth	tkcmd(top, "grid "+f+".bc -row 3 -column 1 -sticky w -pady 5");
53237da2899SCharles.Forsyth
53337da2899SCharles.Forsyth	tkcmd(top, "label "+f+".la1 -text {name} -bg white "+fontb);
53437da2899SCharles.Forsyth	tkcmd(top, "label "+f+".la2 -text {value} -bg white "+fontb);
53537da2899SCharles.Forsyth
53637da2899SCharles.Forsyth	tkcmd(top, "grid "+f+".la1 "+f+".la2 -row 1");
53737da2899SCharles.Forsyth
53837da2899SCharles.Forsyth	insertattribrow(top);
53937da2899SCharles.Forsyth}
54037da2899SCharles.Forsyth
54137da2899SCharles.Forsythinsertattribrow(top: ref Tk->Toplevel)
54237da2899SCharles.Forsyth{
54337da2899SCharles.Forsyth	(n, nil) := sys->tokenize(tkcmd(top, "grid slaves .fsearch -column 1"), " \t\n");
54437da2899SCharles.Forsyth	row := string (n);
54537da2899SCharles.Forsyth	sn := string (n - 2);
54637da2899SCharles.Forsyth	fsn := ".fsearch.ean"+sn;
54737da2899SCharles.Forsyth	fsv := ".fsearch.eav"+sn;
54837da2899SCharles.Forsyth	font := " -font /fonts/charon/plain.normal.font";
54937da2899SCharles.Forsyth	tkcmd(top, "entry "+fsn+" -width 170 -borderwidth 0 "+font);
55037da2899SCharles.Forsyth	tkcmd(top, "bind "+fsn+" <Key> {send butchan key "+sn+" n %s}");
55137da2899SCharles.Forsyth	tkcmd(top, "entry "+fsv+" -width 170 -borderwidth 0 "+font);
55237da2899SCharles.Forsyth	tkcmd(top, "bind "+fsv+" <Key> {send butchan key "+sn+" v %s}");
55337da2899SCharles.Forsyth	tkcmd(top, "grid rowinsert .fsearch "+row);
55437da2899SCharles.Forsyth	tkcmd(top, "grid "+fsn+" -column 0 -row "+row+" -sticky w -pady 1 -padx 2");
55537da2899SCharles.Forsyth	tkcmd(top, "grid "+fsv+" -column 1 -row "+row+" -sticky w -pady 1");
55637da2899SCharles.Forsyth	setscrollr(top, ".fsearch");
55737da2899SCharles.Forsyth}
55837da2899SCharles.Forsyth
55937da2899SCharles.Forsythmin(a,b: int): int
56037da2899SCharles.Forsyth{
56137da2899SCharles.Forsyth	if (a < b)
56237da2899SCharles.Forsyth		return a;
56337da2899SCharles.Forsyth	return b;
56437da2899SCharles.Forsyth}
56537da2899SCharles.Forsyth
56637da2899SCharles.Forsythmax(a,b: int): int
56737da2899SCharles.Forsyth{
56837da2899SCharles.Forsyth	if (a > b)
56937da2899SCharles.Forsyth		return a;
57037da2899SCharles.Forsyth	return b;
57137da2899SCharles.Forsyth}
57237da2899SCharles.Forsyth
57337da2899SCharles.Forsythmakeresultsframe(top: ref Tk->Toplevel, lsrv: list of ref Service, resultstart, maxresults: int)
57437da2899SCharles.Forsyth{
57537da2899SCharles.Forsyth	font := " -font /fonts/charon/plain.normal.font";
57637da2899SCharles.Forsyth	fontb := " -font /fonts/charon/bold.normal.font";
57737da2899SCharles.Forsyth	f := ".fresults";
57837da2899SCharles.Forsyth	nresults := len lsrv;
57937da2899SCharles.Forsyth	row := 0;
58037da2899SCharles.Forsyth	n := 0;
58137da2899SCharles.Forsyth	tk->cmd(top, "destroy "+f);
58237da2899SCharles.Forsyth	tkcmd(top, "frame "+f+" -bg white");
58337da2899SCharles.Forsyth	title := "Search Results";
58437da2899SCharles.Forsyth	if (nresults > 0) {
58537da2899SCharles.Forsyth		from := resultstart+1;
58637da2899SCharles.Forsyth		too := min(resultstart+maxresults, nresults);
58737da2899SCharles.Forsyth		if (from == too)
58837da2899SCharles.Forsyth			title += sys->sprint(" (displaying match %d of %d)", from, nresults);
58937da2899SCharles.Forsyth		else
59037da2899SCharles.Forsyth			title += sys->sprint(" (displaying matches %d - %d of %d)", from, too, nresults);
59137da2899SCharles.Forsyth	}
59237da2899SCharles.Forsyth	tkcmd(top, "label "+f+".l -text {"+title+"} -bg white -anchor w" + fontb);
59337da2899SCharles.Forsyth	w1 := int tkcmd(top, f+".l cget -width");
59437da2899SCharles.Forsyth	w2 := int tkcmd(top, ".f.c cget -width");
59537da2899SCharles.Forsyth	tkcmd(top, f+".l configure -width "+string max(w1,w2));
59637da2899SCharles.Forsyth	tkcmd(top, "grid "+f+".l -row 0 -column 0 -columnspan 3 -sticky nw");
59737da2899SCharles.Forsyth
59837da2899SCharles.Forsyth	tkcmd(top, "grid rowconfigure "+f+" 0 -minsize 30");
59937da2899SCharles.Forsyth	tkcmd(top, "frame "+f+".f -bg white");
60037da2899SCharles.Forsyth	for (; lsrv != nil; lsrv = tl lsrv) {
60137da2899SCharles.Forsyth		if (n >= resultstart && n < resultstart + maxresults) {
60237da2899SCharles.Forsyth			srvc := hd lsrv;
60337da2899SCharles.Forsyth			(resource, name) := getresname(srvc);
60437da2899SCharles.Forsyth			qid := getqid(srvc);
60537da2899SCharles.Forsyth			if (qid == nil)
60637da2899SCharles.Forsyth				qid = string addqid(srvc);
60737da2899SCharles.Forsyth			label := f+".f.lQ"+qid;
60837da2899SCharles.Forsyth			tkcmd(top, "label "+label+" -bg white -text {services/"+
60937da2899SCharles.Forsyth				resource+"/"+name+"/}"+font);
61037da2899SCharles.Forsyth			tkcmd(top, "grid "+label+" -row "+string row+" -column 0 -sticky w");
61137da2899SCharles.Forsyth			tkcmd(top, "bind "+label+" <Button-1> {send butchan select "+label+" "+qid+"}");
61237da2899SCharles.Forsyth			row++;
61337da2899SCharles.Forsyth		}
61437da2899SCharles.Forsyth		n++;
61537da2899SCharles.Forsyth	}
61637da2899SCharles.Forsyth	if (nresults == 0) {
61737da2899SCharles.Forsyth		tkcmd(top, "label "+f+".f.l0 -bg white -text {No matches found}"+font);
61837da2899SCharles.Forsyth		tkcmd(top, "grid "+f+".f.l0 -row 0 -column 0 -columnspan 3 -sticky w");
61937da2899SCharles.Forsyth	}
62037da2899SCharles.Forsyth	else {
62137da2899SCharles.Forsyth		tkcmd(top, "button "+f+".bprev -text {<<} "+
62237da2899SCharles.Forsyth				"-command {send butchan prev}"+font);
62337da2899SCharles.Forsyth		if (resultstart == 0)
62437da2899SCharles.Forsyth			tkcmd(top, f+".bprev configure -state disabled");
62537da2899SCharles.Forsyth		tkcmd(top, "button "+f+".bnext -text {>>} "+
62637da2899SCharles.Forsyth				"-command {send butchan next}"+font);
62737da2899SCharles.Forsyth		if (resultstart + maxresults >= nresults)
62837da2899SCharles.Forsyth			tkcmd(top, f+".bnext configure -state disabled");
62937da2899SCharles.Forsyth		tkcmd(top, "grid "+f+".bprev -column 0 -row 2 -padx 5 -pady 5");
63037da2899SCharles.Forsyth		tkcmd(top, "grid "+f+".bnext -column 2 -row 2 -padx 5 -pady 5");
63137da2899SCharles.Forsyth	}
63237da2899SCharles.Forsyth	tkcmd(top, "grid "+f+".f -row 1 -column 0 -columnspan 3 -sticky nw");
63337da2899SCharles.Forsyth	tkcmd(top, "grid rowconfigure "+f+" 1 -minsize "+string (maxresults*17));
63437da2899SCharles.Forsyth	tkcmd(top, "button "+f+".bsearch -text {Back to Search} "+
63537da2899SCharles.Forsyth			"-command {send butchan backto}"+font);
63637da2899SCharles.Forsyth	tkcmd(top, "grid "+f+".bsearch -column 1 -row 2 -padx 5 -pady 5");
63737da2899SCharles.Forsyth}
63837da2899SCharles.Forsyth
63937da2899SCharles.Forsythfocus(top: ref Tk->Toplevel, newtkp: string)
64037da2899SCharles.Forsyth{
64137da2899SCharles.Forsyth	tkcmd(top, "focus "+newtkp);
64237da2899SCharles.Forsyth	x1 := int tkcmd(top, newtkp + " cget -actx")
64337da2899SCharles.Forsyth			- int tkcmd(top, ".fsearch cget -actx");
64437da2899SCharles.Forsyth	y1 := int tkcmd(top, newtkp + " cget -acty")
64537da2899SCharles.Forsyth			- int tkcmd(top, ".fsearch cget -acty");
64637da2899SCharles.Forsyth	x2 := x1 + int tkcmd(top, newtkp + " cget -width");
64737da2899SCharles.Forsyth	y2 := y1 + int tkcmd(top, newtkp + " cget -height") + 45;
64837da2899SCharles.Forsyth	tkcmd(top, sys->sprint(".f.c see %d %d %d %d", x1,y1-30,x2,y2));
64937da2899SCharles.Forsyth}
65037da2899SCharles.Forsyth
65137da2899SCharles.Forsythsearch(top: ref Tk->Toplevel, filter: list of list of (string, string)): list of ref Service
65237da2899SCharles.Forsyth{
65337da2899SCharles.Forsyth	searchattrib: list of (string, string) = nil;
65437da2899SCharles.Forsyth	(n, nil) := sys->tokenize(tkcmd(top, "grid slaves .fsearch -column 0"), " \t\n");
65537da2899SCharles.Forsyth	for (i := 0; i < n - 3; i++) {
65637da2899SCharles.Forsyth		attrib := tkcmd(top, ".fsearch.ean"+string i+" get");
65737da2899SCharles.Forsyth		val := tkcmd(top, ".fsearch.eav"+string i+" get");
65837da2899SCharles.Forsyth		if (val == nil)
65937da2899SCharles.Forsyth			val = "*";
66037da2899SCharles.Forsyth		if (attrib != nil)
66137da2899SCharles.Forsyth			searchattrib = (attrib, val) :: searchattrib;
66237da2899SCharles.Forsyth	}
66337da2899SCharles.Forsyth	tmp : list of list of (string, string) = nil;
66437da2899SCharles.Forsyth	for (; filter != nil; filter = tl filter) {
66537da2899SCharles.Forsyth		l := hd filter;
66637da2899SCharles.Forsyth		for (tmp2 := searchattrib; tmp2 != nil; tmp2 = tl tmp2)
66737da2899SCharles.Forsyth			l = hd tmp2 :: l;
66837da2899SCharles.Forsyth		tmp = l :: tmp;
66937da2899SCharles.Forsyth	}
67037da2899SCharles.Forsyth	filter = tmp;
67137da2899SCharles.Forsyth	if (filter == nil)
67237da2899SCharles.Forsyth		filter = searchattrib :: nil;
67337da2899SCharles.Forsyth	return find(filter);
67437da2899SCharles.Forsyth}
67537da2899SCharles.Forsyth
67637da2899SCharles.Forsythgetitem(l : list of (string, ref Service), testid: string): ref Service
67737da2899SCharles.Forsyth{
67837da2899SCharles.Forsyth	for (; l != nil; l = tl l) {
67937da2899SCharles.Forsyth		(id, srvc) := hd l;
68037da2899SCharles.Forsyth		if (testid == id)
68137da2899SCharles.Forsyth			return srvc;
68237da2899SCharles.Forsyth	}
68337da2899SCharles.Forsyth	return nil;
68437da2899SCharles.Forsyth}
68537da2899SCharles.Forsyth
68637da2899SCharles.Forsythdelitem(l : list of (string, ref Service), testid: string): list of (string, ref Service)
68737da2899SCharles.Forsyth{
68837da2899SCharles.Forsyth	l2 : list of (string, ref Service) = nil;
68937da2899SCharles.Forsyth	for (; l != nil; l = tl l) {
69037da2899SCharles.Forsyth		(id, srvc) := hd l;
69137da2899SCharles.Forsyth		if (testid != id)
69237da2899SCharles.Forsyth			l2 = (id, srvc) :: l2;
69337da2899SCharles.Forsyth	}
69437da2899SCharles.Forsyth	return l2;
69537da2899SCharles.Forsyth}
69637da2899SCharles.Forsyth
69737da2899SCharles.Forsythresetsearchscr(top: ref Tk->Toplevel)
69837da2899SCharles.Forsyth{
69937da2899SCharles.Forsyth	(n, nil) := sys->tokenize(tkcmd(top, "grid slaves .fsearch -column 1"), " \t\n");
70037da2899SCharles.Forsyth	for (i := 1; i < n - 2; i++)
70137da2899SCharles.Forsyth		tkcmd(top, "destroy .fsearch.ean"+string i+" .fsearch.eav"+string i);
70237da2899SCharles.Forsyth	s := " delete 0 end";
70337da2899SCharles.Forsyth	tkcmd(top, ".fsearch.ean0"+s);
70437da2899SCharles.Forsyth	tkcmd(top, ".fsearch.eav0"+s);
70537da2899SCharles.Forsyth}
70637da2899SCharles.Forsyth
70737da2899SCharles.Forsythtkcmd(top: ref Tk->Toplevel, cmd: string): string
70837da2899SCharles.Forsyth{
70937da2899SCharles.Forsyth	e := tk->cmd(top, cmd);
71037da2899SCharles.Forsyth	if (e != "" && e[0] == '!')
71137da2899SCharles.Forsyth		sys->print("Tk error: '%s': %s\n",cmd,e);
71237da2899SCharles.Forsyth	return e;
71337da2899SCharles.Forsyth}
71437da2899SCharles.Forsyth
71537da2899SCharles.Forsythtkcmds(top: ref Tk->Toplevel, a: array of string)
71637da2899SCharles.Forsyth{
71737da2899SCharles.Forsyth	for (j := 0; j < len a; j++)
71837da2899SCharles.Forsyth		tkcmd(top, a[j]);
71937da2899SCharles.Forsyth}
720