xec.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "sam.h"
  10. #include "parse.h"
  11. int Glooping;
  12. int nest;
  13. int append(File*, Cmd*, Posn);
  14. int display(File*);
  15. void looper(File*, Cmd*, int);
  16. void filelooper(Cmd*, int);
  17. void linelooper(File*, Cmd*);
  18. void
  19. resetxec(void)
  20. {
  21. Glooping = nest = 0;
  22. }
  23. int
  24. cmdexec(File *f, Cmd *cp)
  25. {
  26. int i;
  27. Addr *ap;
  28. Address a;
  29. if(f && f->unread)
  30. load(f);
  31. if(f==0 && (cp->addr==0 || cp->addr->type!='"') &&
  32. !utfrune("bBnqUXY!", cp->cmdc) &&
  33. cp->cmdc!=('c'|0x100) && !(cp->cmdc=='D' && cp->ctext))
  34. error(Enofile);
  35. i = lookup(cp->cmdc);
  36. if(i >= 0 && cmdtab[i].defaddr != aNo){
  37. if((ap=cp->addr)==0 && cp->cmdc!='\n'){
  38. cp->addr = ap = newaddr();
  39. ap->type = '.';
  40. if(cmdtab[i].defaddr == aAll)
  41. ap->type = '*';
  42. }else if(ap && ap->type=='"' && ap->next==0 && cp->cmdc!='\n'){
  43. ap->next = newaddr();
  44. ap->next->type = '.';
  45. if(cmdtab[i].defaddr == aAll)
  46. ap->next->type = '*';
  47. }
  48. if(cp->addr){ /* may be false for '\n' (only) */
  49. static Address none = {0,0,0};
  50. if(f)
  51. addr = address(ap, f->dot, 0);
  52. else /* a " */
  53. addr = address(ap, none, 0);
  54. f = addr.f;
  55. }
  56. }
  57. current(f);
  58. switch(cp->cmdc){
  59. case '{':
  60. a = cp->addr? address(cp->addr, f->dot, 0): f->dot;
  61. for(cp = cp->ccmd; cp; cp = cp->next){
  62. a.f->dot = a;
  63. cmdexec(a.f, cp);
  64. }
  65. break;
  66. default:
  67. i=(*cmdtab[i].fn)(f, cp);
  68. return i;
  69. }
  70. return 1;
  71. }
  72. int
  73. a_cmd(File *f, Cmd *cp)
  74. {
  75. return append(f, cp, addr.r.p2);
  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. int
  89. c_cmd(File *f, Cmd *cp)
  90. {
  91. logdelete(f, addr.r.p1, addr.r.p2);
  92. f->ndot.r.p1 = f->ndot.r.p2 = addr.r.p2;
  93. return append(f, cp, addr.r.p2);
  94. }
  95. int
  96. d_cmd(File *f, Cmd *cp)
  97. {
  98. USED(cp);
  99. logdelete(f, addr.r.p1, addr.r.p2);
  100. f->ndot.r.p1 = f->ndot.r.p2 = addr.r.p1;
  101. return TRUE;
  102. }
  103. int
  104. D_cmd(File *f, Cmd *cp)
  105. {
  106. closefiles(f, cp->ctext);
  107. return TRUE;
  108. }
  109. int
  110. e_cmd(File *f, Cmd *cp)
  111. {
  112. if(getname(f, cp->ctext, cp->cmdc=='e')==0)
  113. error(Enoname);
  114. edit(f, cp->cmdc);
  115. return TRUE;
  116. }
  117. int
  118. f_cmd(File *f, Cmd *cp)
  119. {
  120. getname(f, cp->ctext, TRUE);
  121. filename(f);
  122. return TRUE;
  123. }
  124. int
  125. g_cmd(File *f, Cmd *cp)
  126. {
  127. if(f!=addr.f)panic("g_cmd f!=addr.f");
  128. compile(cp->re);
  129. if(execute(f, addr.r.p1, addr.r.p2) ^ cp->cmdc=='v'){
  130. f->dot = addr;
  131. return cmdexec(f, cp->ccmd);
  132. }
  133. return TRUE;
  134. }
  135. int
  136. i_cmd(File *f, Cmd *cp)
  137. {
  138. return append(f, cp, addr.r.p1);
  139. }
  140. int
  141. k_cmd(File *f, Cmd *cp)
  142. {
  143. USED(cp);
  144. f->mark = addr.r;
  145. return TRUE;
  146. }
  147. int
  148. m_cmd(File *f, Cmd *cp)
  149. {
  150. Address addr2;
  151. addr2 = address(cp->caddr, f->dot, 0);
  152. if(cp->cmdc=='m')
  153. move(f, addr2);
  154. else
  155. copy(f, addr2);
  156. return TRUE;
  157. }
  158. int
  159. n_cmd(File *f, Cmd *cp)
  160. {
  161. int i;
  162. USED(f);
  163. USED(cp);
  164. for(i = 0; i<file.nused; i++){
  165. if(file.filepptr[i] == cmd)
  166. continue;
  167. f = file.filepptr[i];
  168. Strduplstr(&genstr, &f->name);
  169. filename(f);
  170. }
  171. return TRUE;
  172. }
  173. int
  174. p_cmd(File *f, Cmd *cp)
  175. {
  176. USED(cp);
  177. return display(f);
  178. }
  179. int
  180. q_cmd(File *f, Cmd *cp)
  181. {
  182. USED(cp);
  183. USED(f);
  184. trytoquit();
  185. if(downloaded){
  186. outT0(Hexit);
  187. return TRUE;
  188. }
  189. return FALSE;
  190. }
  191. int
  192. s_cmd(File *f, Cmd *cp)
  193. {
  194. int i, j, c, n;
  195. Posn p1, op, didsub = 0, delta = 0;
  196. n = cp->num;
  197. op= -1;
  198. compile(cp->re);
  199. for(p1 = addr.r.p1; p1<=addr.r.p2 && execute(f, p1, addr.r.p2); ){
  200. if(sel.p[0].p1==sel.p[0].p2){ /* empty match? */
  201. if(sel.p[0].p1==op){
  202. p1++;
  203. continue;
  204. }
  205. p1 = sel.p[0].p2+1;
  206. }else
  207. p1 = sel.p[0].p2;
  208. op = sel.p[0].p2;
  209. if(--n>0)
  210. continue;
  211. Strzero(&genstr);
  212. for(i = 0; i<cp->ctext->n; i++)
  213. if((c = cp->ctext->s[i])=='\\' && i<cp->ctext->n-1){
  214. c = cp->ctext->s[++i];
  215. if('1'<=c && c<='9') {
  216. j = c-'0';
  217. if(sel.p[j].p2-sel.p[j].p1>BLOCKSIZE)
  218. error(Elongtag);
  219. bufread(f, sel.p[j].p1, genbuf, sel.p[j].p2-sel.p[j].p1);
  220. Strinsert(&genstr, tmprstr(genbuf, (sel.p[j].p2-sel.p[j].p1)), genstr.n);
  221. }else
  222. Straddc(&genstr, c);
  223. }else if(c!='&')
  224. Straddc(&genstr, c);
  225. else{
  226. if(sel.p[0].p2-sel.p[0].p1>BLOCKSIZE)
  227. error(Elongrhs);
  228. bufread(f, sel.p[0].p1, genbuf, sel.p[0].p2-sel.p[0].p1);
  229. Strinsert(&genstr,
  230. tmprstr(genbuf, (int)(sel.p[0].p2-sel.p[0].p1)),
  231. genstr.n);
  232. }
  233. if(sel.p[0].p1!=sel.p[0].p2){
  234. logdelete(f, sel.p[0].p1, sel.p[0].p2);
  235. delta-=sel.p[0].p2-sel.p[0].p1;
  236. }
  237. if(genstr.n){
  238. loginsert(f, sel.p[0].p2, genstr.s, genstr.n);
  239. delta+=genstr.n;
  240. }
  241. didsub = 1;
  242. if(!cp->flag)
  243. break;
  244. }
  245. if(!didsub && nest==0)
  246. error(Enosub);
  247. f->ndot.r.p1 = addr.r.p1, f->ndot.r.p2 = addr.r.p2+delta;
  248. return TRUE;
  249. }
  250. int
  251. u_cmd(File *f, Cmd *cp)
  252. {
  253. int n;
  254. USED(f);
  255. USED(cp);
  256. n = cp->num;
  257. if(n >= 0)
  258. while(n-- && undo(TRUE))
  259. ;
  260. else
  261. while(n++ && undo(FALSE))
  262. ;
  263. return TRUE;
  264. }
  265. int
  266. w_cmd(File *f, Cmd *cp)
  267. {
  268. int fseq;
  269. fseq = f->seq;
  270. if(getname(f, cp->ctext, FALSE)==0)
  271. error(Enoname);
  272. if(fseq == seq)
  273. error_s(Ewseq, genc);
  274. writef(f);
  275. return TRUE;
  276. }
  277. int
  278. x_cmd(File *f, Cmd *cp)
  279. {
  280. if(cp->re)
  281. looper(f, cp, cp->cmdc=='x');
  282. else
  283. linelooper(f, cp);
  284. return TRUE;
  285. }
  286. int
  287. X_cmd(File *f, Cmd *cp)
  288. {
  289. USED(f);
  290. filelooper(cp, cp->cmdc=='X');
  291. return TRUE;
  292. }
  293. int
  294. plan9_cmd(File *f, Cmd *cp)
  295. {
  296. plan9(f, cp->cmdc, cp->ctext, nest);
  297. return TRUE;
  298. }
  299. int
  300. eq_cmd(File *f, Cmd *cp)
  301. {
  302. int charsonly;
  303. switch(cp->ctext->n){
  304. case 1:
  305. charsonly = FALSE;
  306. break;
  307. case 2:
  308. if(cp->ctext->s[0]=='#'){
  309. charsonly = TRUE;
  310. break;
  311. }
  312. default:
  313. SET(charsonly);
  314. error(Enewline);
  315. }
  316. printposn(f, charsonly);
  317. return TRUE;
  318. }
  319. int
  320. nl_cmd(File *f, Cmd *cp)
  321. {
  322. Address a;
  323. if(cp->addr == 0){
  324. /* First put it on newline boundaries */
  325. addr = lineaddr((Posn)0, f->dot, -1);
  326. a = lineaddr((Posn)0, f->dot, 1);
  327. addr.r.p2 = a.r.p2;
  328. if(addr.r.p1==f->dot.r.p1 && addr.r.p2==f->dot.r.p2)
  329. addr = lineaddr((Posn)1, f->dot, 1);
  330. display(f);
  331. }else if(downloaded)
  332. moveto(f, addr.r);
  333. else
  334. display(f);
  335. return TRUE;
  336. }
  337. int
  338. cd_cmd(File *f, Cmd *cp)
  339. {
  340. USED(f);
  341. cd(cp->ctext);
  342. return TRUE;
  343. }
  344. int
  345. append(File *f, Cmd *cp, Posn p)
  346. {
  347. if(cp->ctext->n>0 && cp->ctext->s[cp->ctext->n-1]==0)
  348. --cp->ctext->n;
  349. if(cp->ctext->n>0)
  350. loginsert(f, p, cp->ctext->s, cp->ctext->n);
  351. f->ndot.r.p1 = p;
  352. f->ndot.r.p2 = p+cp->ctext->n;
  353. return TRUE;
  354. }
  355. int
  356. display(File *f)
  357. {
  358. Posn p1, p2;
  359. int np;
  360. char *c;
  361. p1 = addr.r.p1;
  362. p2 = addr.r.p2;
  363. if(p2 > f->nc){
  364. fprint(2, "bad display addr p1=%ld p2=%ld f->nc=%d\n", p1, p2, f->nc); /*ZZZ should never happen, can remove */
  365. p2 = f->nc;
  366. }
  367. while(p1 < p2){
  368. np = p2-p1;
  369. if(np>BLOCKSIZE-1)
  370. np = BLOCKSIZE-1;
  371. bufread(f, p1, genbuf, np);
  372. genbuf[np] = 0;
  373. c = Strtoc(tmprstr(genbuf, np+1));
  374. if(downloaded)
  375. termwrite(c);
  376. else
  377. Write(1, c, strlen(c));
  378. free(c);
  379. p1 += np;
  380. }
  381. f->dot = addr;
  382. return TRUE;
  383. }
  384. void
  385. looper(File *f, Cmd *cp, int xy)
  386. {
  387. Posn p, op;
  388. Range r;
  389. r = addr.r;
  390. op= xy? -1 : r.p1;
  391. nest++;
  392. compile(cp->re);
  393. for(p = r.p1; p<=r.p2; ){
  394. if(!execute(f, p, r.p2)){ /* no match, but y should still run */
  395. if(xy || op>r.p2)
  396. break;
  397. f->dot.r.p1 = op, f->dot.r.p2 = r.p2;
  398. p = r.p2+1; /* exit next loop */
  399. }else{
  400. if(sel.p[0].p1==sel.p[0].p2){ /* empty match? */
  401. if(sel.p[0].p1==op){
  402. p++;
  403. continue;
  404. }
  405. p = sel.p[0].p2+1;
  406. }else
  407. p = sel.p[0].p2;
  408. if(xy)
  409. f->dot.r = sel.p[0];
  410. else
  411. f->dot.r.p1 = op, f->dot.r.p2 = sel.p[0].p1;
  412. }
  413. op = sel.p[0].p2;
  414. cmdexec(f, cp->ccmd);
  415. compile(cp->re);
  416. }
  417. --nest;
  418. }
  419. void
  420. linelooper(File *f, Cmd *cp)
  421. {
  422. Posn p;
  423. Range r, linesel;
  424. Address a, a3;
  425. nest++;
  426. r = addr.r;
  427. a3.f = f;
  428. a3.r.p1 = a3.r.p2 = r.p1;
  429. for(p = r.p1; p<r.p2; p = a3.r.p2){
  430. a3.r.p1 = a3.r.p2;
  431. /*pjw if(p!=r.p1 || (linesel = lineaddr((Posn)0, a3, 1)).r.p2==p)*/
  432. if(p!=r.p1 || (a = lineaddr((Posn)0, a3, 1), linesel = a.r, linesel.p2==p)){
  433. a = lineaddr((Posn)1, a3, 1);
  434. linesel = a.r;
  435. }
  436. if(linesel.p1 >= r.p2)
  437. break;
  438. if(linesel.p2 >= r.p2)
  439. linesel.p2 = r.p2;
  440. if(linesel.p2 > linesel.p1)
  441. if(linesel.p1>=a3.r.p2 && linesel.p2>a3.r.p2){
  442. f->dot.r = linesel;
  443. cmdexec(f, cp->ccmd);
  444. a3.r = linesel;
  445. continue;
  446. }
  447. break;
  448. }
  449. --nest;
  450. }
  451. void
  452. filelooper(Cmd *cp, int XY)
  453. {
  454. File *f, *cur;
  455. int i;
  456. if(Glooping++)
  457. error(EnestXY);
  458. nest++;
  459. settempfile();
  460. cur = curfile;
  461. for(i = 0; i<tempfile.nused; i++){
  462. f = tempfile.filepptr[i];
  463. if(f==cmd)
  464. continue;
  465. if(cp->re==0 || filematch(f, cp->re)==XY)
  466. cmdexec(f, cp->ccmd);
  467. }
  468. if(cur && whichmenu(cur)>=0) /* check that cur is still a file */
  469. current(cur);
  470. --Glooping;
  471. --nest;
  472. }