cache.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include "misc.h"
  4. #include "dllist.h"
  5. #include "cache.h"
  6. #include "help.h"
  7. static inline int hash(int pgno)
  8. {
  9. // very simple...
  10. return pgno % HASH_SIZE;
  11. }
  12. static void do_erc(struct vt_page *ovtp, struct vt_page *nvtp)
  13. {
  14. int l, c;
  15. if (nvtp->errors == 0 && ovtp->lines == nvtp->lines)
  16. return;
  17. for (l = 0; l < H; ++l)
  18. {
  19. if (~nvtp->lines & (1 << l))
  20. memcpy(nvtp->data[l], ovtp->data[l], W);
  21. else if (ovtp->lines & (1 << l))
  22. for (c = 0; c < W; ++c)
  23. if (nvtp->data[l][c] == BAD_CHAR)
  24. nvtp->data[l][c] = ovtp->data[l][c];
  25. }
  26. nvtp->lines |= ovtp->lines;
  27. }
  28. static void cache_close(struct cache *ca)
  29. {
  30. struct cache_page *cp;
  31. int i;
  32. for (i = 0; i < HASH_SIZE; ++i)
  33. while (not dl_empty(ca->hash + i))
  34. {
  35. cp = PTR ca->hash[i].first;
  36. dl_remove(cp->node);
  37. free(cp);
  38. }
  39. free(ca);
  40. }
  41. static void cache_reset(struct cache *ca)
  42. {
  43. struct cache_page *cp, *cpn;
  44. int i;
  45. for (i = 0; i < HASH_SIZE; ++i)
  46. for (cp = PTR ca->hash[i].first; cpn = PTR cp->node->next; cp = cpn)
  47. if (cp->page->pgno / 256 != 9) // don't remove help pages
  48. {
  49. dl_remove(cp->node);
  50. free(cp);
  51. ca->npages--;
  52. }
  53. memset(ca->hi_subno, 0, sizeof(ca->hi_subno[0]) * 0x900);
  54. }
  55. /* Get a page from the cache.
  56. If subno is SUB_ANY, the newest subpage of that page is returned */
  57. static struct vt_page * cache_get(struct cache *ca, int pgno, int subno)
  58. {
  59. struct cache_page *cp;
  60. int h = hash(pgno);
  61. for (cp = PTR ca->hash[h].first; cp->node->next; cp = PTR cp->node->next)
  62. if (cp->page->pgno == pgno)
  63. if (subno == ANY_SUB || cp->page->subno == subno)
  64. {
  65. // found, move to front (make it 'new')
  66. dl_insert_first(ca->hash + h, dl_remove(cp->node));
  67. return cp->page;
  68. }
  69. return 0;
  70. }
  71. /* Put a page in the cache.
  72. If it's already there, it is updated. */
  73. static struct vt_page * cache_put(struct cache *ca, struct vt_page *vtp)
  74. {
  75. struct cache_page *cp;
  76. int h = hash(vtp->pgno);
  77. for (cp = PTR ca->hash[h].first; cp->node->next; cp = PTR cp->node->next)
  78. if (cp->page->pgno == vtp->pgno && cp->page->subno == vtp->subno)
  79. break;
  80. if (cp->node->next)
  81. {
  82. // move to front.
  83. dl_insert_first(ca->hash + h, dl_remove(cp->node));
  84. if (ca->erc)
  85. do_erc(cp->page, vtp);
  86. }
  87. else
  88. {
  89. cp = malloc(sizeof(*cp));
  90. if (cp == 0)
  91. return 0;
  92. if (vtp->subno >= ca->hi_subno[vtp->pgno])
  93. ca->hi_subno[vtp->pgno] = vtp->subno + 1;
  94. ca->npages++;
  95. dl_insert_first(ca->hash + h, cp->node);
  96. }
  97. *cp->page = *vtp;
  98. return cp->page;
  99. }
  100. /* Same as cache_get but doesn't make the found entry new */
  101. static struct vt_page * cache_lookup(struct cache *ca, int pgno, int subno)
  102. {
  103. struct cache_page *cp;
  104. int h = hash(pgno);
  105. for (cp = PTR ca->hash[h].first; cp->node->next; cp = PTR cp->node->next)
  106. if (cp->page->pgno == pgno)
  107. if (subno == ANY_SUB || cp->page->subno == subno)
  108. return cp->page;
  109. return 0;
  110. }
  111. static struct vt_page * cache_foreach_pg(struct cache *ca, int pgno, int subno,
  112. int dir, int (*func)(), void *data)
  113. {
  114. struct vt_page *vtp, *s_vtp = 0;
  115. if (ca->npages == 0)
  116. return 0;
  117. if (vtp = cache_lookup(ca, pgno, subno))
  118. subno = vtp->subno;
  119. else if (subno == ANY_SUB)
  120. subno = dir < 0 ? 0 : 0xffff;
  121. for (;;)
  122. {
  123. subno += dir;
  124. while (subno < 0 || subno >= ca->hi_subno[pgno])
  125. {
  126. pgno += dir;
  127. if (pgno < 0x100)
  128. pgno = 0x9ff;
  129. if (pgno > 0x9ff)
  130. pgno = 0x100;
  131. subno = dir < 0 ? ca->hi_subno[pgno] - 1 : 0;
  132. }
  133. if (vtp = cache_lookup(ca, pgno, subno))
  134. {
  135. if (s_vtp == vtp)
  136. return 0;
  137. if (s_vtp == 0)
  138. s_vtp = vtp;
  139. if (func(data, vtp))
  140. return vtp;
  141. }
  142. }
  143. }
  144. static int cache_mode(struct cache *ca, int mode, int arg)
  145. {
  146. int res = -1;
  147. switch (mode)
  148. {
  149. case CACHE_MODE_ERC:
  150. res = ca->erc;
  151. ca->erc = arg ? 1 : 0;
  152. break;
  153. }
  154. return res;
  155. }
  156. static struct cache_ops cops =
  157. {
  158. cache_close,
  159. cache_get,
  160. cache_put,
  161. cache_reset,
  162. cache_foreach_pg,
  163. cache_mode,
  164. };
  165. struct cache * cache_open(void)
  166. {
  167. struct cache *ca;
  168. struct vt_page *vtp;
  169. int i;
  170. if (not(ca = malloc(sizeof(*ca))))
  171. goto fail1;
  172. for (i = 0; i < HASH_SIZE; ++i)
  173. dl_init(ca->hash + i);
  174. memset(ca->hi_subno, 0, sizeof(ca->hi_subno));
  175. ca->erc = 1;
  176. ca->npages = 0;
  177. ca->op = &cops;
  178. for (vtp = help_pages; vtp < help_pages + nr_help_pages; vtp++)
  179. cache_put(ca, vtp);
  180. return ca;
  181. fail2:
  182. free(ca);
  183. fail1:
  184. return 0;
  185. }