xec.c (8529B)
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->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 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->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 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 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 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 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 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 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 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 308 X_cmd(File *f, Cmd *cp) 309 { 310 USED(f); 311 filelooper(cp, cp->cmdc=='X'); 312 return TRUE; 313 } 314 315 int 316 plan9_cmd(File *f, Cmd *cp) 317 { 318 plan9(f, cp->cmdc, cp->ctext, nest); 319 return TRUE; 320 } 321 322 int 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 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 365 cd_cmd(File *f, Cmd *cp) 366 { 367 USED(f); 368 cd(cp->ctext); 369 return TRUE; 370 } 371 372 int 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 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 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 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 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 }