xref: /plan9-contrib/sys/src/cmd/acme/look.c (revision a4aad0ee5148f819550a444cc5cf8474f36dda62)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <thread.h>
59a747e4fSDavid du Colombier #include <cursor.h>
67dd7cddfSDavid du Colombier #include <mouse.h>
77dd7cddfSDavid du Colombier #include <keyboard.h>
87dd7cddfSDavid du Colombier #include <frame.h>
97dd7cddfSDavid du Colombier #include <fcall.h>
107dd7cddfSDavid du Colombier #include <regexp.h>
117dd7cddfSDavid du Colombier #include <plumb.h>
127dd7cddfSDavid du Colombier #include "dat.h"
137dd7cddfSDavid du Colombier #include "fns.h"
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier Window*	openfile(Text*, Expand*);
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier int	nuntitled;
187dd7cddfSDavid du Colombier 
197dd7cddfSDavid du Colombier void
look3(Text * t,uint q0,uint q1,int external)207dd7cddfSDavid du Colombier look3(Text *t, uint q0, uint q1, int external)
217dd7cddfSDavid du Colombier {
227dd7cddfSDavid du Colombier 	int n, c, f, expanded;
237dd7cddfSDavid du Colombier 	Text *ct;
247dd7cddfSDavid du Colombier 	Expand e;
257dd7cddfSDavid du Colombier 	Rune *r;
267dd7cddfSDavid du Colombier 	uint p;
277dd7cddfSDavid du Colombier 	Plumbmsg *m;
287dd7cddfSDavid du Colombier 	Runestr dir;
297dd7cddfSDavid du Colombier 	char buf[32];
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier 	ct = seltext;
327dd7cddfSDavid du Colombier 	if(ct == nil)
337dd7cddfSDavid du Colombier 		seltext = t;
347dd7cddfSDavid du Colombier 	expanded = expand(t, q0, q1, &e);
357dd7cddfSDavid du Colombier 	if(!external && t->w!=nil && t->w->nopen[QWevent]>0){
367dd7cddfSDavid du Colombier 		/* send alphanumeric expansion to external client */
377dd7cddfSDavid du Colombier 		if(expanded == FALSE)
387dd7cddfSDavid du Colombier 			return;
397dd7cddfSDavid du Colombier 		f = 0;
407dd7cddfSDavid du Colombier 		if((e.at!=nil && t->w!=nil) || (e.nname>0 && lookfile(e.name, e.nname)!=nil))
417dd7cddfSDavid du Colombier 			f = 1;		/* acme can do it without loading a file */
427dd7cddfSDavid du Colombier 		if(q0!=e.q0 || q1!=e.q1)
437dd7cddfSDavid du Colombier 			f |= 2;	/* second (post-expand) message follows */
447dd7cddfSDavid du Colombier 		if(e.nname)
457dd7cddfSDavid du Colombier 			f |= 4;	/* it's a file name */
467dd7cddfSDavid du Colombier 		c = 'l';
477dd7cddfSDavid du Colombier 		if(t->what == Body)
487dd7cddfSDavid du Colombier 			c = 'L';
497dd7cddfSDavid du Colombier 		n = q1-q0;
507dd7cddfSDavid du Colombier 		if(n <= EVENTSIZE){
517dd7cddfSDavid du Colombier 			r = runemalloc(n);
527dd7cddfSDavid du Colombier 			bufread(t->file, q0, r, n);
537dd7cddfSDavid du Colombier 			winevent(t->w, "%c%d %d %d %d %.*S\n", c, q0, q1, f, n, n, r);
547dd7cddfSDavid du Colombier 			free(r);
557dd7cddfSDavid du Colombier 		}else
567dd7cddfSDavid du Colombier 			winevent(t->w, "%c%d %d %d 0 \n", c, q0, q1, f, n);
577dd7cddfSDavid du Colombier 		if(q0==e.q0 && q1==e.q1)
587dd7cddfSDavid du Colombier 			return;
597dd7cddfSDavid du Colombier 		if(e.nname){
607dd7cddfSDavid du Colombier 			n = e.nname;
617dd7cddfSDavid du Colombier 			if(e.a1 > e.a0)
627dd7cddfSDavid du Colombier 				n += 1+(e.a1-e.a0);
637dd7cddfSDavid du Colombier 			r = runemalloc(n);
647dd7cddfSDavid du Colombier 			runemove(r, e.name, e.nname);
657dd7cddfSDavid du Colombier 			if(e.a1 > e.a0){
667dd7cddfSDavid du Colombier 				r[e.nname] = ':';
677dd7cddfSDavid du Colombier 				bufread(e.at->file, e.a0, r+e.nname+1, e.a1-e.a0);
687dd7cddfSDavid du Colombier 			}
697dd7cddfSDavid du Colombier 		}else{
707dd7cddfSDavid du Colombier 			n = e.q1 - e.q0;
717dd7cddfSDavid du Colombier 			r = runemalloc(n);
727dd7cddfSDavid du Colombier 			bufread(t->file, e.q0, r, n);
737dd7cddfSDavid du Colombier 		}
747dd7cddfSDavid du Colombier 		f &= ~2;
757dd7cddfSDavid du Colombier 		if(n <= EVENTSIZE)
767dd7cddfSDavid du Colombier 			winevent(t->w, "%c%d %d %d %d %.*S\n", c, e.q0, e.q1, f, n, n, r);
777dd7cddfSDavid du Colombier 		else
787dd7cddfSDavid du Colombier 			winevent(t->w, "%c%d %d %d 0 \n", c, e.q0, e.q1, f, n);
797dd7cddfSDavid du Colombier 		free(r);
807dd7cddfSDavid du Colombier 		goto Return;
817dd7cddfSDavid du Colombier 	}
827dd7cddfSDavid du Colombier 	if(plumbsendfd >= 0){
837dd7cddfSDavid du Colombier 		/* send whitespace-delimited word to plumber */
847dd7cddfSDavid du Colombier 		m = emalloc(sizeof(Plumbmsg));
8559cc4ca5SDavid du Colombier 		m->src = estrdup("acme");
867dd7cddfSDavid du Colombier 		m->dst = nil;
877dd7cddfSDavid du Colombier 		dir = dirname(t, nil, 0);
887dd7cddfSDavid du Colombier 		if(dir.nr==1 && dir.r[0]=='.'){	/* sigh */
897dd7cddfSDavid du Colombier 			free(dir.r);
907dd7cddfSDavid du Colombier 			dir.r = nil;
917dd7cddfSDavid du Colombier 			dir.nr = 0;
927dd7cddfSDavid du Colombier 		}
937dd7cddfSDavid du Colombier 		if(dir.nr == 0)
9459cc4ca5SDavid du Colombier 			m->wdir = estrdup(wdir);
957dd7cddfSDavid du Colombier 		else
967dd7cddfSDavid du Colombier 			m->wdir = runetobyte(dir.r, dir.nr);
977dd7cddfSDavid du Colombier 		free(dir.r);
9859cc4ca5SDavid du Colombier 		m->type = estrdup("text");
997dd7cddfSDavid du Colombier 		m->attr = nil;
1007dd7cddfSDavid du Colombier 		buf[0] = '\0';
1017dd7cddfSDavid du Colombier 		if(q1 == q0){
1027dd7cddfSDavid du Colombier 			if(t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){
1037dd7cddfSDavid du Colombier 				q0 = t->q0;
1047dd7cddfSDavid du Colombier 				q1 = t->q1;
1057dd7cddfSDavid du Colombier 			}else{
1067dd7cddfSDavid du Colombier 				p = q0;
1077dd7cddfSDavid du Colombier 				while(q0>0 && (c=tgetc(t, q0-1))!=' ' && c!='\t' && c!='\n')
1087dd7cddfSDavid du Colombier 					q0--;
1097dd7cddfSDavid du Colombier 				while(q1<t->file->nc && (c=tgetc(t, q1))!=' ' && c!='\t' && c!='\n')
1107dd7cddfSDavid du Colombier 					q1++;
1117dd7cddfSDavid du Colombier 				if(q1 == q0){
1127dd7cddfSDavid du Colombier 					plumbfree(m);
1137dd7cddfSDavid du Colombier 					goto Return;
1147dd7cddfSDavid du Colombier 				}
1157dd7cddfSDavid du Colombier 				sprint(buf, "click=%d", p-q0);
1167dd7cddfSDavid du Colombier 				m->attr = plumbunpackattr(buf);
1177dd7cddfSDavid du Colombier 			}
1187dd7cddfSDavid du Colombier 		}
1197dd7cddfSDavid du Colombier 		r = runemalloc(q1-q0);
1207dd7cddfSDavid du Colombier 		bufread(t->file, q0, r, q1-q0);
1217dd7cddfSDavid du Colombier 		m->data = runetobyte(r, q1-q0);
1227dd7cddfSDavid du Colombier 		m->ndata = strlen(m->data);
1237dd7cddfSDavid du Colombier 		free(r);
1249a747e4fSDavid du Colombier 		if(m->ndata<messagesize-1024 && plumbsend(plumbsendfd, m) >= 0){
1257dd7cddfSDavid du Colombier 			plumbfree(m);
1267dd7cddfSDavid du Colombier 			goto Return;
1277dd7cddfSDavid du Colombier 		}
1287dd7cddfSDavid du Colombier 		plumbfree(m);
1297dd7cddfSDavid du Colombier 		/* plumber failed to match; fall through */
1307dd7cddfSDavid du Colombier 	}
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier 	/* interpret alphanumeric string ourselves */
1337dd7cddfSDavid du Colombier 	if(expanded == FALSE)
1347dd7cddfSDavid du Colombier 		return;
1357dd7cddfSDavid du Colombier 	if(e.name || e.at)
1367dd7cddfSDavid du Colombier 		openfile(t, &e);
1377dd7cddfSDavid du Colombier 	else{
1387dd7cddfSDavid du Colombier 		if(t->w == nil)
1397dd7cddfSDavid du Colombier 			return;
1407dd7cddfSDavid du Colombier 		ct = &t->w->body;
1417dd7cddfSDavid du Colombier 		if(t->w != ct->w)
1427dd7cddfSDavid du Colombier 			winlock(ct->w, 'M');
1437dd7cddfSDavid du Colombier 		if(t == ct)
1447dd7cddfSDavid du Colombier 			textsetselect(ct, e.q1, e.q1);
1457dd7cddfSDavid du Colombier 		n = e.q1 - e.q0;
1467dd7cddfSDavid du Colombier 		r = runemalloc(n);
1477dd7cddfSDavid du Colombier 		bufread(t->file, e.q0, r, n);
1487dd7cddfSDavid du Colombier 		if(search(ct, r, n) && e.jump)
1497dd7cddfSDavid du Colombier 			moveto(mousectl, addpt(frptofchar(ct, ct->p0), Pt(4, ct->font->height-4)));
1507dd7cddfSDavid du Colombier 		if(t->w != ct->w)
1517dd7cddfSDavid du Colombier 			winunlock(ct->w);
1527dd7cddfSDavid du Colombier 		free(r);
1537dd7cddfSDavid du Colombier 	}
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier    Return:
1567dd7cddfSDavid du Colombier 	free(e.name);
1577dd7cddfSDavid du Colombier 	free(e.bname);
1587dd7cddfSDavid du Colombier }
1597dd7cddfSDavid du Colombier 
1607dd7cddfSDavid du Colombier int
plumbgetc(void * a,uint n)1617dd7cddfSDavid du Colombier plumbgetc(void *a, uint n)
1627dd7cddfSDavid du Colombier {
1637dd7cddfSDavid du Colombier 	Rune *r;
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier 	r = a;
166c93608ccSDavid du Colombier 	if(n>runestrlen(r))
1677dd7cddfSDavid du Colombier 		return 0;
1687dd7cddfSDavid du Colombier 	return r[n];
1697dd7cddfSDavid du Colombier }
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier void
plumblook(Plumbmsg * m)1727dd7cddfSDavid du Colombier plumblook(Plumbmsg *m)
1737dd7cddfSDavid du Colombier {
1747dd7cddfSDavid du Colombier 	Expand e;
1757dd7cddfSDavid du Colombier 	char *addr;
1767dd7cddfSDavid du Colombier 
1777dd7cddfSDavid du Colombier 	if(m->ndata >= BUFSIZE){
1787dd7cddfSDavid du Colombier 		warning(nil, "insanely long file name (%d bytes) in plumb message (%.32s...)\n", m->ndata, m->data);
1797dd7cddfSDavid du Colombier 		return;
1807dd7cddfSDavid du Colombier 	}
1817dd7cddfSDavid du Colombier 	e.q0 = 0;
1827dd7cddfSDavid du Colombier 	e.q1 = 0;
1837dd7cddfSDavid du Colombier 	if(m->data[0] == '\0')
1847dd7cddfSDavid du Colombier 		return;
1857dd7cddfSDavid du Colombier 	e.ar = nil;
1867dd7cddfSDavid du Colombier 	e.bname = m->data;
1877dd7cddfSDavid du Colombier 	e.name = bytetorune(e.bname, &e.nname);
1887dd7cddfSDavid du Colombier 	e.jump = TRUE;
1897dd7cddfSDavid du Colombier 	e.a0 = 0;
1907dd7cddfSDavid du Colombier 	e.a1 = 0;
1917dd7cddfSDavid du Colombier 	addr = plumblookup(m->attr, "addr");
1927dd7cddfSDavid du Colombier 	if(addr != nil){
1937dd7cddfSDavid du Colombier 		e.ar = bytetorune(addr, &e.a1);
1947dd7cddfSDavid du Colombier 		e.agetc = plumbgetc;
1957dd7cddfSDavid du Colombier 	}
1967dd7cddfSDavid du Colombier 	openfile(nil, &e);
1977dd7cddfSDavid du Colombier 	free(e.name);
1987dd7cddfSDavid du Colombier 	free(e.at);
1997dd7cddfSDavid du Colombier }
2007dd7cddfSDavid du Colombier 
2017dd7cddfSDavid du Colombier void
plumbshow(Plumbmsg * m)2027dd7cddfSDavid du Colombier plumbshow(Plumbmsg *m)
2037dd7cddfSDavid du Colombier {
2047dd7cddfSDavid du Colombier 	Window *w;
2057dd7cddfSDavid du Colombier 	Rune rb[256], *r;
2067dd7cddfSDavid du Colombier 	int nb, nr;
2077dd7cddfSDavid du Colombier 	Runestr rs;
2087dd7cddfSDavid du Colombier 	char *name, *p, namebuf[16];
2097dd7cddfSDavid du Colombier 
210d9306527SDavid du Colombier 	w = makenewwindow(nil);
2117dd7cddfSDavid du Colombier 	name = plumblookup(m->attr, "filename");
2127dd7cddfSDavid du Colombier 	if(name == nil){
2137dd7cddfSDavid du Colombier 		name = namebuf;
2147dd7cddfSDavid du Colombier 		nuntitled++;
2157dd7cddfSDavid du Colombier 		snprint(namebuf, sizeof namebuf, "Untitled-%d", nuntitled);
2167dd7cddfSDavid du Colombier 	}
2177dd7cddfSDavid du Colombier 	p = nil;
2187dd7cddfSDavid du Colombier 	if(name[0]!='/' && m->wdir!=nil && m->wdir[0]!='\0'){
2197dd7cddfSDavid du Colombier 		nb = strlen(m->wdir) + 1 + strlen(name) + 1;
2207dd7cddfSDavid du Colombier 		p = emalloc(nb);
2217dd7cddfSDavid du Colombier 		snprint(p, nb, "%s/%s", m->wdir, name);
2227dd7cddfSDavid du Colombier 		name = p;
2237dd7cddfSDavid du Colombier 	}
2247dd7cddfSDavid du Colombier 	cvttorunes(name, strlen(name), rb, &nb, &nr, nil);
2257dd7cddfSDavid du Colombier 	free(p);
2267dd7cddfSDavid du Colombier 	rs = cleanrname((Runestr){rb, nr});
2277dd7cddfSDavid du Colombier 	winsetname(w, rs.r, rs.nr);
2287dd7cddfSDavid du Colombier 	r = runemalloc(m->ndata);
2297dd7cddfSDavid du Colombier 	cvttorunes(m->data, m->ndata, r, &nb, &nr, nil);
2307dd7cddfSDavid du Colombier 	textinsert(&w->body, 0, r, nr, TRUE);
2319a747e4fSDavid du Colombier 	free(r);
2327dd7cddfSDavid du Colombier 	w->body.file->mod = FALSE;
2337dd7cddfSDavid du Colombier 	w->dirty = FALSE;
2347dd7cddfSDavid du Colombier 	winsettag(w);
2357dd7cddfSDavid du Colombier 	textscrdraw(&w->body);
2367dd7cddfSDavid du Colombier 	textsetselect(&w->tag, w->tag.file->nc, w->tag.file->nc);
2377dd7cddfSDavid du Colombier }
2387dd7cddfSDavid du Colombier 
2397dd7cddfSDavid du Colombier int
search(Text * ct,Rune * r,uint n)2407dd7cddfSDavid du Colombier search(Text *ct, Rune *r, uint n)
2417dd7cddfSDavid du Colombier {
2427dd7cddfSDavid du Colombier 	uint q, nb, maxn;
2437dd7cddfSDavid du Colombier 	int around;
2447dd7cddfSDavid du Colombier 	Rune *s, *b, *c;
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier 	if(n==0 || n>ct->file->nc)
2477dd7cddfSDavid du Colombier 		return FALSE;
2487dd7cddfSDavid du Colombier 	if(2*n > RBUFSIZE){
2497dd7cddfSDavid du Colombier 		warning(nil, "string too long\n");
2507dd7cddfSDavid du Colombier 		return FALSE;
2517dd7cddfSDavid du Colombier 	}
2527dd7cddfSDavid du Colombier 	maxn = max(2*n, RBUFSIZE);
2537dd7cddfSDavid du Colombier 	s = fbufalloc();
2547dd7cddfSDavid du Colombier 	b = s;
2557dd7cddfSDavid du Colombier 	nb = 0;
2567dd7cddfSDavid du Colombier 	b[nb] = 0;
2577dd7cddfSDavid du Colombier 	around = 0;
2587dd7cddfSDavid du Colombier 	q = ct->q1;
2597dd7cddfSDavid du Colombier 	for(;;){
2607dd7cddfSDavid du Colombier 		if(q >= ct->file->nc){
2617dd7cddfSDavid du Colombier 			q = 0;
2627dd7cddfSDavid du Colombier 			around = 1;
2637dd7cddfSDavid du Colombier 			nb = 0;
2647dd7cddfSDavid du Colombier 			b[nb] = 0;
2657dd7cddfSDavid du Colombier 		}
2667dd7cddfSDavid du Colombier 		if(nb > 0){
26759cc4ca5SDavid du Colombier 			c = runestrchr(b, r[0]);
2687dd7cddfSDavid du Colombier 			if(c == nil){
2697dd7cddfSDavid du Colombier 				q += nb;
2707dd7cddfSDavid du Colombier 				nb = 0;
2717dd7cddfSDavid du Colombier 				b[nb] = 0;
2727dd7cddfSDavid du Colombier 				if(around && q>=ct->q1)
2737dd7cddfSDavid du Colombier 					break;
2747dd7cddfSDavid du Colombier 				continue;
2757dd7cddfSDavid du Colombier 			}
2767dd7cddfSDavid du Colombier 			q += (c-b);
2777dd7cddfSDavid du Colombier 			nb -= (c-b);
2787dd7cddfSDavid du Colombier 			b = c;
2797dd7cddfSDavid du Colombier 		}
2807dd7cddfSDavid du Colombier 		/* reload if buffer covers neither string nor rest of file */
2817dd7cddfSDavid du Colombier 		if(nb<n && nb!=ct->file->nc-q){
2827dd7cddfSDavid du Colombier 			nb = ct->file->nc-q;
2837dd7cddfSDavid du Colombier 			if(nb >= maxn)
2847dd7cddfSDavid du Colombier 				nb = maxn-1;
2857dd7cddfSDavid du Colombier 			bufread(ct->file, q, s, nb);
2867dd7cddfSDavid du Colombier 			b = s;
2877dd7cddfSDavid du Colombier 			b[nb] = '\0';
2887dd7cddfSDavid du Colombier 		}
2897dd7cddfSDavid du Colombier 		/* this runeeq is fishy but the null at b[nb] makes it safe */
2907dd7cddfSDavid du Colombier 		if(runeeq(b, n, r, n)==TRUE){
2917dd7cddfSDavid du Colombier 			if(ct->w){
2929a747e4fSDavid du Colombier 				textshow(ct, q, q+n, 1);
2937dd7cddfSDavid du Colombier 				winsettag(ct->w);
2947dd7cddfSDavid du Colombier 			}else{
2957dd7cddfSDavid du Colombier 				ct->q0 = q;
2967dd7cddfSDavid du Colombier 				ct->q1 = q+n;
2977dd7cddfSDavid du Colombier 			}
2987dd7cddfSDavid du Colombier 			seltext = ct;
2997dd7cddfSDavid du Colombier 			fbuffree(s);
3007dd7cddfSDavid du Colombier 			return TRUE;
3017dd7cddfSDavid du Colombier 		}
3027dd7cddfSDavid du Colombier 		--nb;
3037dd7cddfSDavid du Colombier 		b++;
3047dd7cddfSDavid du Colombier 		q++;
305*a4aad0eeSDavid du Colombier 		if(around && q>=ct->q1)
306*a4aad0eeSDavid du Colombier 			break;
3077dd7cddfSDavid du Colombier 	}
3087dd7cddfSDavid du Colombier 	fbuffree(s);
3097dd7cddfSDavid du Colombier 	return FALSE;
3107dd7cddfSDavid du Colombier }
3117dd7cddfSDavid du Colombier 
3127dd7cddfSDavid du Colombier int
isfilec(Rune r)3137dd7cddfSDavid du Colombier isfilec(Rune r)
3147dd7cddfSDavid du Colombier {
3157dd7cddfSDavid du Colombier 	if(isalnum(r))
3167dd7cddfSDavid du Colombier 		return TRUE;
31759cc4ca5SDavid du Colombier 	if(runestrchr(L".-+/:", r))
3187dd7cddfSDavid du Colombier 		return TRUE;
3197dd7cddfSDavid du Colombier 	return FALSE;
3207dd7cddfSDavid du Colombier }
3217dd7cddfSDavid du Colombier 
322fe853e23SDavid du Colombier /* Runestr wrapper for cleanname */
3237dd7cddfSDavid du Colombier Runestr
cleanrname(Runestr rs)3247dd7cddfSDavid du Colombier cleanrname(Runestr rs)
3257dd7cddfSDavid du Colombier {
326b1ffb6adSDavid du Colombier 	char *s;
327b1ffb6adSDavid du Colombier 	int nb, nulls;
3287dd7cddfSDavid du Colombier 
329b1ffb6adSDavid du Colombier 	s = runetobyte(rs.r, rs.nr);
330b1ffb6adSDavid du Colombier 	cleanname(s);
331b1ffb6adSDavid du Colombier 	cvttorunes(s, strlen(s), rs.r, &nb, &rs.nr, &nulls);
332b1ffb6adSDavid du Colombier 	free(s);
333b1ffb6adSDavid du Colombier 	return rs;
3347dd7cddfSDavid du Colombier }
3357dd7cddfSDavid du Colombier 
3367dd7cddfSDavid du Colombier Runestr
includefile(Rune * dir,Rune * file,int nfile)3377dd7cddfSDavid du Colombier includefile(Rune *dir, Rune *file, int nfile)
3387dd7cddfSDavid du Colombier {
3397dd7cddfSDavid du Colombier 	int m, n;
3407dd7cddfSDavid du Colombier 	char *a;
3417dd7cddfSDavid du Colombier 	Rune *r;
3427dd7cddfSDavid du Colombier 
3437dd7cddfSDavid du Colombier 	m = runestrlen(dir);
3447dd7cddfSDavid du Colombier 	a = emalloc((m+1+nfile)*UTFmax+1);
3457dd7cddfSDavid du Colombier 	sprint(a, "%S/%.*S", dir, nfile, file);
3467dd7cddfSDavid du Colombier 	n = access(a, 0);
3477dd7cddfSDavid du Colombier 	free(a);
3487dd7cddfSDavid du Colombier 	if(n < 0)
3497dd7cddfSDavid du Colombier 		return (Runestr){nil, 0};
3507dd7cddfSDavid du Colombier 	r = runemalloc(m+1+nfile);
3517dd7cddfSDavid du Colombier 	runemove(r, dir, m);
3527dd7cddfSDavid du Colombier 	runemove(r+m, L"/", 1);
3537dd7cddfSDavid du Colombier 	runemove(r+m+1, file, nfile);
3547dd7cddfSDavid du Colombier 	free(file);
3557dd7cddfSDavid du Colombier 	return cleanrname((Runestr){r, m+1+nfile});
3567dd7cddfSDavid du Colombier }
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier static	Rune	*objdir;
3597dd7cddfSDavid du Colombier 
3607dd7cddfSDavid du Colombier Runestr
includename(Text * t,Rune * r,int n)3617dd7cddfSDavid du Colombier includename(Text *t, Rune *r, int n)
3627dd7cddfSDavid du Colombier {
3637dd7cddfSDavid du Colombier 	Window *w;
3647dd7cddfSDavid du Colombier 	char buf[128];
3657dd7cddfSDavid du Colombier 	Runestr file;
3667dd7cddfSDavid du Colombier 	int i;
3677dd7cddfSDavid du Colombier 
3687dd7cddfSDavid du Colombier 	if(objdir==nil && objtype!=nil){
3697dd7cddfSDavid du Colombier 		sprint(buf, "/%s/include", objtype);
3707dd7cddfSDavid du Colombier 		objdir = bytetorune(buf, &i);
3717dd7cddfSDavid du Colombier 		objdir = runerealloc(objdir, i+1);
3727dd7cddfSDavid du Colombier 		objdir[i] = '\0';
3737dd7cddfSDavid du Colombier 	}
3747dd7cddfSDavid du Colombier 
3757dd7cddfSDavid du Colombier 	w = t->w;
3767dd7cddfSDavid du Colombier 	if(n==0 || r[0]=='/' || w==nil)
3777dd7cddfSDavid du Colombier 		goto Rescue;
3787dd7cddfSDavid du Colombier 	if(n>2 && r[0]=='.' && r[1]=='/')
3797dd7cddfSDavid du Colombier 		goto Rescue;
3807dd7cddfSDavid du Colombier 	file.r = nil;
3817dd7cddfSDavid du Colombier 	file.nr = 0;
3827dd7cddfSDavid du Colombier 	for(i=0; i<w->nincl && file.r==nil; i++)
3837dd7cddfSDavid du Colombier 		file = includefile(w->incl[i], r, n);
3847dd7cddfSDavid du Colombier 
3857dd7cddfSDavid du Colombier 	if(file.r == nil)
3867dd7cddfSDavid du Colombier 		file = includefile(L"/sys/include", r, n);
3877dd7cddfSDavid du Colombier 	if(file.r==nil && objdir!=nil)
3887dd7cddfSDavid du Colombier 		file = includefile(objdir, r, n);
3897dd7cddfSDavid du Colombier 	if(file.r == nil)
3907dd7cddfSDavid du Colombier 		goto Rescue;
3917dd7cddfSDavid du Colombier 	return file;
3927dd7cddfSDavid du Colombier 
3937dd7cddfSDavid du Colombier     Rescue:
3947dd7cddfSDavid du Colombier 	return (Runestr){r, n};
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier Runestr
dirname(Text * t,Rune * r,int n)3987dd7cddfSDavid du Colombier dirname(Text *t, Rune *r, int n)
3997dd7cddfSDavid du Colombier {
4007dd7cddfSDavid du Colombier 	Rune *b, c;
4017dd7cddfSDavid du Colombier 	uint m, nt;
4027dd7cddfSDavid du Colombier 	int slash;
4037dd7cddfSDavid du Colombier 	Runestr tmp;
4047dd7cddfSDavid du Colombier 
4057dd7cddfSDavid du Colombier 	b = nil;
40659cc4ca5SDavid du Colombier 	if(t==nil || t->w==nil)
4077dd7cddfSDavid du Colombier 		goto Rescue;
4087dd7cddfSDavid du Colombier 	nt = t->w->tag.file->nc;
4097dd7cddfSDavid du Colombier 	if(nt == 0)
4107dd7cddfSDavid du Colombier 		goto Rescue;
4117dd7cddfSDavid du Colombier 	if(n>=1 && r[0]=='/')
4127dd7cddfSDavid du Colombier 		goto Rescue;
4137dd7cddfSDavid du Colombier 	b = runemalloc(nt+n+1);
4147dd7cddfSDavid du Colombier 	bufread(t->w->tag.file, 0, b, nt);
4157dd7cddfSDavid du Colombier 	slash = -1;
4167dd7cddfSDavid du Colombier 	for(m=0; m<nt; m++){
4177dd7cddfSDavid du Colombier 		c = b[m];
4187dd7cddfSDavid du Colombier 		if(c == '/')
4197dd7cddfSDavid du Colombier 			slash = m;
4207dd7cddfSDavid du Colombier 		if(c==' ' || c=='\t')
4217dd7cddfSDavid du Colombier 			break;
4227dd7cddfSDavid du Colombier 	}
4237dd7cddfSDavid du Colombier 	if(slash < 0)
4247dd7cddfSDavid du Colombier 		goto Rescue;
4257dd7cddfSDavid du Colombier 	runemove(b+slash+1, r, n);
4267dd7cddfSDavid du Colombier 	free(r);
4277dd7cddfSDavid du Colombier 	return cleanrname((Runestr){b, slash+1+n});
4287dd7cddfSDavid du Colombier 
4297dd7cddfSDavid du Colombier     Rescue:
4307dd7cddfSDavid du Colombier 	free(b);
4317dd7cddfSDavid du Colombier 	tmp = (Runestr){r, n};
4327dd7cddfSDavid du Colombier 	if(r)
4337dd7cddfSDavid du Colombier 		return cleanrname(tmp);
4347dd7cddfSDavid du Colombier 	return tmp;
4357dd7cddfSDavid du Colombier }
4367dd7cddfSDavid du Colombier 
4377dd7cddfSDavid du Colombier int
expandfile(Text * t,uint q0,uint q1,Expand * e)4387dd7cddfSDavid du Colombier expandfile(Text *t, uint q0, uint q1, Expand *e)
4397dd7cddfSDavid du Colombier {
4407dd7cddfSDavid du Colombier 	int i, n, nname, colon, eval;
4417dd7cddfSDavid du Colombier 	uint amin, amax;
4427dd7cddfSDavid du Colombier 	Rune *r, c;
4437dd7cddfSDavid du Colombier 	Window *w;
4447dd7cddfSDavid du Colombier 	Runestr rs;
4457dd7cddfSDavid du Colombier 
4467dd7cddfSDavid du Colombier 	amax = q1;
4477dd7cddfSDavid du Colombier 	if(q1 == q0){
4487dd7cddfSDavid du Colombier 		colon = -1;
4497dd7cddfSDavid du Colombier 		while(q1<t->file->nc && isfilec(c=textreadc(t, q1))){
4507dd7cddfSDavid du Colombier 			if(c == ':'){
4517dd7cddfSDavid du Colombier 				colon = q1;
4527dd7cddfSDavid du Colombier 				break;
4537dd7cddfSDavid du Colombier 			}
4547dd7cddfSDavid du Colombier 			q1++;
4557dd7cddfSDavid du Colombier 		}
4567dd7cddfSDavid du Colombier 		while(q0>0 && (isfilec(c=textreadc(t, q0-1)) || isaddrc(c) || isregexc(c))){
4577dd7cddfSDavid du Colombier 			q0--;
4587dd7cddfSDavid du Colombier 			if(colon<0 && c==':')
4597dd7cddfSDavid du Colombier 				colon = q0;
4607dd7cddfSDavid du Colombier 		}
4617dd7cddfSDavid du Colombier 		/*
4627dd7cddfSDavid du Colombier 		 * if it looks like it might begin file: , consume address chars after :
4637dd7cddfSDavid du Colombier 		 * otherwise terminate expansion at :
4647dd7cddfSDavid du Colombier 		 */
4657dd7cddfSDavid du Colombier 		if(colon >= 0){
4667dd7cddfSDavid du Colombier 			q1 = colon;
4677dd7cddfSDavid du Colombier 			if(colon<t->file->nc-1 && isaddrc(textreadc(t, colon+1))){
4687dd7cddfSDavid du Colombier 				q1 = colon+1;
4698d724f71SDavid du Colombier 				while(q1<t->file->nc && isaddrc(textreadc(t, q1)))
4707dd7cddfSDavid du Colombier 					q1++;
4717dd7cddfSDavid du Colombier 			}
4727dd7cddfSDavid du Colombier 		}
4737dd7cddfSDavid du Colombier 		if(q1 > q0)
4747dd7cddfSDavid du Colombier 			if(colon >= 0){	/* stop at white space */
4757dd7cddfSDavid du Colombier 				for(amax=colon+1; amax<t->file->nc; amax++)
4767dd7cddfSDavid du Colombier 					if((c=textreadc(t, amax))==' ' || c=='\t' || c=='\n')
4777dd7cddfSDavid du Colombier 						break;
4787dd7cddfSDavid du Colombier 			}else
4797dd7cddfSDavid du Colombier 				amax = t->file->nc;
4807dd7cddfSDavid du Colombier 	}
4817dd7cddfSDavid du Colombier 	amin = amax;
4827dd7cddfSDavid du Colombier 	e->q0 = q0;
4837dd7cddfSDavid du Colombier 	e->q1 = q1;
4847dd7cddfSDavid du Colombier 	n = q1-q0;
4857dd7cddfSDavid du Colombier 	if(n == 0)
4867dd7cddfSDavid du Colombier 		return FALSE;
4877dd7cddfSDavid du Colombier 	/* see if it's a file name */
4887dd7cddfSDavid du Colombier 	r = runemalloc(n);
4897dd7cddfSDavid du Colombier 	bufread(t->file, q0, r, n);
4907dd7cddfSDavid du Colombier 	/* first, does it have bad chars? */
4917dd7cddfSDavid du Colombier 	nname = -1;
4927dd7cddfSDavid du Colombier 	for(i=0; i<n; i++){
4937dd7cddfSDavid du Colombier 		c = r[i];
4947dd7cddfSDavid du Colombier 		if(c==':' && nname<0){
4957dd7cddfSDavid du Colombier 			if(q0+i+1<t->file->nc && (i==n-1 || isaddrc(textreadc(t, q0+i+1))))
4967dd7cddfSDavid du Colombier 				amin = q0+i;
4977dd7cddfSDavid du Colombier 			else
4987dd7cddfSDavid du Colombier 				goto Isntfile;
4997dd7cddfSDavid du Colombier 			nname = i;
5007dd7cddfSDavid du Colombier 		}
5017dd7cddfSDavid du Colombier 	}
5027dd7cddfSDavid du Colombier 	if(nname == -1)
5037dd7cddfSDavid du Colombier 		nname = n;
5047dd7cddfSDavid du Colombier 	for(i=0; i<nname; i++)
5057dd7cddfSDavid du Colombier 		if(!isfilec(r[i]))
5067dd7cddfSDavid du Colombier 			goto Isntfile;
5077dd7cddfSDavid du Colombier 	/*
5087dd7cddfSDavid du Colombier 	 * See if it's a file name in <>, and turn that into an include
5097dd7cddfSDavid du Colombier 	 * file name if so.  Should probably do it for "" too, but that's not
5107dd7cddfSDavid du Colombier 	 * restrictive enough syntax and checking for a #include earlier on the
5117dd7cddfSDavid du Colombier 	 * line would be silly.
5127dd7cddfSDavid du Colombier 	 */
5137dd7cddfSDavid du Colombier 	if(q0>0 && textreadc(t, q0-1)=='<' && q1<t->file->nc && textreadc(t, q1)=='>'){
5147dd7cddfSDavid du Colombier 		rs = includename(t, r, nname);
5157dd7cddfSDavid du Colombier 		r = rs.r;
5167dd7cddfSDavid du Colombier 		nname = rs.nr;
5177dd7cddfSDavid du Colombier 	}
5187dd7cddfSDavid du Colombier 	else if(amin == q0)
5197dd7cddfSDavid du Colombier 		goto Isfile;
5207dd7cddfSDavid du Colombier 	else{
5217dd7cddfSDavid du Colombier 		rs = dirname(t, r, nname);
5227dd7cddfSDavid du Colombier 		r = rs.r;
5237dd7cddfSDavid du Colombier 		nname = rs.nr;
5247dd7cddfSDavid du Colombier 	}
5257dd7cddfSDavid du Colombier 	e->bname = runetobyte(r, nname);
5267dd7cddfSDavid du Colombier 	/* if it's already a window name, it's a file */
5277dd7cddfSDavid du Colombier 	w = lookfile(r, nname);
5287dd7cddfSDavid du Colombier 	if(w != nil)
5297dd7cddfSDavid du Colombier 		goto Isfile;
5307dd7cddfSDavid du Colombier 	/* if it's the name of a file, it's a file */
5317dd7cddfSDavid du Colombier 	if(access(e->bname, 0) < 0){
5327dd7cddfSDavid du Colombier 		free(e->bname);
5337dd7cddfSDavid du Colombier 		e->bname = nil;
5347dd7cddfSDavid du Colombier 		goto Isntfile;
5357dd7cddfSDavid du Colombier 	}
5367dd7cddfSDavid du Colombier 
5377dd7cddfSDavid du Colombier   Isfile:
5387dd7cddfSDavid du Colombier 	e->name = r;
5397dd7cddfSDavid du Colombier 	e->nname = nname;
5407dd7cddfSDavid du Colombier 	e->at = t;
5417dd7cddfSDavid du Colombier 	e->a0 = amin+1;
5427dd7cddfSDavid du Colombier 	eval = FALSE;
54359cc4ca5SDavid du Colombier 	address(nil, nil, (Range){-1,-1}, (Range){0, 0}, t, e->a0, amax, tgetc, &eval, (uint*)&e->a1);
5447dd7cddfSDavid du Colombier 	return TRUE;
5457dd7cddfSDavid du Colombier 
5467dd7cddfSDavid du Colombier    Isntfile:
5477dd7cddfSDavid du Colombier 	free(r);
5487dd7cddfSDavid du Colombier 	return FALSE;
5497dd7cddfSDavid du Colombier }
5507dd7cddfSDavid du Colombier 
5517dd7cddfSDavid du Colombier int
expand(Text * t,uint q0,uint q1,Expand * e)5527dd7cddfSDavid du Colombier expand(Text *t, uint q0, uint q1, Expand *e)
5537dd7cddfSDavid du Colombier {
5547dd7cddfSDavid du Colombier 	memset(e, 0, sizeof *e);
5557dd7cddfSDavid du Colombier 	e->agetc = tgetc;
5567dd7cddfSDavid du Colombier 	/* if in selection, choose selection */
5577dd7cddfSDavid du Colombier 	e->jump = TRUE;
5587dd7cddfSDavid du Colombier 	if(q1==q0 && t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){
5597dd7cddfSDavid du Colombier 		q0 = t->q0;
5607dd7cddfSDavid du Colombier 		q1 = t->q1;
5617dd7cddfSDavid du Colombier 		if(t->what == Tag)
5627dd7cddfSDavid du Colombier 			e->jump = FALSE;
5637dd7cddfSDavid du Colombier 	}
5647dd7cddfSDavid du Colombier 
5657dd7cddfSDavid du Colombier 	if(expandfile(t, q0, q1, e))
5667dd7cddfSDavid du Colombier 		return TRUE;
5677dd7cddfSDavid du Colombier 
5687dd7cddfSDavid du Colombier 	if(q0 == q1){
5697dd7cddfSDavid du Colombier 		while(q1<t->file->nc && isalnum(textreadc(t, q1)))
5707dd7cddfSDavid du Colombier 			q1++;
5717dd7cddfSDavid du Colombier 		while(q0>0 && isalnum(textreadc(t, q0-1)))
5727dd7cddfSDavid du Colombier 			q0--;
5737dd7cddfSDavid du Colombier 	}
5747dd7cddfSDavid du Colombier 	e->q0 = q0;
5757dd7cddfSDavid du Colombier 	e->q1 = q1;
5767dd7cddfSDavid du Colombier 	return q1 > q0;
5777dd7cddfSDavid du Colombier }
5787dd7cddfSDavid du Colombier 
5797dd7cddfSDavid du Colombier Window*
lookfile(Rune * s,int n)5807dd7cddfSDavid du Colombier lookfile(Rune *s, int n)
5817dd7cddfSDavid du Colombier {
5827dd7cddfSDavid du Colombier 	int i, j, k;
5837dd7cddfSDavid du Colombier 	Window *w;
5847dd7cddfSDavid du Colombier 	Column *c;
5857dd7cddfSDavid du Colombier 	Text *t;
5867dd7cddfSDavid du Colombier 
5877dd7cddfSDavid du Colombier 	/* avoid terminal slash on directories */
5887dd7cddfSDavid du Colombier 	if(n>1 && s[n-1] == '/')
5897dd7cddfSDavid du Colombier 		--n;
5907dd7cddfSDavid du Colombier 	for(j=0; j<row.ncol; j++){
5917dd7cddfSDavid du Colombier 		c = row.col[j];
5927dd7cddfSDavid du Colombier 		for(i=0; i<c->nw; i++){
5937dd7cddfSDavid du Colombier 			w = c->w[i];
5947dd7cddfSDavid du Colombier 			t = &w->body;
5957dd7cddfSDavid du Colombier 			k = t->file->nname;
596106486e8SDavid du Colombier 			if(k>1 && t->file->name[k-1] == '/')
5977dd7cddfSDavid du Colombier 				k--;
5987dd7cddfSDavid du Colombier 			if(runeeq(t->file->name, k, s, n)){
5997dd7cddfSDavid du Colombier 				w = w->body.file->curtext->w;
6007dd7cddfSDavid du Colombier 				if(w->col != nil)	/* protect against race deleting w */
6017dd7cddfSDavid du Colombier 					return w;
6027dd7cddfSDavid du Colombier 			}
6037dd7cddfSDavid du Colombier 		}
6047dd7cddfSDavid du Colombier 	}
6057dd7cddfSDavid du Colombier 	return nil;
6067dd7cddfSDavid du Colombier }
6077dd7cddfSDavid du Colombier 
6087dd7cddfSDavid du Colombier Window*
lookid(int id,int dump)6097dd7cddfSDavid du Colombier lookid(int id, int dump)
6107dd7cddfSDavid du Colombier {
6117dd7cddfSDavid du Colombier 	int i, j;
6127dd7cddfSDavid du Colombier 	Window *w;
6137dd7cddfSDavid du Colombier 	Column *c;
6147dd7cddfSDavid du Colombier 
6157dd7cddfSDavid du Colombier 	for(j=0; j<row.ncol; j++){
6167dd7cddfSDavid du Colombier 		c = row.col[j];
6177dd7cddfSDavid du Colombier 		for(i=0; i<c->nw; i++){
6187dd7cddfSDavid du Colombier 			w = c->w[i];
6197dd7cddfSDavid du Colombier 			if(dump && w->dumpid == id)
6207dd7cddfSDavid du Colombier 				return w;
6217dd7cddfSDavid du Colombier 			if(!dump && w->id == id)
6227dd7cddfSDavid du Colombier 				return w;
6237dd7cddfSDavid du Colombier 		}
6247dd7cddfSDavid du Colombier 	}
6257dd7cddfSDavid du Colombier 	return nil;
6267dd7cddfSDavid du Colombier }
6277dd7cddfSDavid du Colombier 
6287dd7cddfSDavid du Colombier 
6297dd7cddfSDavid du Colombier Window*
openfile(Text * t,Expand * e)6307dd7cddfSDavid du Colombier openfile(Text *t, Expand *e)
6317dd7cddfSDavid du Colombier {
6327dd7cddfSDavid du Colombier 	Range r;
6337dd7cddfSDavid du Colombier 	Window *w, *ow;
6347dd7cddfSDavid du Colombier 	int eval, i, n;
6357dd7cddfSDavid du Colombier 	Rune *rp;
6367dd7cddfSDavid du Colombier 	uint dummy;
6377dd7cddfSDavid du Colombier 
6387dd7cddfSDavid du Colombier 	if(e->nname == 0){
6397dd7cddfSDavid du Colombier 		w = t->w;
6407dd7cddfSDavid du Colombier 		if(w == nil)
6417dd7cddfSDavid du Colombier 			return nil;
6427dd7cddfSDavid du Colombier 	}else
6437dd7cddfSDavid du Colombier 		w = lookfile(e->name, e->nname);
6447dd7cddfSDavid du Colombier 	if(w){
6457dd7cddfSDavid du Colombier 		t = &w->body;
6467dd7cddfSDavid du Colombier 		if(!t->col->safe && t->maxlines==0) /* window is obscured by full-column window */
6477dd7cddfSDavid du Colombier 			colgrow(t->col, t->col->w[0], 1);
6487dd7cddfSDavid du Colombier 	}else{
6497dd7cddfSDavid du Colombier 		ow = nil;
6507dd7cddfSDavid du Colombier 		if(t)
6517dd7cddfSDavid du Colombier 			ow = t->w;
652d9306527SDavid du Colombier 		w = makenewwindow(t);
6537dd7cddfSDavid du Colombier 		t = &w->body;
6547dd7cddfSDavid du Colombier 		winsetname(w, e->name, e->nname);
6557dd7cddfSDavid du Colombier 		textload(t, 0, e->bname, 1);
6567dd7cddfSDavid du Colombier 		t->file->mod = FALSE;
6577dd7cddfSDavid du Colombier 		t->w->dirty = FALSE;
6587dd7cddfSDavid du Colombier 		winsettag(t->w);
6597dd7cddfSDavid du Colombier 		textsetselect(&t->w->tag, t->w->tag.file->nc, t->w->tag.file->nc);
6604fec87e5SDavid du Colombier 		if(ow != nil){
6617dd7cddfSDavid du Colombier 			for(i=ow->nincl; --i>=0; ){
6627dd7cddfSDavid du Colombier 				n = runestrlen(ow->incl[i]);
6637dd7cddfSDavid du Colombier 				rp = runemalloc(n);
6647dd7cddfSDavid du Colombier 				runemove(rp, ow->incl[i], n);
6657dd7cddfSDavid du Colombier 				winaddincl(w, rp, n);
6667dd7cddfSDavid du Colombier 			}
6674fec87e5SDavid du Colombier 			w->autoindent = ow->autoindent;
6684fec87e5SDavid du Colombier 		}else
6694fec87e5SDavid du Colombier 			w->autoindent = globalautoindent;
6707dd7cddfSDavid du Colombier 	}
6717dd7cddfSDavid du Colombier 	if(e->a1 == e->a0)
6727dd7cddfSDavid du Colombier 		eval = FALSE;
6737dd7cddfSDavid du Colombier 	else{
6747dd7cddfSDavid du Colombier 		eval = TRUE;
67559cc4ca5SDavid du Colombier 		r = address(nil, t, (Range){-1, -1}, (Range){t->q0, t->q1}, e->at, e->a0, e->a1, e->agetc, &eval, &dummy);
6769a747e4fSDavid du Colombier 		if(eval == FALSE)
6779a747e4fSDavid du Colombier 			e->jump = FALSE;	/* don't jump if invalid address */
6787dd7cddfSDavid du Colombier 	}
6797dd7cddfSDavid du Colombier 	if(eval == FALSE){
6807dd7cddfSDavid du Colombier 		r.q0 = t->q0;
6817dd7cddfSDavid du Colombier 		r.q1 = t->q1;
6827dd7cddfSDavid du Colombier 	}
6839a747e4fSDavid du Colombier 	textshow(t, r.q0, r.q1, 1);
6847dd7cddfSDavid du Colombier 	winsettag(t->w);
6857dd7cddfSDavid du Colombier 	seltext = t;
6867dd7cddfSDavid du Colombier 	if(e->jump)
6877dd7cddfSDavid du Colombier 		moveto(mousectl, addpt(frptofchar(t, t->p0), Pt(4, font->height-4)));
6887dd7cddfSDavid du Colombier 	return w;
6897dd7cddfSDavid du Colombier }
6907dd7cddfSDavid du Colombier 
6917dd7cddfSDavid du Colombier void
new(Text * et,Text * t,Text * argt,int flag1,int flag2,Rune * arg,int narg)6927dd7cddfSDavid du Colombier new(Text *et, Text *t, Text *argt, int flag1, int flag2, Rune *arg, int narg)
6937dd7cddfSDavid du Colombier {
6947dd7cddfSDavid du Colombier 	int ndone;
6957dd7cddfSDavid du Colombier 	Rune *a, *f;
6967dd7cddfSDavid du Colombier 	int na, nf;
6977dd7cddfSDavid du Colombier 	Expand e;
6987dd7cddfSDavid du Colombier 	Runestr rs;
6997dd7cddfSDavid du Colombier 
7007dd7cddfSDavid du Colombier 	getarg(argt, FALSE, TRUE, &a, &na);
7017dd7cddfSDavid du Colombier 	if(a){
7027dd7cddfSDavid du Colombier 		new(et, t, nil, flag1, flag2, a, na);
7037dd7cddfSDavid du Colombier 		if(narg == 0)
7047dd7cddfSDavid du Colombier 			return;
7057dd7cddfSDavid du Colombier 	}
7067dd7cddfSDavid du Colombier 	/* loop condition: *arg is not a blank */
7077dd7cddfSDavid du Colombier 	for(ndone=0; ; ndone++){
7087dd7cddfSDavid du Colombier 		a = findbl(arg, narg, &na);
7097dd7cddfSDavid du Colombier 		if(a == arg){
7107dd7cddfSDavid du Colombier 			if(ndone==0 && et->col!=nil)
7117dd7cddfSDavid du Colombier 				winsettag(coladd(et->col, nil, nil, -1));
7127dd7cddfSDavid du Colombier 			break;
7137dd7cddfSDavid du Colombier 		}
7147dd7cddfSDavid du Colombier 		nf = narg-na;
7157dd7cddfSDavid du Colombier 		f = runemalloc(nf);
7167dd7cddfSDavid du Colombier 		runemove(f, arg, nf);
7177dd7cddfSDavid du Colombier 		rs = dirname(et, f, nf);
7187dd7cddfSDavid du Colombier 		f = rs.r;
7197dd7cddfSDavid du Colombier 		nf = rs.nr;
7207dd7cddfSDavid du Colombier 		memset(&e, 0, sizeof e);
7217dd7cddfSDavid du Colombier 		e.name = f;
7227dd7cddfSDavid du Colombier 		e.nname = nf;
7237dd7cddfSDavid du Colombier 		e.bname = runetobyte(f, nf);
7247dd7cddfSDavid du Colombier 		e.jump = TRUE;
7257dd7cddfSDavid du Colombier 		openfile(et, &e);
7267dd7cddfSDavid du Colombier 		free(f);
7277dd7cddfSDavid du Colombier 		free(e.bname);
7287dd7cddfSDavid du Colombier 		arg = skipbl(a, na, &narg);
7297dd7cddfSDavid du Colombier 	}
7307dd7cddfSDavid du Colombier }
731