xref: /inferno-os/appl/acme/util.b (revision 546783184a373a2dd59afef3affe029a6aedd701)
1implement Utils;
2
3include "common.m";
4include "sh.m";
5include "env.m";
6
7sys : Sys;
8draw : Draw;
9gui : Gui;
10acme : Acme;
11dat : Dat;
12graph : Graph;
13textm : Textm;
14windowm : Windowm;
15columnm : Columnm;
16rowm : Rowm;
17scrl : Scroll;
18look : Look;
19
20RELEASECOPY : import acme;
21Point, Rect : import draw;
22Astring, TRUE, FALSE, Mntdir, Lock : import dat;
23mouse, activecol, seltext, row : import dat;
24cursorset : import graph;
25mainwin : import gui;
26Text : import textm;
27Window : import windowm;
28Column : import columnm;
29Row : import rowm;
30
31init(mods : ref Dat->Mods)
32{
33	sys = mods.sys;
34	draw = mods.draw;
35	gui = mods.gui;
36	acme = mods.acme;
37	dat = mods.dat;
38	graph = mods.graph;
39	textm = mods.textm;
40	windowm = mods.windowm;
41	columnm = mods.columnm;
42	rowm = mods.rowm;
43	scrl = mods.scroll;
44	look = mods.look;
45
46	stderr = sys->fildes(2);
47}
48
49min(x : int, y : int) : int
50{
51	if (x < y)
52		return x;
53	return y;
54}
55
56max(x : int, y : int) : int
57{
58	if (x > y)
59		return x;
60	return y;
61}
62
63abs(x : int) : int
64{
65	if (x < 0)
66		return -x;
67	return x;
68}
69
70isalnum(c : int) : int
71{
72	#
73	# Hard to get absolutely right.  Use what we know about ASCII
74	# and assume anything above the Latin control characters is
75	# potentially an alphanumeric.
76	#
77	if(c <= ' ')
78		return FALSE;
79	if(16r7F<=c && c<=16rA0)
80		return FALSE;
81	if(strchr("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c) >= 0)
82		return FALSE;
83	return TRUE;
84	# return ('a' <= c && c <= 'z') ||
85	#	   ('A' <= c && c <= 'Z') ||
86	#	   ('0' <= c && c <= '9');
87}
88
89strchr(s : string, c : int) : int
90{
91	for (i := 0; i < len s; i++)
92		if (s[i] == c)
93			return i;
94	return -1;
95}
96
97strrchr(s : string, c : int) : int
98{
99	for (i := len s - 1; i >= 0; i--)
100		if (s[i] == c)
101			return i;
102	return -1;
103}
104
105strncmp(s, t : string, n : int) : int
106{
107	if (len s > n)
108		s = s[0:n];
109	if (len t > n)
110		t = t[0:n];
111	if (s < t)
112		return -1;
113	if (s > t)
114		return 1;
115	return 0;
116}
117
118env : Env;
119
120getenv(s : string) : string
121{
122	if (env == nil)
123		env = load Env Env->PATH;
124	e := env->getenv(s);
125	if(e != nil && e[len e - 1] == '\n')	# shell bug
126		return e[0: len e -1];
127	return e;
128}
129
130setenv(s, t : string)
131{
132	if (env == nil)
133		env = load Env Env->PATH;
134	env->setenv(s, t);
135}
136
137stob(s : string, n : int) : array of byte
138{
139	b := array[2*n] of byte;
140	for (i := 0; i < n; i++) {
141		b[2*i] = byte (s[i]&16rff);
142		b[2*i+1] = byte ((s[i]>>8)&16rff);
143	}
144	return b;
145}
146
147btos(b : array of byte, s : ref Astring)
148{
149	n := (len b)/2;
150	for (i := 0; i < n; i++)
151		s.s[i] = int b[2*i] | ((int b[2*i+1])<<8);
152}
153
154reverse(ol : list of string) : list of string
155{
156	nl : list of string;
157
158	nl = nil;
159	while (ol != nil) {
160		nl = hd ol :: nl;
161		ol = tl ol;
162	}
163	return nl;
164}
165
166nextarg(p : ref Arg) : int
167{
168	bp : string;
169
170	if(p.av != nil){
171		bp = hd p.av;
172		if(bp != nil && bp[0] == '-'){
173			p.p = bp[1:];
174			p.av = tl p.av;
175			return 1;
176		}
177	}
178	p.p = nil;
179	return 0;
180}
181
182arginit(av : list of string) : ref Arg
183{
184	p : ref Arg;
185
186	p = ref Arg;
187	p.arg0 = hd av;
188	p.av = tl av;
189	nextarg(p);
190	return p;
191}
192
193argopt(p : ref Arg) : int
194{
195	r : int;
196
197	if(p.p == nil && nextarg(p) == 0)
198		return 0;
199	r = p.p[0];
200	p.p = p.p[1:];
201	return r;
202}
203
204argf(p : ref Arg) : string
205{
206	bp : string;
207
208	if(p.p != nil){
209		bp = p.p;
210		p.p = nil;
211	} else if(p.av != nil){
212		bp = hd p.av;
213		p.av = tl p.av;
214	} else
215		bp = nil;
216	return bp;
217}
218
219exec(cmd : string, argl : list of string)
220{
221	file := cmd;
222	if(len file<4 || file[len file-4:]!=".dis")
223		file += ".dis";
224
225	c := load Command file;
226	if(c == nil) {
227		err := sys->sprint("%r");
228		if(file[0]!='/' && file[0:2]!="./"){
229			c = load Command "/dis/"+file;
230			if(c == nil)
231				err = sys->sprint("%r");
232		}
233		if(c == nil){
234			# debug(sys->sprint("file %s not found\n", file));
235			sys->fprint(stderr, "%s: %s\n", cmd, err);
236			return;
237		}
238	}
239	c->init(acme->acmectxt, argl);
240}
241
242getuser() : string
243{
244  	fd := sys->open("/dev/user", sys->OREAD);
245  	if(fd == nil)
246    		return "";
247
248  	buf := array[128] of byte;
249  	n := sys->read(fd, buf, len buf);
250  	if(n < 0)
251    		return "";
252
253  	return string buf[0:n];
254}
255
256gethome(usr : string) : string
257{
258	if (usr == nil)
259		usr = "tmp";
260	return "/usr/" + usr;
261}
262
263postnote(t : int, this : int, pid : int, note : string) : int
264{
265	if (pid == this || pid == 0)
266		return 0;
267	# fd := sys->open("/prog/" + string pid + "/ctl", sys->OWRITE);
268	fd := sys->open("#p/" + string pid + "/ctl", sys->OWRITE);
269	if (fd == nil)
270		return -1;
271	if (t == PNGROUP)
272		note += "grp";
273	sys->fprint(fd, "%s", note);
274	fd = nil;
275	return 0;
276}
277
278error(s : string)
279{
280	sys->fprint(stderr, "acme: %s: %r\n", s);
281	debug(sys->sprint("error %s : %r\n", s));
282	# s[-1] = 0;	# create broken process for debugging
283	acme->acmeexit("error");
284}
285
286dlock : ref Lock;
287dfd : ref Sys->FD;
288
289debuginit()
290{
291	if (RELEASECOPY)
292		return;
293	dfd = sys->create("./debug", Sys->OWRITE, 8r600);
294	# fd = nil;
295	dlock = Lock.init();
296}
297
298debugpr(s : string)
299{
300	if (RELEASECOPY)
301		return;
302	# fd := sys->open("./debug", Sys->OWRITE);
303	# sys->seek(fd, big 0, Sys->SEEKEND);
304	sys->fprint(dfd, "%s", s);
305	# fd = nil;
306}
307
308debug(s : string)
309{
310	if (RELEASECOPY)
311		return;
312	if (dfd == nil)
313		return;
314	dlock.lock();
315	debugpr(s);
316	dlock.unlock();
317}
318
319memfd : ref Sys->FD;
320memb : array of byte;
321
322memdebug(s : string)
323{
324	if (RELEASECOPY)
325		return;
326	dlock.lock();
327	if (memfd == nil) {
328		sys->bind("#c", "/usr/jrf/mnt", Sys->MBEFORE);
329		memfd = sys->open("/usr/jrf/mnt/memory", Sys->OREAD);
330		memb = array[1024] of byte;
331	}
332	sys->seek(memfd, big 0, 0);
333	n := sys->read(memfd, memb, len memb);
334	if (n <= 0) {
335		dlock.unlock();
336		debug(sys->sprint("bad read %r\n"));
337		return;
338	}
339	s = s + " : " + string memb[0:n] + "\n";
340	dlock.unlock();
341	debug(s);
342	s = nil;
343}
344
345rgetc(s : string, n : int) : int
346{
347	if (n < 0 || n >= len s)
348		return 0;
349	return s[n];
350}
351
352tgetc(t : ref Text, n : int) : int
353{
354	if(n >= t.file.buf.nc)
355		return 0;
356	return t.readc(n);
357}
358
359skipbl(r : string, n : int) : (string, int)
360{
361	i : int = 0;
362
363	while(n>0 && (r[i]==' ' || r[i]=='\t' || r[i]=='\n')){
364		--n;
365		i++;
366	}
367	return (r[i:], n);
368}
369
370findbl(r : string, n : int) : (string, int)
371{
372	i : int = 0;
373
374	while(n>0 && r[i]!=' ' && r[i]!='\t' && r[i]!='\n'){
375		--n;
376		i++;
377	}
378	return (r[i:], n);
379}
380
381prevmouse : Point;
382mousew : ref Window;
383
384savemouse(w : ref Window)
385{
386	prevmouse = mouse.xy;
387	mousew = w;
388}
389
390restoremouse(w : ref Window)
391{
392	if(mousew!=nil && mousew==w)
393		cursorset(prevmouse);
394	mousew = nil;
395}
396
397clearmouse()
398{
399	mousew = nil;
400}
401
402#
403# Heuristic city.
404#
405newwindow(t : ref Text) : ref Window
406{
407	c : ref Column;
408	w, bigw, emptyw : ref Window;
409	emptyb : ref Text;
410	i, y, el : int;
411
412	if(activecol != nil)
413		c = activecol;
414	else if(seltext != nil && seltext.col != nil)
415		c = seltext.col;
416	else if(t != nil && t.col != nil)
417		c = t.col;
418	else{
419		if(row.ncol==0 && row.add(nil, -1)==nil)
420			error("can't make column");
421		c = row.col[row.ncol-1];
422	}
423	activecol = c;
424	if(t==nil || t.w==nil || c.nw==0)
425		return c.add(nil, nil, -1);
426
427	# find biggest window and biggest blank spot
428	emptyw = c.w[0];
429	bigw = emptyw;
430	for(i=1; i<c.nw; i++){
431		w = c.w[i];
432		# use >= to choose one near bottom of screen
433		if(w.body.frame.maxlines >= bigw.body.frame.maxlines)
434			bigw = w;
435		if(w.body.frame.maxlines-w.body.frame.nlines >= emptyw.body.frame.maxlines-emptyw.body.frame.nlines)
436			emptyw = w;
437	}
438	emptyb = emptyw.body;
439	el = emptyb.frame.maxlines-emptyb.frame.nlines;
440	# if empty space is big, use it
441	if(el>15 || (el>3 && el>(bigw.body.frame.maxlines-1)/2))
442		y = emptyb.frame.r.min.y+emptyb.frame.nlines*(graph->font).height;
443	else{
444		# if this window is in column and isn't much smaller, split it
445		if(t.col==c && t.w.r.dy()>2*bigw.r.dy()/3)
446			bigw = t.w;
447		y = (bigw.r.min.y + bigw.r.max.y)/2;
448	}
449	w = c.add(nil, nil, y);
450	if(w.body.frame.maxlines < 2)
451		w.col.grow(w, 1, 1);
452	return w;
453}
454
455stralloc(n : int) : ref Astring
456{
457	r := ref Astring;
458	ab := array[n] of { * => byte 'z' };
459	r.s = string ab;
460	if (len r.s != n)
461		error("bad stralloc");
462	ab = nil;
463	return r;
464}
465
466strfree(s : ref Astring)
467{
468	s.s = nil;
469	s = nil;
470}
471
472access(s : string) : int
473{
474	fd := sys->open(s, 0);
475	if (fd == nil)
476		return -1;
477	fd = nil;
478	return 0;
479}
480
481errorwin(dir : string, ndir : int, incl : array of string, nincl : int) : ref Window
482{
483	w : ref Window;
484	r : string;
485	i, n : int;
486
487	n = ndir;
488	r = dir + "+Errors";
489	n += 7;
490	w = look->lookfile(r, n);
491	if(w == nil){
492		w = row.col[row.ncol-1].add(nil, nil, -1);
493		w.filemenu = FALSE;
494		w.setname(r, n);
495	}
496	r = nil;
497	for(i=nincl; --i>=0; )
498		w.addincl(incl[i], n);
499	return w;
500}
501
502warning(md : ref Mntdir, s : string)
503{
504	n, q0, owner : int;
505	w : ref Window;
506	t : ref Text;
507
508	debug(sys->sprint("warning %s\n", s));
509	if (row == nil) {
510		sys->fprint(sys->fildes(2), "warning: %s\n", s);
511		debug(s);
512		debug("\n");
513		return;
514	}
515	if(row.ncol == 0){	# really early error
516		row.init(mainwin.clipr);
517		row.add(nil, -1);
518		row.add(nil, -1);
519		if(row.ncol == 0)
520			error("initializing columns in warning()");
521	}
522	if(md != nil){
523		for(;;){
524			w = errorwin(md.dir, md.ndir, md.incl, md.nincl);
525			w.lock('E');
526			if (w.col != nil)
527				break;
528			# window was deleted too fast
529			w.unlock();
530		}
531	}else
532		w = errorwin(nil, 0, nil, 0);
533	t = w.body;
534	owner = w.owner;
535	if(owner == 0)
536		w.owner = 'E';
537	w.commit(t);
538	(q0, n) = t.bsinsert(t.file.buf.nc, s, len s, TRUE);
539	t.show(q0, q0+n, TRUE);
540	t.w.settag();
541	scrl->scrdraw(t);
542	w.owner = owner;
543	w.dirty = FALSE;
544	if(md != nil)
545		w.unlock();
546}
547
548getexc(): string
549{
550	f := "/prog/"+string sys->pctl(0, nil)+"/exception";
551	if((fd := sys->open(f, Sys->OREAD)) == nil)
552		return nil;
553	b := array[8192] of byte;
554	if((n := sys->read(fd, b, len b)) < 0)
555		return nil;
556	return string b[0: n];
557}
558
559# returns pc, module, exception
560readexc(): (int, string, string)
561{
562	s := getexc();
563	if(s == nil)
564		return (0, nil, nil);
565	(m, l) := sys->tokenize(s, " ");
566	if(m < 3)
567		return (0, nil, nil);
568	pc := int hd l;	l = tl l;
569	mod := hd l;	l = tl l;
570	exc := hd l;	l = tl l;
571	for( ; l != nil; l = tl l)
572		exc += " " + hd l;
573	return (pc, mod, exc);
574}
575