| xec.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
| git clone git://git.suckless.org/9base | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| 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!… | |
| 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… | |
| 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>BLOCK… | |
| 233 error(Elongtag); | |
| 234 bufread(&f->b, sel.p[j].p1, genb… | |
| 235 Strinsert(&genstr, tmprstr(genbu… | |
| 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.… | |
| 244 Strinsert(&genstr, | |
| 245 tmprstr(genbuf, (int)(sel.p[0].p… | |
| 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",… | |
| 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 stil… | |
| 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 ma… | |
| 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]… | |
| 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)).… | |
| 466 if(p!=r.p1 || (a = lineaddr((Posn)0, a3, 1), linesel = a… | |
| 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… | |
| 505 current(cur); | |
| 506 --Glooping; | |
| 507 --nest; | |
| 508 } |