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