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
resetxec(void)14 resetxec(void)
15 {
16 	Glooping = nest = 0;
17 }
18 
19 int
cmdexec(File * f,Cmd * cp)20 cmdexec(File *f, Cmd *cp)
21 {
22 	int i;
23 	Addr *ap;
24 	Address a;
25 
26 	if(f && f->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(i >= 0 && 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
a_cmd(File * f,Cmd * cp)72 a_cmd(File *f, Cmd *cp)
73 {
74 	return append(f, cp, addr.r.p2);
75 }
76 
77 int
b_cmd(File * f,Cmd * cp)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->unread)
83 		load(f);
84 	else if(nest == 0)
85 		filename(f);
86 	return TRUE;
87 }
88 
89 int
c_cmd(File * f,Cmd * cp)90 c_cmd(File *f, Cmd *cp)
91 {
92 	logdelete(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
d_cmd(File * f,Cmd * cp)98 d_cmd(File *f, Cmd *cp)
99 {
100 	USED(cp);
101 	logdelete(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
D_cmd(File * f,Cmd * cp)107 D_cmd(File *f, Cmd *cp)
108 {
109 	closefiles(f, cp->ctext);
110 	return TRUE;
111 }
112 
113 int
e_cmd(File * f,Cmd * cp)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
f_cmd(File * f,Cmd * cp)123 f_cmd(File *f, Cmd *cp)
124 {
125 	getname(f, cp->ctext, TRUE);
126 	filename(f);
127 	return TRUE;
128 }
129 
130 int
g_cmd(File * f,Cmd * cp)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
i_cmd(File * f,Cmd * cp)143 i_cmd(File *f, Cmd *cp)
144 {
145 	return append(f, cp, addr.r.p1);
146 }
147 
148 int
k_cmd(File * f,Cmd * cp)149 k_cmd(File *f, Cmd *cp)
150 {
151 	USED(cp);
152 	f->mark = addr.r;
153 	return TRUE;
154 }
155 
156 int
m_cmd(File * f,Cmd * cp)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
n_cmd(File * f,Cmd * cp)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
p_cmd(File * f,Cmd * cp)186 p_cmd(File *f, Cmd *cp)
187 {
188 	USED(cp);
189 	return display(f);
190 }
191 
192 int
q_cmd(File * f,Cmd * cp)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
s_cmd(File * f,Cmd * cp)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 					bufread(&f->b, sel.p[j].p1, genbuf, sel.p[j].p2-sel.p[j].p1);
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 				bufread(&f->b, sel.p[0].p1, genbuf, sel.p[0].p2-sel.p[0].p1);
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 			logdelete(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 			loginsert(f, sel.p[0].p2, genstr.s, genstr.n);
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
u_cmd(File * f,Cmd * cp)267 u_cmd(File *f, Cmd *cp)
268 {
269 	int n;
270 
271 	USED(f);
272 	USED(cp);
273 	n = cp->num;
274 	if(n >= 0)
275 		while(n-- && undo(TRUE))
276 			;
277 	else
278 		while(n++ && undo(FALSE))
279 			;
280 	return TRUE;
281 }
282 
283 int
w_cmd(File * f,Cmd * cp)284 w_cmd(File *f, Cmd *cp)
285 {
286 	int fseq;
287 
288 	fseq = f->seq;
289 	if(getname(f, cp->ctext, FALSE)==0)
290 		error(Enoname);
291 	if(fseq == seq)
292 		error_s(Ewseq, genc);
293 	writef(f);
294 	return TRUE;
295 }
296 
297 int
x_cmd(File * f,Cmd * cp)298 x_cmd(File *f, Cmd *cp)
299 {
300 	if(cp->re)
301 		looper(f, cp, cp->cmdc=='x');
302 	else
303 		linelooper(f, cp);
304 	return TRUE;
305 }
306 
307 int
X_cmd(File * f,Cmd * cp)308 X_cmd(File *f, Cmd *cp)
309 {
310 	USED(f);
311 	filelooper(cp, cp->cmdc=='X');
312 	return TRUE;
313 }
314 
315 int
plan9_cmd(File * f,Cmd * cp)316 plan9_cmd(File *f, Cmd *cp)
317 {
318 	plan9(f, cp->cmdc, cp->ctext, nest);
319 	return TRUE;
320 }
321 
322 int
eq_cmd(File * f,Cmd * cp)323 eq_cmd(File *f, Cmd *cp)
324 {
325 	int charsonly;
326 
327 	switch(cp->ctext->n){
328 	case 1:
329 		charsonly = FALSE;
330 		break;
331 	case 2:
332 		if(cp->ctext->s[0]=='#'){
333 			charsonly = TRUE;
334 			break;
335 		}
336 	default:
337 		SET(charsonly);
338 		error(Enewline);
339 	}
340 	printposn(f, charsonly);
341 	return TRUE;
342 }
343 
344 int
nl_cmd(File * f,Cmd * cp)345 nl_cmd(File *f, Cmd *cp)
346 {
347 	Address a;
348 
349 	if(cp->addr == 0){
350 		/* First put it on newline boundaries */
351 		addr = lineaddr((Posn)0, f->dot, -1);
352 		a = lineaddr((Posn)0, f->dot, 1);
353 		addr.r.p2 = a.r.p2;
354 		if(addr.r.p1==f->dot.r.p1 && addr.r.p2==f->dot.r.p2)
355 			addr = lineaddr((Posn)1, f->dot, 1);
356 		display(f);
357 	}else if(downloaded)
358 		moveto(f, addr.r);
359 	else
360 		display(f);
361 	return TRUE;
362 }
363 
364 int
cd_cmd(File * f,Cmd * cp)365 cd_cmd(File *f, Cmd *cp)
366 {
367 	USED(f);
368 	cd(cp->ctext);
369 	return TRUE;
370 }
371 
372 int
append(File * f,Cmd * cp,Posn p)373 append(File *f, Cmd *cp, Posn p)
374 {
375 	if(cp->ctext->n>0 && cp->ctext->s[cp->ctext->n-1]==0)
376 		--cp->ctext->n;
377 	if(cp->ctext->n>0)
378 		loginsert(f, p, cp->ctext->s, cp->ctext->n);
379 	f->ndot.r.p1 = p;
380 	f->ndot.r.p2 = p+cp->ctext->n;
381 	return TRUE;
382 }
383 
384 int
display(File * f)385 display(File *f)
386 {
387 	Posn p1, p2;
388 	int np;
389 	char *c;
390 
391 	p1 = addr.r.p1;
392 	p2 = addr.r.p2;
393 	if(p2 > f->b.nc){
394 		fprint(2, "bad display addr p1=%ld p2=%ld f->b.nc=%d\n", p1, p2, f->b.nc); /*ZZZ should never happen, can remove */
395 		p2 = f->b.nc;
396 	}
397 	while(p1 < p2){
398 		np = p2-p1;
399 		if(np>BLOCKSIZE-1)
400 			np = BLOCKSIZE-1;
401 		bufread(&f->b, p1, genbuf, np);
402 		genbuf[np] = 0;
403 		c = Strtoc(tmprstr(genbuf, np+1));
404 		if(downloaded)
405 			termwrite(c);
406 		else
407 			Write(1, c, strlen(c));
408 		free(c);
409 		p1 += np;
410 	}
411 	f->dot = addr;
412 	return TRUE;
413 }
414 
415 void
looper(File * f,Cmd * cp,int xy)416 looper(File *f, Cmd *cp, int xy)
417 {
418 	Posn p, op;
419 	Range r;
420 
421 	r = addr.r;
422 	op= xy? -1 : r.p1;
423 	nest++;
424 	compile(cp->re);
425 	for(p = r.p1; p<=r.p2; ){
426 		if(!execute(f, p, r.p2)){ /* no match, but y should still run */
427 			if(xy || op>r.p2)
428 				break;
429 			f->dot.r.p1 = op, f->dot.r.p2 = r.p2;
430 			p = r.p2+1;	/* exit next loop */
431 		}else{
432 			if(sel.p[0].p1==sel.p[0].p2){	/* empty match? */
433 				if(sel.p[0].p1==op){
434 					p++;
435 					continue;
436 				}
437 				p = sel.p[0].p2+1;
438 			}else
439 				p = sel.p[0].p2;
440 			if(xy)
441 				f->dot.r = sel.p[0];
442 			else
443 				f->dot.r.p1 = op, f->dot.r.p2 = sel.p[0].p1;
444 		}
445 		op = sel.p[0].p2;
446 		cmdexec(f, cp->ccmd);
447 		compile(cp->re);
448 	}
449 	--nest;
450 }
451 
452 void
linelooper(File * f,Cmd * cp)453 linelooper(File *f, Cmd *cp)
454 {
455 	Posn p;
456 	Range r, linesel;
457 	Address a, a3;
458 
459 	nest++;
460 	r = addr.r;
461 	a3.f = f;
462 	a3.r.p1 = a3.r.p2 = r.p1;
463 	for(p = r.p1; p<r.p2; p = a3.r.p2){
464 		a3.r.p1 = a3.r.p2;
465 /*pjw		if(p!=r.p1 || (linesel = lineaddr((Posn)0, a3, 1)).r.p2==p)*/
466 		if(p!=r.p1 || (a = lineaddr((Posn)0, a3, 1), linesel = a.r, linesel.p2==p)){
467 			a = lineaddr((Posn)1, a3, 1);
468 			linesel = a.r;
469 		}
470 		if(linesel.p1 >= r.p2)
471 			break;
472 		if(linesel.p2 >= r.p2)
473 			linesel.p2 = r.p2;
474 		if(linesel.p2 > linesel.p1)
475 			if(linesel.p1>=a3.r.p2 && linesel.p2>a3.r.p2){
476 				f->dot.r = linesel;
477 				cmdexec(f, cp->ccmd);
478 				a3.r = linesel;
479 				continue;
480 			}
481 		break;
482 	}
483 	--nest;
484 }
485 
486 void
filelooper(Cmd * cp,int XY)487 filelooper(Cmd *cp, int XY)
488 {
489 	File *f, *cur;
490 	int i;
491 
492 	if(Glooping++)
493 		error(EnestXY);
494 	nest++;
495 	settempfile();
496 	cur = curfile;
497 	for(i = 0; i<tempfile.nused; i++){
498 		f = tempfile.filepptr[i];
499 		if(f==cmd)
500 			continue;
501 		if(cp->re==0 || filematch(f, cp->re)==XY)
502 			cmdexec(f, cp->ccmd);
503 	}
504 	if(cur && whichmenu(cur)>=0)	/* check that cur is still a file */
505 		current(cur);
506 	--Glooping;
507 	--nest;
508 }
509