shithub: purgatorio

ref: 41e27b2d10c6a60c49931332e8677438736a1e36
dir: /appl/acme/util.b/

View raw version
implement Utils;

include "common.m";
include "sh.m";
include "env.m";

sys : Sys;
draw : Draw;
gui : Gui;
acme : Acme;
dat : Dat;
graph : Graph;
textm : Textm;
windowm : Windowm;
columnm : Columnm;
rowm : Rowm;
scrl : Scroll;
look : Look;

RELEASECOPY : import acme;
Point, Rect : import draw;
Astring, TRUE, FALSE, Mntdir, Lock : import dat;
mouse, activecol, seltext, row : import dat;
cursorset : import graph;
mainwin : import gui;
Text : import textm;
Window : import windowm;
Column : import columnm;
Row : import rowm;

init(mods : ref Dat->Mods)
{
	sys = mods.sys;
	draw = mods.draw;
	gui = mods.gui;
	acme = mods.acme;
	dat = mods.dat;
	graph = mods.graph;
	textm = mods.textm;
	windowm = mods.windowm;
	columnm = mods.columnm;
	rowm = mods.rowm;
	scrl = mods.scroll;
	look = mods.look;

	stderr = sys->fildes(2);
}

min(x : int, y : int) : int
{
	if (x < y)
		return x;
	return y;
}

max(x : int, y : int) : int
{
	if (x > y)
		return x;
	return y;
}

abs(x : int) : int
{
	if (x < 0)
		return -x;
	return x;
}

