Blob


1 #include "sam.h"
2 #include "parse.h"
4 int Glooping;
5 int nest;
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*);
13 void
14 resetxec(void)
15 {
16 Glooping = nest = 0;
17 }
19 int
20 cmdexec(File *f, Cmd *cp)
21 {
22 int i;
23 Addr *ap;
24 Address a;
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 }
71 int
72 a_cmd(File *f, Cmd *cp)
73 {
74 return append(f, cp, addr.r.p2);
75 }
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->unread)
83 load(f);
84 else if(nest == 0)
85 filename(f);
86 return TRUE;
87 }
89 int
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 }
97 int
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;
106 int
107 D_cmd(File *f, Cmd *cp)
109 closefiles(f, cp->ctext);
110 return TRUE;
113 int
114 e_cmd(File *f, Cmd *cp)
116 if(getname(f, cp->ctext, cp->cmdc=='e')==0)
117 error(Enoname);
118 edit(f, cp->cmdc);
119 return TRUE;
122 int
123 f_cmd(File *f, Cmd *cp)
125 getname(f, cp->ctext, TRUE);
126 filename(f);
127 return TRUE;
130 int
131 g_cmd(File *f, Cmd *cp)
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);
139 return TRUE;
142 int
143 i_cmd(File *f, Cmd *cp)
145 return append(f, cp, addr.r.p1);
148 int
149 k_cmd(File *f, Cmd *cp)
151 USED(cp);
152 f->mark = addr.r;
153 return TRUE;
156 int
157 m_cmd(File *f, Cmd *cp)
159 Address addr2;
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;
169 int
170 n_cmd(File *f, Cmd *cp)
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);
182 return TRUE;
185 int
186 p_cmd(File *f, Cmd *cp)
188 USED(cp);
189 return display(f);
192 int
193 q_cmd(File *f, Cmd *cp)
195 USED(cp);
196 USED(f);
197 trytoquit();
198 if(downloaded){
199 outT0(Hexit);
200 return TRUE;
202 return FALSE;
205 int
206 s_cmd(File *f, Cmd *cp)
208 int i, j, c, n;
209 Posn p1, op, didsub = 0, delta = 0;
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;
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);
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;
252 if(genstr.n){
253 loginsert(f, sel.p[0].p2, genstr.s, genstr.n);
254 delta+=genstr.n;
256 didsub = 1;
257 if(!cp->flag)
258 break;
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;
266 int
267 u_cmd(File *f, Cmd *cp)
269 int n;
271 USED(f);
272 USED(cp);
273 n = cp->num;
274 if(n >= 0)
275 while(n-- && undo(TRUE))
277 else
278 while(n++ && undo(FALSE))
280 return TRUE;
283 int
284 w_cmd(File *f, Cmd *cp)
286 int fseq;
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;
297 int
298 x_cmd(File *f, Cmd *cp)
300 if(cp->re)
301 looper(f, cp, cp->cmdc=='x');
302 else
303 linelooper(f, cp);
304 return TRUE;
307 int
308 X_cmd(File *f, Cmd *cp)
310 USED(f);
311 filelooper(cp, cp->cmdc=='X');
312 return TRUE;
315 int
316 plan9_cmd(File *f, Cmd *cp)
318 plan9(f, cp->cmdc, cp->ctext, nest);
319 return TRUE;
322 int
323 eq_cmd(File *f, Cmd *cp)
325 int charsonly;
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;
336 default:
337 SET(charsonly);
338 error(Enewline);
340 printposn(f, charsonly);
341 return TRUE;
344 int
345 nl_cmd(File *f, Cmd *cp)
347 Address a;
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;
364 int
365 cd_cmd(File *f, Cmd *cp)
367 USED(f);
368 cd(cp->ctext);
369 return TRUE;
372 int
373 append(File *f, Cmd *cp, Posn p)
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;
384 int
385 display(File *f)
387 Posn p1, p2;
388 int np;
389 char *c;
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;
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;
411 f->dot = addr;
412 return TRUE;
415 void
416 looper(File *f, Cmd *cp, int xy)
418 Posn p, op;
419 Range r;
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;
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;
445 op = sel.p[0].p2;
446 cmdexec(f, cp->ccmd);
447 compile(cp->re);
449 --nest;
452 void
453 linelooper(File *f, Cmd *cp)
455 Posn p;
456 Range r, linesel;
457 Address a, a3;
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;
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;
481 break;
483 --nest;
486 void
487 filelooper(Cmd *cp, int XY)
489 File *f, *cur;
490 int i;
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);
504 if(cur && whichmenu(cur)>=0) /* check that cur is still a file */
505 current(cur);
506 --Glooping;
507 --nest;