file.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. #include "sam.h"
  2. /*
  3. * Structure of Undo list:
  4. * The Undo structure follows any associated data, so the list
  5. * can be read backwards: read the structure, then read whatever
  6. * data is associated (insert string, file name) and precedes it.
  7. * The structure includes the previous value of the modify bit
  8. * and a sequence number; successive Undo structures with the
  9. * same sequence number represent simultaneous changes.
  10. */
  11. typedef struct Undo Undo;
  12. typedef struct Merge Merge;
  13. struct Undo
  14. {
  15. short type; /* Delete, Insert, Filename, Dot, Mark */
  16. short mod; /* modify bit */
  17. uint seq; /* sequence number */
  18. uint p0; /* location of change (unused in f) */
  19. uint n; /* # runes in string or file name */
  20. };
  21. struct Merge
  22. {
  23. File *f;
  24. uint seq; /* of logged change */
  25. uint p0; /* location of change (unused in f) */
  26. uint n; /* # runes to delete */
  27. uint nbuf; /* # runes to insert */
  28. Rune buf[RBUFSIZE];
  29. };
  30. enum
  31. {
  32. Maxmerge = 50,
  33. Undosize = sizeof(Undo)/sizeof(Rune),
  34. };
  35. static Merge merge;
  36. File*
  37. fileopen(void)
  38. {
  39. File *f;
  40. f = emalloc(sizeof(File));
  41. f->dot.f = f;
  42. f->ndot.f = f;
  43. f->seq = 0;
  44. f->mod = FALSE;
  45. f->unread = TRUE;
  46. Strinit0(&f->name);
  47. return f;
  48. }
  49. int
  50. fileisdirty(File *f)
  51. {
  52. return f->seq != f->cleanseq;
  53. }
  54. static void
  55. wrinsert(Buffer *delta, int seq, int mod, uint p0, Rune *s, uint ns)
  56. {
  57. Undo u;
  58. u.type = Insert;
  59. u.mod = mod;
  60. u.seq = seq;
  61. u.p0 = p0;
  62. u.n = ns;
  63. bufinsert(delta, delta->nc, s, ns);
  64. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  65. }
  66. static void
  67. wrdelete(Buffer *delta, int seq, int mod, uint p0, uint p1)
  68. {
  69. Undo u;
  70. u.type = Delete;
  71. u.mod = mod;
  72. u.seq = seq;
  73. u.p0 = p0;
  74. u.n = p1 - p0;
  75. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  76. }
  77. void
  78. flushmerge(void)
  79. {
  80. File *f;
  81. f = merge.f;
  82. if(f == nil)
  83. return;
  84. if(merge.seq != f->seq)
  85. panic("flushmerge seq mismatch");
  86. if(merge.n != 0)
  87. wrdelete(&f->epsilon, f->seq, TRUE, merge.p0, merge.p0+merge.n);
  88. if(merge.nbuf != 0)
  89. wrinsert(&f->epsilon, f->seq, TRUE, merge.p0+merge.n, merge.buf, merge.nbuf);
  90. merge.f = nil;
  91. merge.n = 0;
  92. merge.nbuf = 0;
  93. }
  94. void
  95. mergeextend(File *f, uint p0)
  96. {
  97. uint mp0n;
  98. mp0n = merge.p0+merge.n;
  99. if(mp0n != p0){
  100. bufread(f, mp0n, merge.buf+merge.nbuf, p0-mp0n);
  101. merge.nbuf += p0-mp0n;
  102. merge.n = p0-merge.p0;
  103. }
  104. }
  105. /*
  106. * like fileundelete, but get the data from arguments
  107. */
  108. void
  109. loginsert(File *f, uint p0, Rune *s, uint ns)
  110. {
  111. if(f->rescuing)
  112. return;
  113. if(ns == 0)
  114. return;
  115. if(ns<0 || ns>STRSIZE)
  116. panic("loginsert");
  117. if(f->seq < seq)
  118. filemark(f);
  119. if(p0 < f->hiposn)
  120. error(Esequence);
  121. if(merge.f != f
  122. || p0-(merge.p0+merge.n)>Maxmerge /* too far */
  123. || merge.nbuf+((p0+ns)-(merge.p0+merge.n))>RBUFSIZE) /* too long */
  124. flushmerge();
  125. if(ns>=RBUFSIZE){
  126. if(!(merge.n == 0 && merge.nbuf == 0 && merge.f == nil))
  127. panic("loginsert bad merge state");
  128. wrinsert(&f->epsilon, f->seq, TRUE, p0, s, ns);
  129. }else{
  130. if(merge.f != f){
  131. merge.f = f;
  132. merge.p0 = p0;
  133. merge.seq = f->seq;
  134. }
  135. mergeextend(f, p0);
  136. /* append string to merge */
  137. runemove(merge.buf+merge.nbuf, s, ns);
  138. merge.nbuf += ns;
  139. }
  140. f->hiposn = p0;
  141. if(!f->unread && !f->mod)
  142. state(f, Dirty);
  143. }
  144. void
  145. logdelete(File *f, uint p0, uint p1)
  146. {
  147. if(f->rescuing)
  148. return;
  149. if(p0 == p1)
  150. return;
  151. if(f->seq < seq)
  152. filemark(f);
  153. if(p1 < f->hiposn)
  154. error(Esequence);
  155. if(merge.f != f
  156. || p0-(merge.p0+merge.n)>Maxmerge /* too far */
  157. || merge.nbuf+(p0-(merge.p0+merge.n))>RBUFSIZE){ /* too long */
  158. flushmerge();
  159. merge.f = f;
  160. merge.p0 = p0;
  161. merge.seq = f->seq;
  162. }
  163. mergeextend(f, p0);
  164. /* add to deletion */
  165. merge.n = p1-merge.p0;
  166. f->hiposn = p1;
  167. if(!f->unread && !f->mod)
  168. state(f, Dirty);
  169. }
  170. /*
  171. * like fileunsetname, but get the data from arguments
  172. */
  173. void
  174. logsetname(File *f, String *s)
  175. {
  176. Undo u;
  177. Buffer *delta;
  178. if(f->rescuing)
  179. return;
  180. if(f->unread){ /* This is setting initial file name */
  181. filesetname(f, s);
  182. return;
  183. }
  184. if(f->seq < seq)
  185. filemark(f);
  186. /* undo a file name change by restoring old name */
  187. delta = &f->epsilon;
  188. u.type = Filename;
  189. u.mod = TRUE;
  190. u.seq = f->seq;
  191. u.p0 = 0; /* unused */
  192. u.n = s->n;
  193. if(s->n)
  194. bufinsert(delta, delta->nc, s->s, s->n);
  195. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  196. if(!f->unread && !f->mod)
  197. state(f, Dirty);
  198. }
  199. #ifdef NOTEXT
  200. File*
  201. fileaddtext(File *f, Text *t)
  202. {
  203. if(f == nil){
  204. f = emalloc(sizeof(File));
  205. f->unread = TRUE;
  206. }
  207. f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*));
  208. f->text[f->ntext++] = t;
  209. f->curtext = t;
  210. return f;
  211. }
  212. void
  213. filedeltext(File *f, Text *t)
  214. {
  215. int i;
  216. for(i=0; i<f->ntext; i++)
  217. if(f->text[i] == t)
  218. goto Found;
  219. panic("can't find text in filedeltext");
  220. Found:
  221. f->ntext--;
  222. if(f->ntext == 0){
  223. fileclose(f);
  224. return;
  225. }
  226. memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*));
  227. if(f->curtext == t)
  228. f->curtext = f->text[0];
  229. }
  230. #endif
  231. void
  232. fileinsert(File *f, uint p0, Rune *s, uint ns)
  233. {
  234. if(p0 > f->nc)
  235. panic("internal error: fileinsert");
  236. if(f->seq > 0)
  237. fileuninsert(f, &f->delta, p0, ns);
  238. bufinsert(f, p0, s, ns);
  239. if(ns)
  240. f->mod = TRUE;
  241. }
  242. void
  243. fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
  244. {
  245. Undo u;
  246. /* undo an insertion by deleting */
  247. u.type = Delete;
  248. u.mod = f->mod;
  249. u.seq = f->seq;
  250. u.p0 = p0;
  251. u.n = ns;
  252. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  253. }
  254. void
  255. filedelete(File *f, uint p0, uint p1)
  256. {
  257. if(!(p0<=p1 && p0<=f->nc && p1<=f->nc))
  258. panic("internal error: filedelete");
  259. if(f->seq > 0)
  260. fileundelete(f, &f->delta, p0, p1);
  261. bufdelete(f, p0, p1);
  262. if(p1 > p0)
  263. f->mod = TRUE;
  264. }
  265. void
  266. fileundelete(File *f, Buffer *delta, uint p0, uint p1)
  267. {
  268. Undo u;
  269. Rune *buf;
  270. uint i, n;
  271. /* undo a deletion by inserting */
  272. u.type = Insert;
  273. u.mod = f->mod;
  274. u.seq = f->seq;
  275. u.p0 = p0;
  276. u.n = p1-p0;
  277. buf = fbufalloc();
  278. for(i=p0; i<p1; i+=n){
  279. n = p1 - i;
  280. if(n > RBUFSIZE)
  281. n = RBUFSIZE;
  282. bufread(f, i, buf, n);
  283. bufinsert(delta, delta->nc, buf, n);
  284. }
  285. fbuffree(buf);
  286. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  287. }
  288. int
  289. filereadc(File *f, uint q)
  290. {
  291. Rune r;
  292. if(q >= f->nc)
  293. return -1;
  294. bufread(f, q, &r, 1);
  295. return r;
  296. }
  297. void
  298. filesetname(File *f, String *s)
  299. {
  300. if(!f->unread) /* This is setting initial file name */
  301. fileunsetname(f, &f->delta);
  302. Strduplstr(&f->name, s);
  303. sortname(f);
  304. f->unread = TRUE;
  305. }
  306. void
  307. fileunsetname(File *f, Buffer *delta)
  308. {
  309. String s;
  310. Undo u;
  311. /* undo a file name change by restoring old name */
  312. u.type = Filename;
  313. u.mod = f->mod;
  314. u.seq = f->seq;
  315. u.p0 = 0; /* unused */
  316. Strinit(&s);
  317. Strduplstr(&s, &f->name);
  318. fullname(&s);
  319. u.n = s.n;
  320. if(s.n)
  321. bufinsert(delta, delta->nc, s.s, s.n);
  322. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  323. Strclose(&s);
  324. }
  325. void
  326. fileunsetdot(File *f, Buffer *delta, Range dot)
  327. {
  328. Undo u;
  329. u.type = Dot;
  330. u.mod = f->mod;
  331. u.seq = f->seq;
  332. u.p0 = dot.p1;
  333. u.n = dot.p2 - dot.p1;
  334. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  335. }
  336. void
  337. fileunsetmark(File *f, Buffer *delta, Range mark)
  338. {
  339. Undo u;
  340. u.type = Mark;
  341. u.mod = f->mod;
  342. u.seq = f->seq;
  343. u.p0 = mark.p1;
  344. u.n = mark.p2 - mark.p1;
  345. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  346. }
  347. uint
  348. fileload(File *f, uint p0, int fd, int *nulls)
  349. {
  350. if(f->seq > 0)
  351. panic("undo in file.load unimplemented");
  352. return bufload(f, p0, fd, nulls);
  353. }
  354. int
  355. fileupdate(File *f, int notrans, int toterm)
  356. {
  357. uint p1, p2;
  358. int mod;
  359. if(f->rescuing)
  360. return FALSE;
  361. flushmerge();
  362. /*
  363. * fix the modification bit
  364. * subtle point: don't save it away in the log.
  365. *
  366. * if another change is made, the correct f->mod
  367. * state is saved in the undo log by filemark
  368. * when setting the dot and mark.
  369. *
  370. * if the change is undone, the correct state is
  371. * saved from f in the fileun... routines.
  372. */
  373. mod = f->mod;
  374. f->mod = f->prevmod;
  375. if(f == cmd)
  376. notrans = TRUE;
  377. else{
  378. fileunsetdot(f, &f->delta, f->prevdot);
  379. fileunsetmark(f, &f->delta, f->prevmark);
  380. }
  381. f->dot = f->ndot;
  382. fileundo(f, FALSE, !notrans, &p1, &p2, toterm);
  383. f->mod = mod;
  384. if(f->delta.nc == 0)
  385. f->seq = 0;
  386. if(f == cmd)
  387. return FALSE;
  388. if(f->mod){
  389. f->closeok = 0;
  390. quitok = 0;
  391. }else
  392. f->closeok = 1;
  393. return TRUE;
  394. }
  395. long
  396. prevseq(Buffer *b)
  397. {
  398. Undo u;
  399. uint up;
  400. up = b->nc;
  401. if(up == 0)
  402. return 0;
  403. up -= Undosize;
  404. bufread(b, up, (Rune*)&u, Undosize);
  405. return u.seq;
  406. }
  407. long
  408. undoseq(File *f, int isundo)
  409. {
  410. if(isundo)
  411. return f->seq;
  412. return prevseq(&f->epsilon);
  413. }
  414. void
  415. fileundo(File *f, int isundo, int canredo, uint *q0p, uint *q1p, int flag)
  416. {
  417. Undo u;
  418. Rune *buf;
  419. uint i, n, up;
  420. uint stop;
  421. Buffer *delta, *epsilon;
  422. if(isundo){
  423. /* undo; reverse delta onto epsilon, seq decreases */
  424. delta = &f->delta;
  425. epsilon = &f->epsilon;
  426. stop = f->seq;
  427. }else{
  428. /* redo; reverse epsilon onto delta, seq increases */
  429. delta = &f->epsilon;
  430. epsilon = &f->delta;
  431. stop = 0; /* don't know yet */
  432. }
  433. raspstart(f);
  434. while(delta->nc > 0){
  435. up = delta->nc-Undosize;
  436. bufread(delta, up, (Rune*)&u, Undosize);
  437. if(isundo){
  438. if(u.seq < stop){
  439. f->seq = u.seq;
  440. raspdone(f, flag);
  441. return;
  442. }
  443. }else{
  444. if(stop == 0)
  445. stop = u.seq;
  446. if(u.seq > stop){
  447. raspdone(f, flag);
  448. return;
  449. }
  450. }
  451. switch(u.type){
  452. default:
  453. panic("undo unknown u.type");
  454. break;
  455. case Delete:
  456. f->seq = u.seq;
  457. if(canredo)
  458. fileundelete(f, epsilon, u.p0, u.p0+u.n);
  459. f->mod = u.mod;
  460. bufdelete(f, u.p0, u.p0+u.n);
  461. raspdelete(f, u.p0, u.p0+u.n, flag);
  462. *q0p = u.p0;
  463. *q1p = u.p0;
  464. break;
  465. case Insert:
  466. f->seq = u.seq;
  467. if(canredo)
  468. fileuninsert(f, epsilon, u.p0, u.n);
  469. f->mod = u.mod;
  470. up -= u.n;
  471. buf = fbufalloc();
  472. for(i=0; i<u.n; i+=n){
  473. n = u.n - i;
  474. if(n > RBUFSIZE)
  475. n = RBUFSIZE;
  476. bufread(delta, up+i, buf, n);
  477. bufinsert(f, u.p0+i, buf, n);
  478. raspinsert(f, u.p0+i, buf, n, flag);
  479. }
  480. fbuffree(buf);
  481. *q0p = u.p0;
  482. *q1p = u.p0+u.n;
  483. break;
  484. case Filename:
  485. f->seq = u.seq;
  486. if(canredo)
  487. fileunsetname(f, epsilon);
  488. f->mod = u.mod;
  489. up -= u.n;
  490. Strinsure(&f->name, u.n+1);
  491. bufread(delta, up, f->name.s, u.n);
  492. f->name.s[u.n] = 0;
  493. f->name.n = u.n;
  494. fixname(&f->name);
  495. sortname(f);
  496. break;
  497. case Dot:
  498. f->seq = u.seq;
  499. if(canredo)
  500. fileunsetdot(f, epsilon, f->dot.r);
  501. f->mod = u.mod;
  502. f->dot.r.p1 = u.p0;
  503. f->dot.r.p2 = u.p0 + u.n;
  504. break;
  505. case Mark:
  506. f->seq = u.seq;
  507. if(canredo)
  508. fileunsetmark(f, epsilon, f->mark);
  509. f->mod = u.mod;
  510. f->mark.p1 = u.p0;
  511. f->mark.p2 = u.p0 + u.n;
  512. break;
  513. }
  514. bufdelete(delta, up, delta->nc);
  515. }
  516. if(isundo)
  517. f->seq = 0;
  518. raspdone(f, flag);
  519. }
  520. void
  521. filereset(File *f)
  522. {
  523. bufreset(&f->delta);
  524. bufreset(&f->epsilon);
  525. f->seq = 0;
  526. }
  527. void
  528. fileclose(File *f)
  529. {
  530. Strclose(&f->name);
  531. bufclose(f);
  532. bufclose(&f->delta);
  533. bufclose(&f->epsilon);
  534. if(f->rasp)
  535. listfree(f->rasp);
  536. free(f);
  537. }
  538. void
  539. filemark(File *f)
  540. {
  541. if(f->unread)
  542. return;
  543. if(f->epsilon.nc)
  544. bufdelete(&f->epsilon, 0, f->epsilon.nc);
  545. if(f != cmd){
  546. f->prevdot = f->dot.r;
  547. f->prevmark = f->mark;
  548. f->prevseq = f->seq;
  549. f->prevmod = f->mod;
  550. }
  551. f->ndot = f->dot;
  552. f->seq = seq;
  553. f->hiposn = 0;
  554. }