isalnum(c : int) : int
{
	#
	# Hard to get absolutely right.  Use what we know about ASCII
	# and assume anything above the Latin control characters is
	# potentially an alphanumeric.
	#
	if(c <= ' ')
		return FALSE;
	if(16r7F<=c && c<=16rA0)
		return FALSE;
	if(strchr("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c) >= 0)
		return FALSE;
	return TRUE;
	# return ('a' <= c && c <= 'z') || 
	#	   ('A' <= c && c <= 'Z') ||
	#	   ('0' <= c && c <= '9');
}

strchr(s : string, c : int) : int
{
	for (i := 0; i < len s; i++)
		if (s[i] == c)
			return i;
	return -1;
} 

strrchr(s : string, c : int) : int
{
	for (i := len s - 1; i >= 0; i--)
		if (s[i] == c)
			return i;
	return -1;
}

strncmp(s, t : string, n : int) : int
{
	if (len s > n)
		s = s[0:n];
	if (len t > n)
		t = t[0:n];
	if (s < t)
		return -1;
	if (s > t)
		return 1;
	return 0;
}

env : Env;

getenv(s : string) : string
{
	if (env == nil)
		env = load Env Env->PATH;
	e := env->getenv(s);
	if(e != nil && e[len e - 1] == '\n')	# shell bug
		return e[0: len e -1];
	return e;
}

setenv(s, t : string)
{
	if (env == nil)
		env = load Env Env->PATH;
	env->setenv(s, t);
}

stob(s : string, n : int) : array of byte
{
	b := array[2*n] of byte;
	for (i := 0; i < n; i++) {
		b[2*i] = byte (s[i]&16rff);
		b[2*i+1] = byte ((s[i]>>8)&16rff);
	}
	return b;
}

btos(b : array of byte, s : ref Astring)
{
	n := (len b)/2;
	for (i := 0; i < n; i++)
		s.s[i] = int b[2*i] | ((int b[2*i+1])<<8);
}

reverse(ol : list of string) : list of string
{
	nl : list of string;

	nl = nil;
	while (ol != nil) {
		nl = hd ol :: nl;
		ol = tl ol;
	}
	return nl;
}

nextarg(p : ref Arg) : int
{
	bp : string;

	if(p.av != nil){
		bp = hd p.av;
		if(bp != nil && bp[0] == '-'){
			p.p = bp[1:];
			p.av = tl p.av;
			return 1;
		}
	}
	p.p = nil;
	return 0;
}

arginit(av : list of string) : ref Arg
{
	p : ref Arg;

	p = ref Arg;
	p.arg0 = hd av;
	p.av = tl av;
	nextarg(p);
	return p;
}

argopt(p : ref Arg) : int
{
	r : int;

	if(p.p == nil && nextarg(p) == 0)
		return 0;
	r = p.p[0];
	p.p = p.p[1:];
	return r;
}

argf(p : ref Arg) : string
{
	bp : string;

	if(p.p != nil){
		bp = p.p;
		p.p = nil;
	} else if(p.av != nil){
		bp = hd p.av;
		p.av = tl p.av;
	} else
		bp = nil;
	return bp;
}

exec(cmd : string, argl : list of string)
{
	file := cmd;
	if(len file<4 || file[len file-4:]!=".dis")
		file += ".dis";

	c := load Command file;
	if(c == nil) {
		err := sys->sprint("%r");
		if(file[0]!='/' && file[0:2]!="./"){
			c = load Command "/dis/"+file;
			if(c == nil)
				err = sys->sprint("%r");
		}
		if(c == nil){
			# debug(sys->sprint("file %s not found\n", file));
			sys->fprint(stderr, "%s: %s\n", cmd, err);
			return;
		}
	}
	c->init(acme->acmectxt, argl);
}

getuser() : string
{
  	fd := sys->open("/dev/user", sys->OREAD);
  	if(fd == nil)
    		return "";

  	buf := array[128] of byte;
  	n := sys->read(fd, buf, len buf);
  	if(n < 0)
    		return "";

  	return string buf[0:n];	
}

gethome(usr : string) : string
{
	if (usr == nil)
		usr = "tmp";
	return "/usr/" + usr;
}

postnote(t : int, this : int, pid : int, note : string) : int
{
	if (pid == this || pid == 0)
		return 0;
	# fd := sys->open("/prog/" + string pid + "/ctl", sys->OWRITE);
	fd := sys->open("#p/" + string pid + "/ctl", sys->OWRITE);
	if (fd == nil)
		return -1;
	if (t == PNGROUP)
		note += "grp";
	sys->fprint(fd, "%s", note);
	fd = nil;
	return 0;
}

error(s : string)
{
	sys->fprint(stderr, "acme: %s: %r\n", s);
	debug(sys->sprint("error %s : %r\n", s));
	# s[-1] = 0;	# create broken process for debugging
	acme->acmeexit("error");
}

dlock : ref Lock;
dfd : ref Sys->FD;

debuginit()
{
	if (RELEASECOPY)
		return;
	dfd = sys->create("./debug", Sys->OWRITE, 8r600);
	# fd = nil;
	dlock = Lock.init();
}

debugpr(s : string)
{
	if (RELEASECOPY)
		return;
	# fd := sys->open("./debug", Sys->OWRITE);
	# sys->seek(fd, big 0, Sys->SEEKEND);
	sys->fprint(dfd, "%s", s);
	# fd = nil;
}

debug(s : string)
{
	if (RELEASECOPY)
		return;
	if (dfd == nil)
		return;
	dlock.lock();
	debugpr(s);	
	dlock.unlock();
}

memfd : ref Sys->FD;
memb : array of byte;

memdebug(s : string)
{
	if (RELEASECOPY)
		return;
	dlock.lock();
	if (memfd == nil) {
		sys->bind("#c", "/usr/jrf/mnt", Sys->MBEFORE);
		memfd = sys->open("/usr/jrf/mnt/memory", Sys->OREAD);
		memb = array[1024] of byte;
	}
	sys->seek(memfd, big 0, 0);
	n := sys->read(memfd, memb, len memb);
	if (n <= 0) {
		dlock.unlock();
		debug(sys->sprint("bad read %r\n"));
		return;
	}
	s = s + " : " + string memb[0:n] + "\n";
	dlock.unlock();
	debug(s);
	s = nil;
}

rgetc(s : string, n : int) : int
{
	if (n < 0 || n >= len s)
		return 0;
	return s[n];
}

tgetc(t : ref Text, n : int) : int
{
	if(n >= t.file.buf.nc)
		return 0;
	return t.readc(n);
}

skipbl(r : string, n : int) : (string, int)
{
	i : int = 0;

	while(n>0 && (r[i]==' ' || r[i]=='\t' || r[i]=='\n')){
		--n;
		i++;
	}
	return (r[i:], n);
}

findbl(r : string, n : int) : (string, int)
{
	i : int = 0;

	while(n>0 && r[i]!=' ' && r[i]!='\t' && r[i]!='\n'){
		--n;
		i++;
	}
	return (r[i:], n);
}

prevmouse : Point;
mousew : ref Window;

savemouse(w : ref Window)
{
	prevmouse = mouse.xy;
	mousew = w;
}

restoremouse(w : ref Window)
{
	if(mousew!=nil && mousew==w)
		cursorset(prevmouse);
	mousew = nil;
}

clearmouse()
{
	mousew = nil;
}

#
# Heuristic city.
#
newwindow(t : ref Text) : ref Window
{
	c : ref Column;
	w, bigw, emptyw : ref Window;
	emptyb : ref Text;
	i, y, el : int;

	if(activecol != nil)
		c = activecol;
	else if(seltext != nil && seltext.col != nil)
		c = seltext.col;
	else if(t != nil && t.col != nil)
		c = t.col;
	else{
		if(row.ncol==0 && row.add(nil, -1)==nil)
			error("can't make column");
		c = row.col[row.ncol-1];
	}
	activecol = c;
	if(t==nil || t.w==nil || c.nw==0)
		return c.add(nil, nil, -1);

	# find biggest window and biggest blank spot
	emptyw = c.w[0];
	bigw = emptyw;
	for(i=1; i<c.nw; i++){
		w = c.w[i];
		# use >= to choose one near bottom of screen
		if(w.body.frame.maxlines >= bigw.body.frame.maxlines)
			bigw = w;
		if(w.body.frame.maxlines-w.body.frame.nlines >= emptyw.body.frame.maxlines-emptyw.body.frame.nlines)
			emptyw = w;
	}
	emptyb = emptyw.body;
	el = emptyb.frame.maxlines-emptyb.frame.nlines;
	# if empty space is big, use it
	if(el>15 || (el>3 && el>(bigw.body.frame.maxlines-1)/2))
		y = emptyb.frame.r.min.y+emptyb.frame.nlines*(graph->font).height;
	else{
		# if this window is in column and isn't much smaller, split it
		if(t.col==c && t.w.r.dy()>2*bigw.r.dy()/3)
			bigw = t.w;
		y = (bigw.r.min.y + bigw.r.max.y)/2;
	}
	w = c.add(nil, nil, y);
	if(w.body.frame.maxlines < 2)
		w.col.grow(w, 1, 1);
	return w;
}

stralloc(n : int) : ref Astring
{
	r := ref Astring;
	ab := array[n] of { * => byte 'z' };
	r.s = string ab;
	if (len r.s != n)
		error("bad stralloc");
	ab = nil;
	return r;
}

strfree(s : ref Astring)
{
	s.s = nil;
	s = nil;
}

access(s : string) : int
{
	fd := sys->open(s, 0);
	if (fd == nil)
		return -1;
	fd = nil;
	return 0;
}

errorwin(dir : string, ndir : int, incl : array of string, nincl : int) : ref Window
{
	w : ref Window;
	r : string;
	i, n : int;

	n = ndir;
	r = dir + "+Errors";
	n += 7;
	w = look->lookfile(r, n);
	if(w == nil){
		w = row.col[row.ncol-1].add(nil, nil, -1);
		w.filemenu = FALSE;
		w.setname(r, n);
	}
	r = nil;
	for(i=nincl; --i>=0; )
		w.addincl(incl[i], n);
	return w;
}

warning(md : ref Mntdir, s : string)
{
	n, q0, owner : int;
	w : ref Window;
	t : ref Text;

	debug(sys->sprint("warning %s\n", s));
	if (row == nil) {
		sys->fprint(sys->fildes(2), "warning: %s\n", s);
		debug(s); 
		debug("\n");
		return;
	}	
	if(row.ncol == 0){	# really early error
		row.init(mainwin.clipr);
		row.add(nil, -1);
		row.add(nil, -1);
		if(row.ncol == 0)
			error("initializing columns in warning()");
	}
	if(md != nil){
		for(;;){
			w = errorwin(md.dir, md.ndir, md.incl, md.nincl);
			w.lock('E');
			if (w.col != nil)
				break;
			# window was deleted too fast
			w.unlock();
		}
	}else
		w = errorwin(nil, 0, nil, 0);
	t = w.body;
	owner = w.owner;
	if(owner == 0)
		w.owner = 'E';
	w.commit(t);
	(q0, n) = t.bsinsert(t.file.buf.nc, s, len s, TRUE);
	t.show(q0, q0+n, TRUE);
	t.w.settag();
	scrl->scrdraw(t);
	w.owner = owner;
	w.dirty = FALSE;
	if(md != nil)
		w.unlock();
}

getexc(): string
{
	f := "/prog/"+string sys->pctl(0, nil)+"/exception";
	if((fd := sys->open(f, Sys->OREAD)) == nil)
		return nil;
	b := array[8192] of byte;
	if((n := sys->read(fd, b, len b)) < 0)
		return nil;
	return string b[0: n];
}

# returns pc, module, exception
readexc(): (int, string, string)
{
	s := getexc();
	if(s == nil)
		return (0, nil, nil);
	(m, l) := sys->tokenize(s, " ");
	if(m < 3)
		return (0, nil, nil);
	pc := int hd l;	l = tl l;
	mod := hd l;	l = tl l;
	exc := hd l;	l = tl l;
	for( ; l != nil; l = tl l)
		exc += " " + hd l;
	return (pc, mod, exc);
}