buff.c 5.0 KB

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