xref: /plan9-contrib/sys/src/cmd/sam/xec.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include "sam.h"
2 #include "parse.h"
3 
4 int	Glooping;
5 int	nest;
6 
7 int	append(File*, Cmd*, Posn);
8 int	display(File*);
9 void	looper(File*, Cmd*, int);
10 void	filelooper(Cmd*, int);
11 void	linelooper(File*, Cmd*);
12 
13 void
14 resetxec(void)
15 {
16 	Glooping = nest = 0;
17 }
18 
19 int
20 cmdexec(File *f, Cmd *cp)
21 {
22 	int i;
23 	Addr *ap;
24 	Address a;
25 
26 	if(f && f->state==Unread)
27 		load(f);
28 	if(f==0 && (cp->addr==0 || cp->addr->type!='"') &&
29 	    !utfrune("bBnqUXY!{", cp->cmdc) &&
30 	    cp->cmdc!=('c'|0x100) && !(cp->cmdc=='D' && cp->ctext))
31 		error(Enofile);
32 	i = lookup(cp->cmdc);
33 	if(cmdtab[i].defaddr != aNo){
34 		if((ap=cp->addr)==0 && cp->cmdc!='\n'){
35 			cp->addr = ap = newaddr();
36 			ap->type = '.';
37 			if(cmdtab[i].defaddr == aAll)
38 				ap->type = '*';
39 		}else if(ap && ap->type=='"' && ap->next==0 && cp->cmdc!='\n'){
40 			ap->next = newaddr();
41 			ap->next->type = '.';
42 			if(cmdtab[i].defaddr == aAll)
43 				ap->next->type = '*';
44 		}
45 		if(cp->addr){	/* may be false for '\n' (only) */
46 			static Address none = {0,0,0};
47 			if(f)
48 				addr = address(ap, f->dot, 0);
49 			else	/* a " */
50 				addr = address(ap, none, 0);
51 			f = addr.f;
52 		}
53 	}
54 	current(f);
55 	switch(cp->cmdc){
56 	case '{':
57 		a = cp->addr? address(cp->addr, f->dot, 0): f->dot;
58 		for(cp = cp->ccmd; cp; cp = cp->next){
59 			a.f->dot = a;
60 			cmdexec(a.f, cp);
61 		}
62 		break;
63 	default:
64 		i=(*cmdtab[i].fn)(f, cp);
65 		return i;
66 	}
67 	return 1;
68 }
69 
70 
71 int
72 a_cmd(File *f, Cmd *cp)
73 {
74 	return append(f, cp, addr.r.p2);
75 }
76 
77 int
78 b_cmd(File *f, Cmd *cp)
79 {
80 	USED(f);
81 	f = cp->cmdc=='b'? tofile(cp->ctext) : getfile(cp->ctext);
82 	if(f->state == Unread)
83 		load(f);
84 	else if(nest == 0)
85 		filename(f);
86 	return TRUE;
87 }
88 
89 int
90 c_cmd(File *f, Cmd *cp)
91 {
92 	Fdelete(f, addr.r.p1, addr.r.p2);
93 	f->ndot.r.p1 = f->ndot.r.p2 = addr.r.p2;
94 	return append(f, cp, addr.r.p2);
95 }
96 
97 int
98 d_cmd(File *f, Cmd *cp)
99 {
100 	USED(cp);
101 	Fdelete(f, addr.r.p1, addr.r.p2);
102 	f->ndot.r.p1 = f->ndot.r.p2 = addr.r.p1;
103 	return TRUE;
104 }
105 
106 int
107 D_cmd(File *f, Cmd *cp)
108 {
109 	closefiles(f, cp->ctext);
110 	return TRUE;
111 }
112 
113 int
114 e_cmd(File *f, Cmd *cp)
115 {
116 	if(getname(f, cp->ctext, cp->cmdc=='e')==0)
117 		error(Enoname);
118 	edit(f, cp->cmdc);
119 	return TRUE;
120 }
121 
122 int
123 f_cmd(File *f, Cmd *cp)
124 {
125 	getname(f, cp->ctext, TRUE);
126 	filename(f);
127 	return TRUE;
128 }
129 
130 int
131 g_cmd(File *f, Cmd *cp)
132 {
133 	if(f!=addr.f)panic("g_cmd f!=addr.f");
134 	compile(cp->re);
135 	if(execute(f, addr.r.p1, addr.r.p2) ^ cp->cmdc=='v'){
136 		f->dot = addr;
137 		return cmdexec(f, cp->ccmd);
138 	}
139 	return TRUE;
140 }
141 
142 int
143 i_cmd(File *f, Cmd *cp)
144 {
145 	return append(f, cp, addr.r.p1);
146 }
147 
148 int
149 k_cmd(File *f, Cmd *cp)
150 {
151 	USED(cp);
152 	f->mark = addr.r;
153 	return TRUE;
154 }
155 
156 int
157 m_cmd(File *f, Cmd *cp)
158 {
159 	Address addr2;
160 
161 	addr2 = address(cp->caddr, f->dot, 0);
162 	if(cp->cmdc=='m')
163 		move(f, addr2);
164 	else
165 		copy(f, addr2);
166 	return TRUE;
167 }
168 
169 int
170 n_cmd(File *f, Cmd *cp)
171 {
172 	int i;
173 	USED(f);
174 	USED(cp);
175 	for(i = 0; i<file.nused; i++){
176 		if(file.filepptr[i] == cmd)
177 			continue;
178 		f = file.filepptr[i];
179 		Strduplstr(&genstr, &f->name);
180 		filename(f);
181 	}
182 	return TRUE;
183 }
184 
185 int
186 p_cmd(File *f, Cmd *cp)
187 {
188 	USED(cp);
189 	return display(f);
190 }
191 
192 int
193 q_cmd(File *f, Cmd *cp)
194 {
195 	USED(cp);
196 	USED(f);
197 	trytoquit();
198 	if(downloaded){
199 		outT0(Hexit);
200 		return TRUE;
201 	}
202 	return FALSE;
203 }
204 
205 int
206 s_cmd(File *f, Cmd *cp)
207 {
208 	int i, j, c, n;
209 	Posn p1, op, didsub = 0, delta = 0;
210 
211 	n = cp->num;
212 	op= -1;
213 	compile(cp->re);
214 	for(p1 = addr.r.p1; p1<=addr.r.p2 && execute(f, p1, addr.r.p2); ){
215 		if(sel.p[0].p1==sel.p[0].p2){	/* empty match? */
216 			if(sel.p[0].p1==op){
217 				p1++;
218 				continue;
219 			}
220 			p1 = sel.p[0].p2+1;
221 		}else
222 			p1 = sel.p[0].p2;
223 		op = sel.p[0].p2;
224 		if(--n>0)
225 			continue;
226 		Strzero(&genstr);
227 		for(i = 0; i<cp->ctext->n; i++)
228 			if((c = cp->ctext->s[i])=='\\' && i<cp->ctext->n-1){
229 				c = cp->ctext->s[++i];
230 				if('1'<=c && c<='9') {
231 					j = c-'0';
232 					if(sel.p[j].p2-sel.p[j].p1>BLOCKSIZE)
233 						error(Elongtag);
234 					Fchars(f, genbuf, sel.p[j].p1, sel.p[j].p2);
235 					Strinsert(&genstr, tmprstr(genbuf, (sel.p[j].p2-sel.p[j].p1)), genstr.n);
236 				}else
237 				 	Straddc(&genstr, c);
238 			}else if(c!='&')
239 				Straddc(&genstr, c);
240 			else{
241 				if(sel.p[0].p2-sel.p[0].p1>BLOCKSIZE)
242 					error(Elongrhs);
243 				Fchars(f, genbuf, sel.p[0].p1, sel.p[0].p2);
244 				Strinsert(&genstr,
245 					tmprstr(genbuf, (int)(sel.p[0].p2-sel.p[0].p1)),
246 					genstr.n);
247 			}
248 		if(sel.p[0].p1!=sel.p[0].p2){
249 			Fdelete(f, sel.p[0].p1, sel.p[0].p2);
250 			delta-=sel.p[0].p2-sel.p[0].p1;
251 		}
252 		if(genstr.n){
253 			Finsert(f, &genstr, sel.p[0].p2);
254 			delta+=genstr.n;
255 		}
256 		didsub = 1;
257 		if(!cp->flag)
258 			break;
259 	}
260 	if(!didsub && nest==0)
261 		error(Enosub);
262 	f->ndot.r.p1 = addr.r.p1, f->ndot.r.p2 = addr.r.p2+delta;
263 	return TRUE;
264 }
265 
266 int
267 u_cmd(File *f, Cmd *cp)
268 {
269 	int n;
270 	USED(f);
271 	USED(cp);
272 	n = cp->num;
273 	while(n-- && undo())
274 		;
275 	return TRUE;
276 }
277 
278 int
279 w_cmd(File *f, Cmd *cp)
280 {
281 	if(getname(f, cp->ctext, FALSE)==0)
282 		error(Enoname);
283 	writef(f);
284 	return TRUE;
285 }
286 
287 int
288 x_cmd(File *f, Cmd *cp)
289 {
290 	if(cp->re)
291 		looper(f, cp, cp->cmdc=='x');
292 	else
293 		linelooper(f, cp);
294 	return TRUE;
295 }
296 
297 int
298 X_cmd(File *f, Cmd *cp)
299 {
300 	USED(f);
301 	filelooper(cp, cp->cmdc=='X');
302 	return TRUE;
303 }
304 
305 int
306 plan9_cmd(File *f, Cmd *cp)
307 {
308 	plan9(f, cp->cmdc, cp->ctext, nest);
309 	return TRUE;
310 }
311 
312 int
313 eq_cmd(File *f, Cmd *cp)
314 {
315 	int charsonly;
316 
317 	switch(cp->ctext->n){
318 	case 1:
319 		charsonly = FALSE;
320 		break;
321 	case 2:
322 		if(cp->ctext->s[0]=='#'){
323 			charsonly = TRUE;
324 			break;
325 		}
326 	default:
327 		SET(charsonly);
328 		error(Enewline);
329 	}
330 	printposn(f, charsonly);
331 	return TRUE;
332 }
333 
334 int
335 nl_cmd(File *f, Cmd *cp)
336 {
337 	if(cp->addr == 0){
338 		/* First put it on newline boundaries */
339 		addr = lineaddr((Posn)0, f->dot, -1);
340 		addr.r.p2 = lineaddr((Posn)0, f->dot, 1).r.p2;
341 		if(addr.r.p1==f->dot.r.p1 && addr.r.p2==f->dot.r.p2)
342 			addr = lineaddr((Posn)1, f->dot, 1);
343 		display(f);
344 	}else if(downloaded)
345 		moveto(f, addr.r);
346 	else
347 		display(f);
348 	return TRUE;
349 }
350 
351 int
352 cd_cmd(File *f, Cmd *cp)
353 {
354 	USED(f);
355 	cd(cp->ctext);
356 	return TRUE;
357 }
358 
359 int
360 append(File *f, Cmd *cp, Posn p)
361 {
362 	if(cp->ctext->n>0 && cp->ctext->s[cp->ctext->n-1]==0)
363 		--cp->ctext->n;
364 	if(cp->ctext->n>0)
365 		Finsert(f, cp->ctext, p);
366 	f->ndot.r.p1 = p;
367 	f->ndot.r.p2 = p+cp->ctext->n;
368 	return TRUE;
369 }
370 
371 int
372 display(File *f)
373 {
374 	Posn p1, p2;
375 	int np, n;
376 	char *c;
377 
378 	p1 = addr.r.p1;
379 	p2 = addr.r.p2;
380 	while(p1 < p2){
381 		np = p2-p1;
382 		if(np>BLOCKSIZE-1)
383 			np = BLOCKSIZE-1;
384 		n = Fchars(f, genbuf, p1, p1+np);
385 		if(n <= 0)
386 			panic("display");
387 		genbuf[n] = 0;
388 		c = Strtoc(tmprstr(genbuf, n+1));
389 		if(downloaded)
390 			termwrite(c);
391 		else
392 			Write(1, c, strlen(c));
393 		free(c);
394 		p1+=n;
395 	}
396 	f->dot = addr;
397 	return TRUE;
398 }
399 
400 void
401 looper(File *f, Cmd *cp, int xy)
402 {
403 	Posn p, op;
404 	Range r;
405 
406 	r = addr.r;
407 	op= xy? -1 : r.p1;
408 	nest++;
409 	compile(cp->re);
410 	for(p = r.p1; p<=r.p2; ){
411 		if(!execute(f, p, r.p2)){ /* no match, but y should still run */
412 			if(xy || op>r.p2)
413 				break;
414 			f->dot.r.p1 = op, f->dot.r.p2 = r.p2;
415 			p = r.p2+1;	/* exit next loop */
416 		}else{
417 			if(sel.p[0].p1==sel.p[0].p2){	/* empty match? */
418 				if(sel.p[0].p1==op){
419 					p++;
420 					continue;
421 				}
422 				p = sel.p[0].p2+1;
423 			}else
424 				p = sel.p[0].p2;
425 			if(xy)
426 				f->dot.r = sel.p[0];
427 			else
428 				f->dot.r.p1 = op, f->dot.r.p2 = sel.p[0].p1;
429 		}
430 		op = sel.p[0].p2;
431 		cmdexec(f, cp->ccmd);
432 		compile(cp->re);
433 	}
434 	--nest;
435 }
436 
437 void
438 linelooper(File *f, Cmd *cp)
439 {
440 	Posn p;
441 	Range r, linesel;
442 	Address a3;
443 
444 	nest++;
445 	r = addr.r;
446 	a3.f = f;
447 	a3.r.p1 = a3.r.p2 = r.p1;
448 	for(p = r.p1; p<r.p2; p = a3.r.p2){
449 		a3.r.p1 = a3.r.p2;
450 /*pjw		if(p!=r.p1 || (linesel = lineaddr((Posn)0, a3, 1)).r.p2==p)*/
451 		if(p!=r.p1 || ((linesel = lineaddr((Posn)0, a3, 1).r), linesel.p2==p))
452 			linesel = lineaddr((Posn)1, a3, 1).r;
453 		if(linesel.p1 >= r.p2)
454 			break;
455 		if(linesel.p2 >= r.p2)
456 			linesel.p2 = r.p2;
457 		if(linesel.p2 > linesel.p1)
458 			if(linesel.p1>=a3.r.p2 && linesel.p2>a3.r.p2){
459 				f->dot.r = linesel;
460 				cmdexec(f, cp->ccmd);
461 				a3.r = linesel;
462 				continue;
463 			}
464 		break;
465 	}
466 	--nest;
467 }
468 
469 void
470 filelooper(Cmd *cp, int XY)
471 {
472 	File *f, *cur;
473 	int i;
474 
475 	if(Glooping++)
476 		error(EnestXY);
477 	nest++;
478 	settempfile();
479 	cur = curfile;
480 	for(i = 0; i<tempfile.nused; i++){
481 		f = tempfile.filepptr[i];
482 		if(f==cmd)
483 			continue;
484 		if(cp->re==0 || filematch(f, cp->re)==XY)
485 			cmdexec(f, cp->ccmd);
486 	}
487 	if(cur && whichmenu(cur)>=0)	/* check that cur is still a file */
488 		current(cur);
489 	--Glooping;
490 	--nest;
491 }
492