file.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  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>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(p0 < 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. fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
  233. {
  234. Undo u;
  235. /* undo an insertion by deleting */
  236. u.type = Delete;
  237. u.mod = f->mod;
  238. u.seq = f->seq;
  239. u.p0 = p0;
  240. u.n = ns;
  241. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  242. }
  243. void
  244. fileundelete(File *f, Buffer *delta, uint p0, uint p1)
  245. {
  246. Undo u;
  247. Rune *buf;
  248. uint i, n;
  249. /* undo a deletion by inserting */
  250. u.type = Insert;
  251. u.mod = f->mod;
  252. u.seq = f->seq;
  253. u.p0 = p0;
  254. u.n = p1-p0;
  255. buf = fbufalloc();
  256. for(i=p0; i<p1; i+=n){
  257. n = p1 - i;
  258. if(n > RBUFSIZE)
  259. n = RBUFSIZE;
  260. bufread(f, i, buf, n);
  261. bufinsert(delta, delta->nc, buf, n);
  262. }
  263. fbuffree(buf);
  264. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  265. }
  266. int
  267. filereadc(File *f, uint q)
  268. {
  269. Rune r;
  270. if(q >= f->nc)
  271. return -1;
  272. bufread(f, q, &r, 1);
  273. return r;
  274. }
  275. void
  276. filesetname(File *f, String *s)
  277. {
  278. if(!f->unread) /* This is setting initial file name */
  279. fileunsetname(f, &f->delta);
  280. Strduplstr(&f->name, s);
  281. sortname(f);
  282. f->unread = TRUE;
  283. }
  284. void
  285. fileunsetname(File *f, Buffer *delta)
  286. {
  287. String s;
  288. Undo u;
  289. /* undo a file name change by restoring old name */
  290. u.type = Filename;
  291. u.mod = f->mod;
  292. u.seq = f->seq;
  293. u.p0 = 0; /* unused */
  294. Strinit(&s);
  295. Strduplstr(&s, &f->name);
  296. fullname(&s);
  297. u.n = s.n;
  298. if(s.n)
  299. bufinsert(delta, delta->nc, s.s, s.n);
  300. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  301. Strclose(&s);
  302. }
  303. void
  304. fileunsetdot(File *f, Buffer *delta, Range dot)
  305. {
  306. Undo u;
  307. u.type = Dot;
  308. u.mod = f->mod;
  309. u.seq = f->seq;
  310. u.p0 = dot.p1;
  311. u.n = dot.p2 - dot.p1;
  312. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  313. }
  314. void
  315. fileunsetmark(File *f, Buffer *delta, Range mark)
  316. {
  317. Undo u;
  318. u.type = Mark;
  319. u.mod = f->mod;
  320. u.seq = f->seq;
  321. u.p0 = mark.p1;
  322. u.n = mark.p2 - mark.p1;
  323. bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
  324. }
  325. uint
  326. fileload(File *f, uint p0, int fd, int *nulls)
  327. {
  328. if(f->seq > 0)
  329. panic("undo in file.load unimplemented");
  330. return bufload(f, p0, fd, nulls);
  331. }
  332. int
  333. fileupdate(File *f, int notrans, int toterm)
  334. {
  335. uint p1, p2;
  336. int mod;
  337. if(f->rescuing)
  338. return FALSE;
  339. flushmerge();
  340. /*
  341. * fix the modification bit
  342. * subtle point: don't save it away in the log.
  343. *
  344. * if another change is made, the correct f->mod
  345. * state is saved in the undo log by filemark
  346. * when setting the dot and mark.
  347. *
  348. * if the change is undone, the correct state is
  349. * saved from f in the fileun... routines.
  350. */
  351. mod = f->mod;
  352. f->mod = f->prevmod;
  353. if(f == cmd)
  354. notrans = TRUE;
  355. else{
  356. fileunsetdot(f, &f->delta, f->prevdot);
  357. fileunsetmark(f, &f->delta, f->prevmark);
  358. }
  359. f->dot = f->ndot;
  360. fileundo(f, FALSE, !notrans, &p1, &p2, toterm);
  361. f->mod = mod;
  362. if(f->delta.nc == 0)
  363. f->seq = 0;
  364. if(f == cmd)
  365. return FALSE;
  366. if(f->mod){
  367. f->closeok = 0;
  368. quitok = 0;
  369. }else
  370. f->closeok = 1;
  371. return TRUE;
  372. }
  373. long
  374. prevseq(Buffer *b)
  375. {
  376. Undo u;
  377. uint up;
  378. up = b->nc;
  379. if(up == 0)
  380. return 0;
  381. up -= Undosize;
  382. bufread(b, up, (Rune*)&u, Undosize);
  383. return u.seq;
  384. }
  385. long
  386. undoseq(File *f, int isundo)
  387. {
  388. if(isundo)
  389. return f->seq;
  390. return prevseq(&f->epsilon);
  391. }
  392. void
  393. fileundo(File *f, int isundo, int canredo, uint *q0p, uint *q1p, int flag)
  394. {
  395. Undo u;
  396. Rune *buf;
  397. uint i, n, up;
  398. uint stop;
  399. Buffer *delta, *epsilon;
  400. if(isundo){
  401. /* undo; reverse delta onto epsilon, seq decreases */
  402. delta = &f->delta;
  403. epsilon = &f->epsilon;
  404. stop = f->seq;
  405. }else{
  406. /* redo; reverse epsilon onto delta, seq increases */
  407. delta = &f->epsilon;
  408. epsilon = &f->delta;
  409. stop = 0; /* don't know yet */
  410. }
  411. raspstart(f);
  412. while(delta->nc > 0){
  413. /* rasp and buffer are in sync; sync with wire if needed */
  414. if(needoutflush())
  415. raspflush(f);
  416. up = delta->nc-Undosize;
  417. bufread(delta, up, (Rune*)&u, Undosize);
  418. if(isundo){
  419. if(u.seq < stop){
  420. f->seq = u.seq;
  421. raspdone(f, flag);
  422. return;
  423. }
  424. }else{
  425. if(stop == 0)
  426. stop = u.seq;
  427. if(u.seq > stop){
  428. raspdone(f, flag);
  429. return;
  430. }
  431. }
  432. switch(u.type){
  433. default:
  434. panic("undo unknown u.type");
  435. break;
  436. case Delete:
  437. f->seq = u.seq;
  438. if(canredo)
  439. fileundelete(f, epsilon, u.p0, u.p0+u.n);
  440. f->mod = u.mod;
  441. bufdelete(f, u.p0, u.p0+u.n);
  442. raspdelete(f, u.p0, u.p0+u.n, flag);
  443. *q0p = u.p0;
  444. *q1p = u.p0;
  445. break;
  446. case Insert:
  447. f->seq = u.seq;
  448. if(canredo)
  449. fileuninsert(f, epsilon, u.p0, u.n);
  450. f->mod = u.mod;
  451. up -= u.n;
  452. buf = fbufalloc();
  453. for(i=0; i<u.n; i+=n){
  454. n = u.n - i;
  455. if(n > RBUFSIZE)
  456. n = RBUFSIZE;
  457. bufread(delta, up+i, buf, n);
  458. bufinsert(f, u.p0+i, buf, n);
  459. raspinsert(f, u.p0+i, buf, n, flag);
  460. }
  461. fbuffree(buf);
  462. *q0p = u.p0;
  463. *q1p = u.p0+u.n;
  464. break;
  465. case Filename:
  466. f->seq = u.seq;
  467. if(canredo)
  468. fileunsetname(f, epsilon);
  469. f->mod = u.mod;
  470. up -= u.n;
  471. Strinsure(&f->name, u.n+1);
  472. bufread(delta, up, f->name.s, u.n);
  473. f->name.s[u.n] = 0;
  474. f->name.n = u.n;
  475. fixname(&f->name);
  476. sortname(f);
  477. break;
  478. case Dot:
  479. f->seq = u.seq;
  480. if(canredo)
  481. fileunsetdot(f, epsilon, f->dot.r);
  482. f->mod = u.mod;
  483. f->dot.r.p1 = u.p0;
  484. f->dot.r.p2 = u.p0 + u.n;
  485. break;
  486. case Mark:
  487. f->seq = u.seq;
  488. if(canredo)
  489. fileunsetmark(f, epsilon, f->mark);
  490. f->mod = u.mod;
  491. f->mark.p1 = u.p0;
  492. f->mark.p2 = u.p0 + u.n;
  493. break;
  494. }
  495. bufdelete(delta, up, delta->nc);
  496. }
  497. if(isundo)
  498. f->seq = 0;
  499. raspdone(f, flag);
  500. }
  501. void
  502. filereset(File *f)
  503. {
  504. bufreset(&f->delta);
  505. bufreset(&f->epsilon);
  506. f->seq = 0;
  507. }
  508. void
  509. fileclose(File *f)
  510. {
  511. Strclose(&f->name);
  512. bufclose(f);
  513. bufclose(&f->delta);
  514. bufclose(&f->epsilon);
  515. if(f->rasp)
  516. listfree(f->rasp);
  517. free(f);
  518. }
  519. void
  520. filemark(File *f)
  521. {
  522. if(f->unread)
  523. return;
  524. if(f->epsilon.nc)
  525. bufdelete(&f->epsilon, 0, f->epsilon.nc);
  526. if(f != cmd){
  527. f->prevdot = f->dot.r;
  528. f->prevmark = f->mark;
  529. f->prevseq = f->seq;
  530. f->prevmod = f->mod;
  531. }
  532. f->ndot = f->dot;
  533. f->seq = seq;
  534. f->hiposn = 0;
  535. }