buff.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <thread.h>
  5. #include <cursor.h>
  6. #include <mouse.h>
  7. #include <keyboard.h>
  8. #include <frame.h>
  9. #include <fcall.h>
  10. #include <plumb.h>
  11. #include "dat.h"
  12. #include "fns.h"
  13. enum
  14. {
  15. Slop = 100, /* room to grow with reallocation */
  16. };
  17. static
  18. void
  19. sizecache(Buffer *b, uint n)
  20. {
  21. if(n <= b->cmax)
  22. return;
  23. b->cmax = n+Slop;
  24. b->c = runerealloc(b->c, b->cmax);
  25. }
  26. static
  27. void
  28. addblock(Buffer *b, uint i, uint n)
  29. {
  30. if(i > b->nbl)
  31. error("internal error: addblock");
  32. b->bl = realloc(b->bl, (b->nbl+1)*sizeof b->bl[0]);
  33. if(i < b->nbl)
  34. memmove(b->bl+i+1, b->bl+i, (b->nbl-i)*sizeof(Block*));
  35. b->bl[i] = disknewblock(disk, n);
  36. b->nbl++;
  37. }
  38. static
  39. void
  40. delblock(Buffer *b, uint i)
  41. {
  42. if(i >= b->nbl)
  43. error("internal error: delblock");
  44. diskrelease(disk, b->bl[i]);
  45. b->nbl--;
  46. if(i < b->nbl)
  47. memmove(b->bl+i, b->bl+i+1, (b->nbl-i)*sizeof(Block*));
  48. b->bl = realloc(b->bl, b->nbl*sizeof b->bl[0]);
  49. }
  50. /*
  51. * Move cache so b->cq <= q0 < b->cq+b->cnc.
  52. * If at very end, q0 will fall on end of cache block.
  53. */
  54. static
  55. void
  56. flush(Buffer *b)
  57. {
  58. if(b->cdirty || b->cnc==0){
  59. if(b->cnc == 0)
  60. delblock(b, b->cbi);
  61. else
  62. diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc);
  63. b->cdirty = FALSE;
  64. }
  65. }
  66. static
  67. void
  68. setcache(Buffer *b, uint q0)
  69. {
  70. Block **blp, *bl;
  71. uint i, q;
  72. if(q0 > b->nc)
  73. error("internal error: setcache");
  74. /*
  75. * flush and reload if q0 is not in cache.
  76. */
  77. if(b->nc == 0 || (b->cq<=q0 && q0<b->cq+b->cnc))
  78. return;
  79. /*
  80. * if q0 is at end of file and end of cache, continue to grow this block
  81. */
  82. if(q0==b->nc && q0==b->cq+b->cnc && b->cnc<Maxblock)
  83. return;
  84. flush(b);
  85. /* find block */
  86. if(q0 < b->cq){
  87. q = 0;
  88. i = 0;
  89. }else{
  90. q = b->cq;
  91. i = b->cbi;
  92. }
  93. blp = &b->bl[i];
  94. while(q+(*blp)->n <= q0 && q+(*blp)->n < b->nc){
  95. q += (*blp)->n;
  96. i++;
  97. blp++;
  98. if(i >= b->nbl)
  99. error("block not found");
  100. }
  101. bl = *blp;
  102. /* remember position */
  103. b->cbi = i;
  104. b->cq = q;
  105. sizecache(b, bl->n);
  106. b->cnc = bl->n;
  107. /*read block*/
  108. diskread(disk, bl, b->c, b->cnc);
  109. }
  110. void
  111. bufinsert(Buffer *b, uint q0, Rune *s, uint n)
  112. {
  113. uint i, m, t, off;
  114. if(q0 > b->nc)
  115. error("internal error: bufinsert");
  116. while(n > 0){
  117. setcache(b, q0);
  118. off = q0-b->cq;
  119. if(b->cnc+n <= Maxblock){
  120. /* Everything fits in one block. */
  121. t = b->cnc+n;
  122. m = n;
  123. if(b->bl == nil){ /* allocate */
  124. if(b->cnc != 0)
  125. error("internal error: bufinsert1 cnc!=0");
  126. addblock(b, 0, t);
  127. b->cbi = 0;
  128. }
  129. sizecache(b, t);
  130. runemove(b->c+off+m, b->c+off, b->cnc-off);
  131. runemove(b->c+off, s, m);
  132. b->cnc = t;
  133. goto Tail;
  134. }
  135. /*
  136. * We must make a new block. If q0 is at
  137. * the very beginning or end of this block,
  138. * just make a new block and fill it.
  139. */
  140. if(q0==b->cq || q0==b->cq+b->cnc){
  141. if(b->cdirty)
  142. flush(b);
  143. m = min(n, Maxblock);
  144. if(b->bl == nil){ /* allocate */
  145. if(b->cnc != 0)
  146. error("internal error: bufinsert2 cnc!=0");
  147. i = 0;
  148. }else{
  149. i = b->cbi;
  150. if(q0 > b->cq)
  151. i++;
  152. }
  153. addblock(b, i, m);
  154. sizecache(b, m);
  155. runemove(b->c, s, m);
  156. b->cq = q0;
  157. b->cbi = i;
  158. b->cnc = m;
  159. goto Tail;
  160. }
  161. /*
  162. * Split the block; cut off the right side and
  163. * let go of it.
  164. */
  165. m = b->cnc-off;
  166. if(m > 0){
  167. i = b->cbi+1;
  168. addblock(b, i, m);
  169. diskwrite(disk, &b->bl[i], b->c+off, m);
  170. b->cnc -= m;
  171. }
  172. /*
  173. * Now at end of block. Take as much input
  174. * as possible and tack it on end of block.
  175. */
  176. m = min(n, Maxblock-b->cnc);
  177. sizecache(b, b->cnc+m);
  178. runemove(b->c+b->cnc, s, m);
  179. b->cnc += m;
  180. Tail:
  181. b->nc += m;
  182. q0 += m;
  183. s += m;
  184. n -= m;
  185. b->cdirty = TRUE;
  186. }
  187. }
  188. void
  189. bufdelete(Buffer *b, uint q0, uint q1)
  190. {
  191. uint m, n, off;
  192. if(!(q0<=q1 && q0<=b->nc && q1<=b->nc))
  193. error("internal error: bufdelete");
  194. while(q1 > q0){
  195. setcache(b, q0);
  196. off = q0-b->cq;
  197. if(q1 > b->cq+b->cnc)
  198. n = b->cnc - off;
  199. else
  200. n = q1-q0;
  201. m = b->cnc - (off+n);
  202. if(m > 0)
  203. runemove(b->c+off, b->c+off+n, m);
  204. b->cnc -= n;
  205. b->cdirty = TRUE;
  206. q1 -= n;
  207. b->nc -= n;
  208. }
  209. }
  210. static int
  211. bufloader(void *v, uint q0, Rune *r, int nr)
  212. {
  213. bufinsert(v, q0, r, nr);
  214. return nr;
  215. }
  216. uint
  217. loadfile(int fd, uint q0, int *nulls, int(*f)(void*, uint, Rune*, int), void *arg)
  218. {
  219. char *p;
  220. Rune *r;
  221. int l, m, n, nb, nr;
  222. uint q1;
  223. p = emalloc((Maxblock+UTFmax+1)*sizeof p[0]);
  224. r = runemalloc(Maxblock);
  225. m = 0;
  226. n = 1;
  227. q1 = q0;
  228. /*
  229. * At top of loop, may have m bytes left over from
  230. * last pass, possibly representing a partial rune.
  231. */
  232. while(n > 0){
  233. n = read(fd, p+m, Maxblock);
  234. if(n < 0){
  235. warning(nil, "read error in Buffer.load");
  236. break;
  237. }
  238. m += n;
  239. p[m] = 0;
  240. l = m;
  241. if(n > 0)
  242. l -= UTFmax;
  243. cvttorunes(p, l, r, &nb, &nr, nulls);
  244. memmove(p, p+nb, m-nb);
  245. m -= nb;
  246. q1 += (*f)(arg, q1, r, nr);
  247. }
  248. free(p);
  249. free(r);
  250. return q1-q0;
  251. }
  252. uint
  253. bufload(Buffer *b, uint q0, int fd, int *nulls)
  254. {
  255. if(q0 > b->nc)
  256. error("internal error: bufload");
  257. return loadfile(fd, q0, nulls, bufloader, b);
  258. }
  259. void
  260. bufread(Buffer *b, uint q0, Rune *s, uint n)
  261. {
  262. uint m;
  263. if(!(q0<=b->nc && q0+n<=b->nc))
  264. error("bufread: internal error");
  265. while(n > 0){
  266. setcache(b, q0);
  267. m = min(n, b->cnc-(q0-b->cq));
  268. runemove(s, b->c+(q0-b->cq), m);
  269. q0 += m;
  270. s += m;
  271. n -= m;
  272. }
  273. }
  274. void
  275. bufreset(Buffer *b)
  276. {
  277. int i;
  278. b->nc = 0;
  279. b->cnc = 0;
  280. b->cq = 0;
  281. b->cdirty = 0;
  282. b->cbi = 0;
  283. /* delete backwards to avoid n² behavior */
  284. for(i=b->nbl-1; --i>=0; )
  285. delblock(b, i);
  286. }
  287. void
  288. bufclose(Buffer *b)
  289. {
  290. bufreset(b);
  291. free(b->c);
  292. b->c = nil;
  293. b->cnc = 0;
  294. free(b->bl);
  295. b->bl = nil;
  296. b->nbl = 0;
  297. }