xref: /inferno-os/appl/grid/lib/fbrowse.b (revision 170ff9d45744c9a94d26be32709fb3f616ba141a)
137da2899SCharles.Forsythimplement FBrowse;
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 "readdir.m";
1837da2899SCharles.Forsyth	readdir: Readdir;
1937da2899SCharles.Forsythinclude "workdir.m";
2037da2899SCharles.Forsythinclude "sh.m";
2137da2899SCharles.Forsyth	sh: Sh;
2237da2899SCharles.Forsythinclude "grid/pathreader.m";
2337da2899SCharles.Forsyth	reader: PathReader;
2437da2899SCharles.Forsythinclude "grid/browser.m";
2537da2899SCharles.Forsyth	browser: Browser;
2637da2899SCharles.Forsyth	Browse, Select, File, Parameter,
2737da2899SCharles.Forsyth	DESELECT, SELECT, TOGGLE: import browser;
2837da2899SCharles.Forsythinclude "grid/fbrowse.m";
2937da2899SCharles.Forsyth
3037da2899SCharles.Forsythbr: ref Browse;
3137da2899SCharles.Forsyth
3237da2899SCharles.Forsythinit(ctxt : ref Draw->Context, title, root, currdir: string): string
3337da2899SCharles.Forsyth{
3437da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
3537da2899SCharles.Forsyth	if (sys == nil)
3637da2899SCharles.Forsyth		badmod(Sys->PATH);
3737da2899SCharles.Forsyth	draw = load Draw Draw->PATH;
3837da2899SCharles.Forsyth	if (draw == nil)
3937da2899SCharles.Forsyth		badmod(Draw->PATH);
4037da2899SCharles.Forsyth	readdir = load Readdir Readdir->PATH;
4137da2899SCharles.Forsyth	if (readdir == nil)
4237da2899SCharles.Forsyth		badmod(Readdir->PATH);
4337da2899SCharles.Forsyth	tk = load Tk Tk->PATH;
4437da2899SCharles.Forsyth	if (tk == nil)
4537da2899SCharles.Forsyth		badmod(Tk->PATH);
4637da2899SCharles.Forsyth	tkclient = load Tkclient Tkclient->PATH;
4737da2899SCharles.Forsyth	if (tkclient == nil)
4837da2899SCharles.Forsyth		badmod(Tkclient->PATH);
4937da2899SCharles.Forsyth	tkclient->init();
5037da2899SCharles.Forsyth	workdir := load Workdir Workdir->PATH;
5137da2899SCharles.Forsyth	if (workdir == nil)
5237da2899SCharles.Forsyth		badmod(Workdir->PATH);
5337da2899SCharles.Forsyth	sh = load Sh Sh->PATH;
5437da2899SCharles.Forsyth	if (sh == nil)
5537da2899SCharles.Forsyth		badmod(Sh->PATH);
5637da2899SCharles.Forsyth	browser = load Browser Browser->PATH;
5737da2899SCharles.Forsyth	if (browser == nil)
5837da2899SCharles.Forsyth		badmod(Browser->PATH);
5937da2899SCharles.Forsyth	browser->init();
6037da2899SCharles.Forsyth	reader = load PathReader "$self";
6137da2899SCharles.Forsyth	if (reader == nil)
6237da2899SCharles.Forsyth		sys->print("cannot load reader!\n");
6337da2899SCharles.Forsyth	sys->pctl(sys->NEWPGRP, nil);
6437da2899SCharles.Forsyth	if (root == nil)
6537da2899SCharles.Forsyth		root = "/";
6637da2899SCharles.Forsyth	sys->chdir(root);
6737da2899SCharles.Forsyth	if (currdir == nil)
6837da2899SCharles.Forsyth		currdir = workdir->init();
6937da2899SCharles.Forsyth	if (root[len root - 1] != '/')
7037da2899SCharles.Forsyth		root[len root] = '/';
7137da2899SCharles.Forsyth	if (currdir[len currdir - 1] != '/')
7237da2899SCharles.Forsyth		currdir[len currdir] = '/';
7337da2899SCharles.Forsyth
7437da2899SCharles.Forsyth	(top, titlebar) := tkclient->toplevel(ctxt,"", title , tkclient->OK | tkclient->Appl);
7537da2899SCharles.Forsyth	browsechan := chan of string;
7637da2899SCharles.Forsyth	tk->namechan(top, browsechan, "browsechan");
7737da2899SCharles.Forsyth	br = Browse.new(top, "browsechan", root, root, 2, reader);
7837da2899SCharles.Forsyth	br.addopened(File (root, nil), 1);
7937da2899SCharles.Forsyth	br.gotoselectfile(File (currdir, nil));
8037da2899SCharles.Forsyth	for (ik := 0; ik < len mainscreen; ik++)
8137da2899SCharles.Forsyth		tkcmd(top,mainscreen[ik]);
8237da2899SCharles.Forsyth	butchan := chan of string;
8337da2899SCharles.Forsyth	tk->namechan(top, butchan, "butchan");
8437da2899SCharles.Forsyth
8537da2899SCharles.Forsyth	tkcmd(top, "pack .f -fill both -expand 1; pack propagate . 0");
8637da2899SCharles.Forsyth	tkcmd(top, ". configure -height 300 -width 300");
8737da2899SCharles.Forsyth
8837da2899SCharles.Forsyth	tkcmd(top, "update");
8937da2899SCharles.Forsyth	released := 1;
9037da2899SCharles.Forsyth	title = "";
9137da2899SCharles.Forsyth
9237da2899SCharles.Forsyth	tkclient->onscreen(top, nil);
9337da2899SCharles.Forsyth	resize(top, ctxt.display.image);
9437da2899SCharles.Forsyth	tkclient->startinput(top, "kbd"::"ptr"::nil);
9537da2899SCharles.Forsyth
9637da2899SCharles.Forsyth	path: string;
9737da2899SCharles.Forsyth
9837da2899SCharles.Forsyth	main: for (;;) {
9937da2899SCharles.Forsyth		alt {
10037da2899SCharles.Forsyth		s := <-top.ctxt.kbd =>
10137da2899SCharles.Forsyth			tk->keyboard(top, s);
10237da2899SCharles.Forsyth		s := <-top.ctxt.ptr =>
10337da2899SCharles.Forsyth			tk->pointer(top, *s);
10437da2899SCharles.Forsyth		inp := <-browsechan =>
10537da2899SCharles.Forsyth			(nil, lst) := sys->tokenize(inp, " \n\t");
10637da2899SCharles.Forsyth			selected := br.getselected(1);
10737da2899SCharles.Forsyth			case hd lst {
10837da2899SCharles.Forsyth				"double1pane1" =>
10937da2899SCharles.Forsyth					tkpath := hd tl lst;
11037da2899SCharles.Forsyth					file := br.getpath(tkpath);
11137da2899SCharles.Forsyth					br.defaultaction(lst, file);
11237da2899SCharles.Forsyth					(n, dir) := sys->stat(file.path);
11337da2899SCharles.Forsyth					if (n == -1 || dir.mode & sys->DMDIR)
11437da2899SCharles.Forsyth						break;
11537da2899SCharles.Forsyth					if ((len dir.name > 4 && dir.name[len dir.name - 4:] == ".dis") ||
11637da2899SCharles.Forsyth						dir.mode & 8r111)
11737da2899SCharles.Forsyth						spawn send(butchan, "run "+tkpath);
11837da2899SCharles.Forsyth					else if (dir.mode & 8r222)
11937da2899SCharles.Forsyth						spawn send(butchan, "write "+tkpath);
12037da2899SCharles.Forsyth					else if (dir.mode & 8r444)
12137da2899SCharles.Forsyth							spawn send(butchan, "open "+tkpath);
12237da2899SCharles.Forsyth				* =>
12337da2899SCharles.Forsyth					br.defaultaction(lst, nil);
12437da2899SCharles.Forsyth			}
12537da2899SCharles.Forsyth			if (!File.eq(selected, br.getselected(1)))
12637da2899SCharles.Forsyth				actionbutton(top, br.selected[1].file.path, br.selected[1].tkpath);
12737da2899SCharles.Forsyth			tkcmd(top, "update");
12837da2899SCharles.Forsyth		inp := <-butchan =>
12937da2899SCharles.Forsyth			(nil, lst) := sys->tokenize(inp, " \n\t");
13037da2899SCharles.Forsyth			case hd lst {
13137da2899SCharles.Forsyth				"refresh" =>
13237da2899SCharles.Forsyth					br.refresh();
13337da2899SCharles.Forsyth				"shell" =>
13437da2899SCharles.Forsyth					path = br.getselected(1).path;
13537da2899SCharles.Forsyth					if (path == nil)
13637da2899SCharles.Forsyth						sys->chdir(root);
13737da2899SCharles.Forsyth					else
13837da2899SCharles.Forsyth						sys->chdir(path);
13937da2899SCharles.Forsyth					sh->run(ctxt, "/dis/wm/sh.dis" :: nil);
14037da2899SCharles.Forsyth
14137da2899SCharles.Forsyth				"run" =>
14237da2899SCharles.Forsyth					spawn run(ctxt, br.getselected(1).path);
14337da2899SCharles.Forsyth				"read" =>
14437da2899SCharles.Forsyth					wtitle := tkcmd(top, hd tl lst+" cget text");
14537da2899SCharles.Forsyth					spawn openfile(ctxt, br.getselected(1).path, wtitle,0);
14637da2899SCharles.Forsyth				"write" =>
14737da2899SCharles.Forsyth					wtitle := tkcmd(top, hd tl lst+" cget text");
14837da2899SCharles.Forsyth					spawn openfile(ctxt, br.getselected(1).path, wtitle,1);
14937da2899SCharles.Forsyth			}
15037da2899SCharles.Forsyth			tkcmd(top, "update");
15137da2899SCharles.Forsyth
15237da2899SCharles.Forsyth		title = <-top.ctxt.ctl or
15337da2899SCharles.Forsyth		title = <-top.wreq or
15437da2899SCharles.Forsyth		title = <-titlebar =>
15537da2899SCharles.Forsyth			if (title == "exit" || title == "ok")
15637da2899SCharles.Forsyth				break main;
15737da2899SCharles.Forsyth			e := tkclient->wmctl(top, title);
15837da2899SCharles.Forsyth			if (e != nil && e[0] == '!')
15937da2899SCharles.Forsyth				br.resize();
16037da2899SCharles.Forsyth		}
16137da2899SCharles.Forsyth	}
16237da2899SCharles.Forsyth	if (title == "ok")
16337da2899SCharles.Forsyth		return br.getselected(1).path;
16437da2899SCharles.Forsyth	return "";
16537da2899SCharles.Forsyth}
16637da2899SCharles.Forsyth
16737da2899SCharles.Forsythsend(chanout: chan of string, s: string)
16837da2899SCharles.Forsyth{
16937da2899SCharles.Forsyth	chanout <-= s;
17037da2899SCharles.Forsyth}
17137da2899SCharles.Forsyth
17237da2899SCharles.Forsythresize(top: ref Tk->Toplevel, img: ref Draw->Image)
17337da2899SCharles.Forsyth{
17437da2899SCharles.Forsyth	if (img != nil) {
17537da2899SCharles.Forsyth		scw := img.r.dx();
17637da2899SCharles.Forsyth		sch := img.r.dy();
17737da2899SCharles.Forsyth		ww := int tkcmd(top, ". cget -width");
17837da2899SCharles.Forsyth		wh := int tkcmd(top, ". cget -height");
17937da2899SCharles.Forsyth		if (ww > scw)
18037da2899SCharles.Forsyth			tkcmd(top, ". configure -x 0 -width "+string scw);
18137da2899SCharles.Forsyth		if (wh > sch)
18237da2899SCharles.Forsyth			tkcmd(top, ". configure -y 0 -height "+string sch);
18337da2899SCharles.Forsyth	}
18437da2899SCharles.Forsyth}
18537da2899SCharles.Forsyth
18637da2899SCharles.Forsythmainscreen := array[] of {
18737da2899SCharles.Forsyth	"frame .f",
18837da2899SCharles.Forsyth	"frame .f.ftop",
18937da2899SCharles.Forsyth	"button .f.ftop.bs -text {Shell} -command {send butchan shell} -font /fonts/charon/bold.normal.font",
19037da2899SCharles.Forsyth	"button .f.ftop.br -text {Refresh} -command {send butchan refresh} -font /fonts/charon/bold.normal.font",
19137da2899SCharles.Forsyth	"grid .f.ftop.bs .f.ftop.br -row 0",
19237da2899SCharles.Forsyth	"grid columnconfigure .f.ftop 2 -minsize 30",
19337da2899SCharles.Forsyth	"grid .f.ftop -row 0 -column 0 -pady 2 -sticky w",
19437da2899SCharles.Forsyth	"label .f.l -text { } -height 1 -bg red",
19537da2899SCharles.Forsyth	"grid .f.l -row 1 -sticky ew",
19637da2899SCharles.Forsyth	"grid .fbrowse -in .f -row 2 -column 0 -sticky nsew",
19737da2899SCharles.Forsyth	"grid rowconfigure .f 2 -weight 1",
19837da2899SCharles.Forsyth	"grid columnconfigure .f 0 -weight 1",
19937da2899SCharles.Forsyth
20037da2899SCharles.Forsyth	"bind .Wm_t <Button-1> +{focus .Wm_t}",
20137da2899SCharles.Forsyth	"bind .Wm_t.title <Button-1> +{focus .Wm_t}",
20237da2899SCharles.Forsyth	"focus .Wm_t",
20337da2899SCharles.Forsyth};
20437da2899SCharles.Forsyth
20537da2899SCharles.Forsythreadpath(file: File): (array of ref sys->Dir, int)
20637da2899SCharles.Forsyth{
20737da2899SCharles.Forsyth	(dirs, nil) := readdir->init(file.path, readdir->NAME | readdir->COMPACT);
20837da2899SCharles.Forsyth	return (dirs, 0);
20937da2899SCharles.Forsyth}
21037da2899SCharles.Forsyth
21137da2899SCharles.Forsythrun(ctxt: ref Draw->Context, file: string)
21237da2899SCharles.Forsyth{
21337da2899SCharles.Forsyth	sys->pctl(sys->FORKNS | sys->NEWPGRP, nil);
21437da2899SCharles.Forsyth	sys->chdir(browser->prevpath(file));
21537da2899SCharles.Forsyth	sh->run(ctxt, file :: nil);
21637da2899SCharles.Forsyth}
21737da2899SCharles.Forsyth
21837da2899SCharles.Forsythopenscr := array[] of {
21937da2899SCharles.Forsyth	"frame .f",
22037da2899SCharles.Forsyth	"scrollbar .f.sy -command {.f.t yview}",
22137da2899SCharles.Forsyth	"text .f.t -yscrollcommand {.f.sy set} -bg white -font /fonts/charon/plain.normal.font",
22237da2899SCharles.Forsyth	"pack .f.sy -side left -fill y",
22337da2899SCharles.Forsyth	"pack .f.t -fill both -expand 1",
22437da2899SCharles.Forsyth	"bind .Wm_t <Button-1> +{focus .Wm_t}",
22537da2899SCharles.Forsyth	"bind .Wm_t.title <Button-1> +{focus .Wm_t}",
22637da2899SCharles.Forsyth	"focus .f.t",
22737da2899SCharles.Forsyth};
22837da2899SCharles.Forsyth
22937da2899SCharles.Forsythfopensize := ("", "");
23037da2899SCharles.Forsyth
23137da2899SCharles.Forsythplumbing := array[] of {
23237da2899SCharles.Forsyth	("bit", "wm/view"),
23337da2899SCharles.Forsyth	("jpg", "wm/view"),
23437da2899SCharles.Forsyth};
23537da2899SCharles.Forsyth
23637da2899SCharles.Forsythfreader(top: ref Tk->Toplevel, fd: ref sys->FD, sync: chan of int)
23737da2899SCharles.Forsyth{
23837da2899SCharles.Forsyth	sync <-= sys->pctl(0,nil);
23937da2899SCharles.Forsyth	buf := array[8192] of byte;
24037da2899SCharles.Forsyth	for (;;) {
24137da2899SCharles.Forsyth		i := sys->read(fd, buf, len buf);
24237da2899SCharles.Forsyth		if (i < 1)
24337da2899SCharles.Forsyth			return;
24437da2899SCharles.Forsyth		s :="";
24537da2899SCharles.Forsyth		for (j := 0; j < i; j++) {
24637da2899SCharles.Forsyth			c := int buf[j];
24737da2899SCharles.Forsyth			if (c == '{' || c == '}')
24837da2899SCharles.Forsyth				s[len s] = '\\';
24937da2899SCharles.Forsyth			s[len s] = c;
25037da2899SCharles.Forsyth		}
25137da2899SCharles.Forsyth		tk->cmd(top, ".f.t insert end {"+s+"}; update");
25237da2899SCharles.Forsyth	}
25337da2899SCharles.Forsyth}
25437da2899SCharles.Forsyth
25537da2899SCharles.Forsythopenfile(ctxt: ref draw->Context, file, title: string, writeable: int)
25637da2899SCharles.Forsyth{
25737da2899SCharles.Forsyth	ext := getext(file);
25837da2899SCharles.Forsyth	plumb := getplumb(ext);
25937da2899SCharles.Forsyth	if (plumb != nil) {
26037da2899SCharles.Forsyth		sh->run(ctxt, plumb :: file :: nil);
26137da2899SCharles.Forsyth		return;
26237da2899SCharles.Forsyth	}
26337da2899SCharles.Forsyth	button := tkclient->Appl;
26437da2899SCharles.Forsyth	if (writeable)
26537da2899SCharles.Forsyth		button = button | tkclient->OK;
26637da2899SCharles.Forsyth	(top, titlebar) := tkclient->toplevel(ctxt, "", title, button);
26737da2899SCharles.Forsyth	tkcmds(top, openscr);
26837da2899SCharles.Forsyth	tkcmd(top,"pack .f -fill both -expand 1");
26937da2899SCharles.Forsyth	tkcmd(top,"pack propagate . 0");
27037da2899SCharles.Forsyth	(w,h) := fopensize;
27137da2899SCharles.Forsyth	if (w != "" && h != "")
27237da2899SCharles.Forsyth		tkcmd(top, ". configure -width "+w+" -height "+h);
27337da2899SCharles.Forsyth	killpid := -1;
27437da2899SCharles.Forsyth	fd := sys->open(file, sys->OREAD);
27537da2899SCharles.Forsyth	if (fd != nil) {
27637da2899SCharles.Forsyth		sync := chan of int;
27737da2899SCharles.Forsyth		spawn freader(top, fd, sync);
27837da2899SCharles.Forsyth		killpid = <-sync;
27937da2899SCharles.Forsyth	}
28037da2899SCharles.Forsyth	tkcmd(top, "update");
28137da2899SCharles.Forsyth	tkclient->onscreen(top, nil);
28237da2899SCharles.Forsyth	tkclient->startinput(top, "kbd"::"ptr"::nil);
28337da2899SCharles.Forsyth	main: for (;;) {
28437da2899SCharles.Forsyth		alt {
28537da2899SCharles.Forsyth		s := <-top.ctxt.kbd =>
28637da2899SCharles.Forsyth			tk->keyboard(top, s);
28737da2899SCharles.Forsyth		s := <-top.ctxt.ptr =>
28837da2899SCharles.Forsyth			tk->pointer(top, *s);
28937da2899SCharles.Forsyth
29037da2899SCharles.Forsyth		title = <-top.ctxt.ctl or
29137da2899SCharles.Forsyth		title = <-top.wreq or
29237da2899SCharles.Forsyth		title = <-titlebar =>
29337da2899SCharles.Forsyth			if (title == "exit" || title == "ok")
29437da2899SCharles.Forsyth				break main;
29537da2899SCharles.Forsyth			tkclient->wmctl(top, title);
29637da2899SCharles.Forsyth		}
29737da2899SCharles.Forsyth	}
29837da2899SCharles.Forsyth	if (killpid != -1)
29937da2899SCharles.Forsyth		kill(killpid);
30037da2899SCharles.Forsyth	fopensize = (tkcmd(top, ". cget -width"), tkcmd(top, ". cget -height"));
30137da2899SCharles.Forsyth	if (title == "ok") {
30237da2899SCharles.Forsyth		(n, dir) := sys->stat(file);
30337da2899SCharles.Forsyth		if (n != -1) {
30437da2899SCharles.Forsyth			fd = sys->create(file, sys->OWRITE, dir.mode);
30537da2899SCharles.Forsyth			if (fd != nil) {
30637da2899SCharles.Forsyth				s := tkcmd(top, ".f.t get 1.0 end");
30737da2899SCharles.Forsyth				sys->fprint(fd,"%s",s);
30837da2899SCharles.Forsyth				fd = nil;
30937da2899SCharles.Forsyth			}
31037da2899SCharles.Forsyth		}
31137da2899SCharles.Forsyth	}
31237da2899SCharles.Forsyth}
31337da2899SCharles.Forsyth
31437da2899SCharles.Forsythbadmod(path: string)
31537da2899SCharles.Forsyth{
31637da2899SCharles.Forsyth	sys->print("FBrowse: failed to load: %s\n",path);
31737da2899SCharles.Forsyth	exit;
31837da2899SCharles.Forsyth}
31937da2899SCharles.Forsyth
32037da2899SCharles.Forsythtkcmd(top: ref Tk->Toplevel, cmd: string): string
32137da2899SCharles.Forsyth{
32237da2899SCharles.Forsyth	e := tk->cmd(top, cmd);
32337da2899SCharles.Forsyth	if (e != "" && e[0] == '!')
32437da2899SCharles.Forsyth		sys->print("Tk error: '%s': %s\n",cmd,e);
32537da2899SCharles.Forsyth	return e;
32637da2899SCharles.Forsyth}
32737da2899SCharles.Forsyth
32837da2899SCharles.Forsythtkcmds(top: ref Tk->Toplevel, a: array of string)
32937da2899SCharles.Forsyth{
33037da2899SCharles.Forsyth	for (j := 0; j < len a; j++)
33137da2899SCharles.Forsyth		tkcmd(top, a[j]);
33237da2899SCharles.Forsyth}
33337da2899SCharles.Forsyth
33437da2899SCharles.Forsythnactionbuttons := 0;
33537da2899SCharles.Forsythactionbutton(top: ref Tk->Toplevel, path, tkpath: string)
33637da2899SCharles.Forsyth{
33737da2899SCharles.Forsyth	(n, dir) := sys->stat(path);
33837da2899SCharles.Forsyth	for (i := 0; i < nactionbuttons; i++) {
33937da2899SCharles.Forsyth		tkcmd(top, "grid forget .f.ftop.baction"+string i);
34037da2899SCharles.Forsyth		tkcmd(top, "destroy .f.ftop.baction"+string i);
34137da2899SCharles.Forsyth	}
34237da2899SCharles.Forsyth	if (path == nil || n == -1 || dir.mode & sys->DMDIR) {
34337da2899SCharles.Forsyth		nactionbuttons = 0;
34437da2899SCharles.Forsyth		return;
34537da2899SCharles.Forsyth	}
34637da2899SCharles.Forsyth	buttons : list of (string,string) = nil;
34737da2899SCharles.Forsyth
34837da2899SCharles.Forsyth	if (dir.mode & 8r222)
34937da2899SCharles.Forsyth		buttons = ("Open", "write "+tkpath) :: buttons;
35037da2899SCharles.Forsyth	else if (dir.mode & 8r444)
35137da2899SCharles.Forsyth		buttons = ("Open", "read "+tkpath) :: buttons;
35237da2899SCharles.Forsyth	if (len dir.name > 4 && dir.name[len dir.name - 4:] == ".dis" || dir.mode & 8r111)
35337da2899SCharles.Forsyth		buttons = ("Run", "run "+tkpath) :: buttons;
35437da2899SCharles.Forsyth
35537da2899SCharles.Forsyth	nactionbuttons = len buttons;
35637da2899SCharles.Forsyth	for (i = 0; i < nactionbuttons; i++) {
35737da2899SCharles.Forsyth		name := ".f.ftop.baction"+string i+" ";
35837da2899SCharles.Forsyth		(text,cmd) := hd buttons;
35937da2899SCharles.Forsyth		tkcmd(top, "button "+name+"-text {"+text+"} "+
36037da2899SCharles.Forsyth				"-font /fonts/charon/bold.normal.font "+
36137da2899SCharles.Forsyth				"-command {send butchan "+cmd+"}");
36237da2899SCharles.Forsyth		tkcmd(top, "grid "+name+" -row 0 -column "+string (4+i));
36337da2899SCharles.Forsyth		buttons = tl buttons;
36437da2899SCharles.Forsyth	}
36537da2899SCharles.Forsyth}
36637da2899SCharles.Forsyth
36737da2899SCharles.Forsythgetext(file: string): string
36837da2899SCharles.Forsyth{
369*170ff9d4SCharles Forsyth	(nil, lst) := sys->tokenize(file, ".");
37037da2899SCharles.Forsyth	for (; tl lst != nil; lst = tl lst)
37137da2899SCharles.Forsyth		;
37237da2899SCharles.Forsyth	return hd lst;
37337da2899SCharles.Forsyth}
37437da2899SCharles.Forsyth
37537da2899SCharles.Forsythgetplumb(ext: string): string
37637da2899SCharles.Forsyth{
37737da2899SCharles.Forsyth	for (i := 0; i < len plumbing; i++)
37837da2899SCharles.Forsyth		if (ext == plumbing[i].t0)
37937da2899SCharles.Forsyth			return plumbing[i].t1;
38037da2899SCharles.Forsyth	return nil;
38137da2899SCharles.Forsyth}
38237da2899SCharles.Forsyth
38337da2899SCharles.Forsythkill(pid: int)
38437da2899SCharles.Forsyth{
38537da2899SCharles.Forsyth	if ((fd := sys->open("/prog/" + string pid + "/ctl", Sys->OWRITE)) != nil)
38637da2899SCharles.Forsyth		sys->fprint(fd, "kill");
38737da2899SCharles.Forsyth}
388