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