jk-ferret 0.11.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (228) hide show
  1. data/CHANGELOG +24 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +90 -0
  4. data/RELEASE_CHANGES +137 -0
  5. data/RELEASE_NOTES +60 -0
  6. data/Rakefile +443 -0
  7. data/TODO +109 -0
  8. data/TUTORIAL +231 -0
  9. data/bin/ferret-browser +79 -0
  10. data/ext/BZLIB_blocksort.c +1094 -0
  11. data/ext/BZLIB_bzlib.c +1578 -0
  12. data/ext/BZLIB_compress.c +672 -0
  13. data/ext/BZLIB_crctable.c +104 -0
  14. data/ext/BZLIB_decompress.c +626 -0
  15. data/ext/BZLIB_huffman.c +205 -0
  16. data/ext/BZLIB_randtable.c +84 -0
  17. data/ext/STEMMER_api.c +66 -0
  18. data/ext/STEMMER_libstemmer.c +93 -0
  19. data/ext/STEMMER_stem_ISO_8859_1_danish.c +337 -0
  20. data/ext/STEMMER_stem_ISO_8859_1_dutch.c +624 -0
  21. data/ext/STEMMER_stem_ISO_8859_1_english.c +1117 -0
  22. data/ext/STEMMER_stem_ISO_8859_1_finnish.c +762 -0
  23. data/ext/STEMMER_stem_ISO_8859_1_french.c +1246 -0
  24. data/ext/STEMMER_stem_ISO_8859_1_german.c +503 -0
  25. data/ext/STEMMER_stem_ISO_8859_1_hungarian.c +1230 -0
  26. data/ext/STEMMER_stem_ISO_8859_1_italian.c +1065 -0
  27. data/ext/STEMMER_stem_ISO_8859_1_norwegian.c +297 -0
  28. data/ext/STEMMER_stem_ISO_8859_1_porter.c +749 -0
  29. data/ext/STEMMER_stem_ISO_8859_1_portuguese.c +1017 -0
  30. data/ext/STEMMER_stem_ISO_8859_1_spanish.c +1093 -0
  31. data/ext/STEMMER_stem_ISO_8859_1_swedish.c +307 -0
  32. data/ext/STEMMER_stem_ISO_8859_2_romanian.c +998 -0
  33. data/ext/STEMMER_stem_KOI8_R_russian.c +700 -0
  34. data/ext/STEMMER_stem_UTF_8_danish.c +339 -0
  35. data/ext/STEMMER_stem_UTF_8_dutch.c +634 -0
  36. data/ext/STEMMER_stem_UTF_8_english.c +1125 -0
  37. data/ext/STEMMER_stem_UTF_8_finnish.c +768 -0
  38. data/ext/STEMMER_stem_UTF_8_french.c +1256 -0
  39. data/ext/STEMMER_stem_UTF_8_german.c +509 -0
  40. data/ext/STEMMER_stem_UTF_8_hungarian.c +1234 -0
  41. data/ext/STEMMER_stem_UTF_8_italian.c +1073 -0
  42. data/ext/STEMMER_stem_UTF_8_norwegian.c +299 -0
  43. data/ext/STEMMER_stem_UTF_8_porter.c +755 -0
  44. data/ext/STEMMER_stem_UTF_8_portuguese.c +1023 -0
  45. data/ext/STEMMER_stem_UTF_8_romanian.c +1004 -0
  46. data/ext/STEMMER_stem_UTF_8_russian.c +694 -0
  47. data/ext/STEMMER_stem_UTF_8_spanish.c +1097 -0
  48. data/ext/STEMMER_stem_UTF_8_swedish.c +309 -0
  49. data/ext/STEMMER_stem_UTF_8_turkish.c +2205 -0
  50. data/ext/STEMMER_utilities.c +478 -0
  51. data/ext/analysis.c +1710 -0
  52. data/ext/analysis.h +266 -0
  53. data/ext/api.h +26 -0
  54. data/ext/array.c +125 -0
  55. data/ext/array.h +62 -0
  56. data/ext/bitvector.c +96 -0
  57. data/ext/bitvector.h +594 -0
  58. data/ext/bzlib.h +282 -0
  59. data/ext/bzlib_private.h +503 -0
  60. data/ext/compound_io.c +384 -0
  61. data/ext/config.h +52 -0
  62. data/ext/document.c +159 -0
  63. data/ext/document.h +63 -0
  64. data/ext/except.c +102 -0
  65. data/ext/except.h +176 -0
  66. data/ext/extconf.rb +15 -0
  67. data/ext/ferret.c +416 -0
  68. data/ext/ferret.h +94 -0
  69. data/ext/field_index.c +262 -0
  70. data/ext/field_index.h +52 -0
  71. data/ext/filter.c +157 -0
  72. data/ext/fs_store.c +493 -0
  73. data/ext/global.c +458 -0
  74. data/ext/global.h +302 -0
  75. data/ext/hash.c +524 -0
  76. data/ext/hash.h +515 -0
  77. data/ext/hashset.c +192 -0
  78. data/ext/hashset.h +215 -0
  79. data/ext/header.h +58 -0
  80. data/ext/helper.c +63 -0
  81. data/ext/helper.h +21 -0
  82. data/ext/index.c +6804 -0
  83. data/ext/index.h +935 -0
  84. data/ext/internal.h +1019 -0
  85. data/ext/lang.c +10 -0
  86. data/ext/lang.h +68 -0
  87. data/ext/libstemmer.h +79 -0
  88. data/ext/mempool.c +88 -0
  89. data/ext/mempool.h +43 -0
  90. data/ext/modules.h +190 -0
  91. data/ext/multimapper.c +351 -0
  92. data/ext/multimapper.h +60 -0
  93. data/ext/posh.c +1006 -0
  94. data/ext/posh.h +973 -0
  95. data/ext/priorityqueue.c +149 -0
  96. data/ext/priorityqueue.h +155 -0
  97. data/ext/q_boolean.c +1621 -0
  98. data/ext/q_const_score.c +162 -0
  99. data/ext/q_filtered_query.c +212 -0
  100. data/ext/q_fuzzy.c +280 -0
  101. data/ext/q_match_all.c +149 -0
  102. data/ext/q_multi_term.c +673 -0
  103. data/ext/q_parser.c +3103 -0
  104. data/ext/q_phrase.c +1206 -0
  105. data/ext/q_prefix.c +98 -0
  106. data/ext/q_range.c +682 -0
  107. data/ext/q_span.c +2390 -0
  108. data/ext/q_term.c +337 -0
  109. data/ext/q_wildcard.c +167 -0
  110. data/ext/r_analysis.c +2626 -0
  111. data/ext/r_index.c +3468 -0
  112. data/ext/r_qparser.c +635 -0
  113. data/ext/r_search.c +4490 -0
  114. data/ext/r_store.c +513 -0
  115. data/ext/r_utils.c +1131 -0
  116. data/ext/ram_store.c +476 -0
  117. data/ext/scanner.c +895 -0
  118. data/ext/scanner.h +36 -0
  119. data/ext/scanner_mb.c +6701 -0
  120. data/ext/scanner_utf8.c +4415 -0
  121. data/ext/search.c +1864 -0
  122. data/ext/search.h +953 -0
  123. data/ext/similarity.c +151 -0
  124. data/ext/similarity.h +89 -0
  125. data/ext/sort.c +786 -0
  126. data/ext/stem_ISO_8859_1_danish.h +16 -0
  127. data/ext/stem_ISO_8859_1_dutch.h +16 -0
  128. data/ext/stem_ISO_8859_1_english.h +16 -0
  129. data/ext/stem_ISO_8859_1_finnish.h +16 -0
  130. data/ext/stem_ISO_8859_1_french.h +16 -0
  131. data/ext/stem_ISO_8859_1_german.h +16 -0
  132. data/ext/stem_ISO_8859_1_hungarian.h +16 -0
  133. data/ext/stem_ISO_8859_1_italian.h +16 -0
  134. data/ext/stem_ISO_8859_1_norwegian.h +16 -0
  135. data/ext/stem_ISO_8859_1_porter.h +16 -0
  136. data/ext/stem_ISO_8859_1_portuguese.h +16 -0
  137. data/ext/stem_ISO_8859_1_spanish.h +16 -0
  138. data/ext/stem_ISO_8859_1_swedish.h +16 -0
  139. data/ext/stem_ISO_8859_2_romanian.h +16 -0
  140. data/ext/stem_KOI8_R_russian.h +16 -0
  141. data/ext/stem_UTF_8_danish.h +16 -0
  142. data/ext/stem_UTF_8_dutch.h +16 -0
  143. data/ext/stem_UTF_8_english.h +16 -0
  144. data/ext/stem_UTF_8_finnish.h +16 -0
  145. data/ext/stem_UTF_8_french.h +16 -0
  146. data/ext/stem_UTF_8_german.h +16 -0
  147. data/ext/stem_UTF_8_hungarian.h +16 -0
  148. data/ext/stem_UTF_8_italian.h +16 -0
  149. data/ext/stem_UTF_8_norwegian.h +16 -0
  150. data/ext/stem_UTF_8_porter.h +16 -0
  151. data/ext/stem_UTF_8_portuguese.h +16 -0
  152. data/ext/stem_UTF_8_romanian.h +16 -0
  153. data/ext/stem_UTF_8_russian.h +16 -0
  154. data/ext/stem_UTF_8_spanish.h +16 -0
  155. data/ext/stem_UTF_8_swedish.h +16 -0
  156. data/ext/stem_UTF_8_turkish.h +16 -0
  157. data/ext/stopwords.c +410 -0
  158. data/ext/store.c +698 -0
  159. data/ext/store.h +799 -0
  160. data/ext/symbol.c +10 -0
  161. data/ext/symbol.h +23 -0
  162. data/ext/term_vectors.c +73 -0
  163. data/ext/threading.h +31 -0
  164. data/ext/win32.h +62 -0
  165. data/lib/ferret.rb +30 -0
  166. data/lib/ferret/browser.rb +246 -0
  167. data/lib/ferret/browser/s/global.js +192 -0
  168. data/lib/ferret/browser/s/style.css +148 -0
  169. data/lib/ferret/browser/views/document/list.rhtml +49 -0
  170. data/lib/ferret/browser/views/document/show.rhtml +27 -0
  171. data/lib/ferret/browser/views/error/index.rhtml +7 -0
  172. data/lib/ferret/browser/views/help/index.rhtml +8 -0
  173. data/lib/ferret/browser/views/home/index.rhtml +29 -0
  174. data/lib/ferret/browser/views/layout.rhtml +22 -0
  175. data/lib/ferret/browser/views/term-vector/index.rhtml +4 -0
  176. data/lib/ferret/browser/views/term/index.rhtml +199 -0
  177. data/lib/ferret/browser/views/term/termdocs.rhtml +1 -0
  178. data/lib/ferret/browser/webrick.rb +14 -0
  179. data/lib/ferret/document.rb +130 -0
  180. data/lib/ferret/field_infos.rb +44 -0
  181. data/lib/ferret/field_symbol.rb +87 -0
  182. data/lib/ferret/index.rb +973 -0
  183. data/lib/ferret/number_tools.rb +157 -0
  184. data/lib/ferret/version.rb +3 -0
  185. data/setup.rb +1555 -0
  186. data/test/long_running/largefile/tc_largefile.rb +46 -0
  187. data/test/test_all.rb +5 -0
  188. data/test/test_helper.rb +29 -0
  189. data/test/test_installed.rb +1 -0
  190. data/test/threading/number_to_spoken.rb +132 -0
  191. data/test/threading/thread_safety_index_test.rb +88 -0
  192. data/test/threading/thread_safety_read_write_test.rb +73 -0
  193. data/test/threading/thread_safety_test.rb +133 -0
  194. data/test/unit/analysis/tc_analyzer.rb +550 -0
  195. data/test/unit/analysis/tc_token_stream.rb +653 -0
  196. data/test/unit/index/tc_index.rb +867 -0
  197. data/test/unit/index/tc_index_reader.rb +699 -0
  198. data/test/unit/index/tc_index_writer.rb +447 -0
  199. data/test/unit/index/th_doc.rb +332 -0
  200. data/test/unit/query_parser/tc_query_parser.rb +238 -0
  201. data/test/unit/search/tc_filter.rb +156 -0
  202. data/test/unit/search/tc_fuzzy_query.rb +147 -0
  203. data/test/unit/search/tc_index_searcher.rb +67 -0
  204. data/test/unit/search/tc_multi_searcher.rb +128 -0
  205. data/test/unit/search/tc_multiple_search_requests.rb +58 -0
  206. data/test/unit/search/tc_search_and_sort.rb +179 -0
  207. data/test/unit/search/tc_sort.rb +49 -0
  208. data/test/unit/search/tc_sort_field.rb +27 -0
  209. data/test/unit/search/tc_spans.rb +190 -0
  210. data/test/unit/search/tm_searcher.rb +436 -0
  211. data/test/unit/store/tc_fs_store.rb +115 -0
  212. data/test/unit/store/tc_ram_store.rb +35 -0
  213. data/test/unit/store/tm_store.rb +34 -0
  214. data/test/unit/store/tm_store_lock.rb +68 -0
  215. data/test/unit/tc_document.rb +81 -0
  216. data/test/unit/tc_field_symbol.rb +26 -0
  217. data/test/unit/ts_analysis.rb +2 -0
  218. data/test/unit/ts_index.rb +2 -0
  219. data/test/unit/ts_largefile.rb +4 -0
  220. data/test/unit/ts_query_parser.rb +2 -0
  221. data/test/unit/ts_search.rb +2 -0
  222. data/test/unit/ts_store.rb +2 -0
  223. data/test/unit/ts_utils.rb +2 -0
  224. data/test/unit/utils/tc_bit_vector.rb +295 -0
  225. data/test/unit/utils/tc_number_tools.rb +117 -0
  226. data/test/unit/utils/tc_priority_queue.rb +106 -0
  227. data/test/utils/content_generator.rb +226 -0
  228. metadata +319 -0
data/ext/ram_store.c ADDED
@@ -0,0 +1,476 @@
1
+ #include "store.h"
2
+ #include <string.h>
3
+ #include "internal.h"
4
+
5
+ static RAMFile *rf_new(const char *name)
6
+ {
7
+ RAMFile *rf = ALLOC(RAMFile);
8
+ rf->buffers = ALLOC(uchar *);
9
+ rf->buffers[0] = ALLOC_N(uchar, BUFFER_SIZE);
10
+ rf->name = estrdup(name);
11
+ rf->len = 0;
12
+ rf->bufcnt = 1;
13
+ rf->ref_cnt = 1;
14
+ return rf;
15
+ }
16
+
17
+ static void rf_extend_if_necessary(RAMFile *rf, int buf_num)
18
+ {
19
+ while (rf->bufcnt <= buf_num) {
20
+ REALLOC_N(rf->buffers, uchar *, (rf->bufcnt + 1));
21
+ rf->buffers[rf->bufcnt++] = ALLOC_N(uchar, BUFFER_SIZE);
22
+ }
23
+ }
24
+
25
+ static void rf_close(void *p)
26
+ {
27
+ int i;
28
+ RAMFile *rf = (RAMFile *)p;
29
+ if (rf->ref_cnt > 0) {
30
+ return;
31
+ }
32
+ free(rf->name);
33
+ for (i = 0; i < rf->bufcnt; i++) {
34
+ free(rf->buffers[i]);
35
+ }
36
+ free(rf->buffers);
37
+ free(rf);
38
+ }
39
+
40
+ static void ram_touch(Store *store, const char *filename)
41
+ {
42
+ if (h_get(store->dir.ht, filename) == NULL) {
43
+ h_set(store->dir.ht, filename, rf_new(filename));
44
+ }
45
+ }
46
+
47
+ static int ram_exists(Store *store, const char *filename)
48
+ {
49
+ if (h_get(store->dir.ht, filename) != NULL) {
50
+ return true;
51
+ }
52
+ else {
53
+ return false;
54
+ }
55
+ }
56
+
57
+ static int ram_remove(Store *store, const char *filename)
58
+ {
59
+ RAMFile *rf = (RAMFile *)h_rem(store->dir.ht, filename, false);
60
+ if (rf != NULL) {
61
+ DEREF(rf);
62
+ rf_close(rf);
63
+ return true;
64
+ }
65
+ else {
66
+ return false;
67
+ }
68
+ }
69
+
70
+ static void ram_rename(Store *store, const char *from, const char *to)
71
+ {
72
+ RAMFile *rf = (RAMFile *)h_rem(store->dir.ht, from, false);
73
+ RAMFile *tmp;
74
+
75
+ if (rf == NULL) {
76
+ RAISE(IO_ERROR, "couldn't rename \"%s\" to \"%s\". \"%s\""
77
+ " doesn't exist", from, to, from);
78
+ }
79
+
80
+ free(rf->name);
81
+
82
+ rf->name = estrdup(to);
83
+
84
+ /* clean up the file we are overwriting */
85
+ tmp = (RAMFile *)h_get(store->dir.ht, to);
86
+ if (tmp != NULL) {
87
+ DEREF(tmp);
88
+ }
89
+
90
+ h_set(store->dir.ht, rf->name, rf);
91
+ }
92
+
93
+ static int ram_count(Store *store)
94
+ {
95
+ return store->dir.ht->size;
96
+ }
97
+
98
+ static void ram_each(Store *store,
99
+ void (*func)(const char *fname, void *arg), void *arg)
100
+ {
101
+ Hash *ht = store->dir.ht;
102
+ int i;
103
+ for (i = 0; i <= ht->mask; i++) {
104
+ RAMFile *rf = (RAMFile *)ht->table[i].value;
105
+ if (rf) {
106
+ if (strncmp(rf->name, LOCK_PREFIX, strlen(LOCK_PREFIX)) == 0) {
107
+ continue;
108
+ }
109
+ func(rf->name, arg);
110
+ }
111
+ }
112
+ }
113
+
114
+ static void ram_close_i(Store *store)
115
+ {
116
+ Hash *ht = store->dir.ht;
117
+ int i;
118
+ for (i = 0; i <= ht->mask; i++) {
119
+ RAMFile *rf = (RAMFile *)ht->table[i].value;
120
+ if (rf) {
121
+ DEREF(rf);
122
+ }
123
+ }
124
+ h_destroy(store->dir.ht);
125
+ store_destroy(store);
126
+ }
127
+
128
+ /*
129
+ * Be sure to keep the locks
130
+ */
131
+ static void ram_clear(Store *store)
132
+ {
133
+ int i;
134
+ Hash *ht = store->dir.ht;
135
+ for (i = 0; i <= ht->mask; i++) {
136
+ RAMFile *rf = (RAMFile *)ht->table[i].value;
137
+ if (rf && !file_is_lock(rf->name)) {
138
+ DEREF(rf);
139
+ h_del(ht, rf->name);
140
+ }
141
+ }
142
+ }
143
+
144
+ static void ram_clear_locks(Store *store)
145
+ {
146
+ int i;
147
+ Hash *ht = store->dir.ht;
148
+ for (i = 0; i <= ht->mask; i++) {
149
+ RAMFile *rf = (RAMFile *)ht->table[i].value;
150
+ if (rf && file_is_lock(rf->name)) {
151
+ DEREF(rf);
152
+ h_del(ht, rf->name);
153
+ }
154
+ }
155
+ }
156
+
157
+ static void ram_clear_all(Store *store)
158
+ {
159
+ int i;
160
+ Hash *ht = store->dir.ht;
161
+ for (i = 0; i <= ht->mask; i++) {
162
+ RAMFile *rf = (RAMFile *)ht->table[i].value;
163
+ if (rf) {
164
+ DEREF(rf);
165
+ h_del(ht, rf->name);
166
+ }
167
+ }
168
+ }
169
+
170
+ static off_t ram_length(Store *store, const char *filename)
171
+ {
172
+ RAMFile *rf = (RAMFile *)h_get(store->dir.ht, filename);
173
+ if (rf != NULL) {
174
+ return rf->len;
175
+ }
176
+ else {
177
+ return 0;
178
+ }
179
+ }
180
+
181
+ off_t ramo_length(OutStream *os)
182
+ {
183
+ return os->file.rf->len;
184
+ }
185
+
186
+ static void ramo_flush_i(OutStream *os, const uchar *src, int len)
187
+ {
188
+ uchar *buffer;
189
+ RAMFile *rf = os->file.rf;
190
+ int buffer_number, buffer_offset, bytes_in_buffer, bytes_to_copy;
191
+ int src_offset;
192
+ off_t pointer = os->pointer;
193
+
194
+ buffer_number = (int)(pointer / BUFFER_SIZE);
195
+ buffer_offset = pointer % BUFFER_SIZE;
196
+ bytes_in_buffer = BUFFER_SIZE - buffer_offset;
197
+ bytes_to_copy = bytes_in_buffer < len ? bytes_in_buffer : len;
198
+
199
+ rf_extend_if_necessary(rf, buffer_number);
200
+
201
+ buffer = rf->buffers[buffer_number];
202
+ memcpy(buffer + buffer_offset, src, bytes_to_copy);
203
+
204
+ if (bytes_to_copy < len) {
205
+ src_offset = bytes_to_copy;
206
+ bytes_to_copy = len - bytes_to_copy;
207
+ buffer_number += 1;
208
+ rf_extend_if_necessary(rf, buffer_number);
209
+ buffer = rf->buffers[buffer_number];
210
+
211
+ memcpy(buffer, src + src_offset, bytes_to_copy);
212
+ }
213
+ os->pointer += len;
214
+
215
+ if (os->pointer > rf->len) {
216
+ rf->len = os->pointer;
217
+ }
218
+ }
219
+
220
+ static void ramo_seek_i(OutStream *os, off_t pos)
221
+ {
222
+ os->pointer = pos;
223
+ }
224
+
225
+ void ramo_reset(OutStream *os)
226
+ {
227
+ os_seek(os, 0);
228
+ os->file.rf->len = 0;
229
+ }
230
+
231
+ static void ramo_close_i(OutStream *os)
232
+ {
233
+ RAMFile *rf = os->file.rf;
234
+ DEREF(rf);
235
+ rf_close(rf);
236
+ }
237
+
238
+ void ramo_write_to(OutStream *os, OutStream *other_o)
239
+ {
240
+ int i, len;
241
+ RAMFile *rf = os->file.rf;
242
+ int last_buffer_number;
243
+ int last_buffer_offset;
244
+
245
+ os_flush(os);
246
+ last_buffer_number = (int) (rf->len / BUFFER_SIZE);
247
+ last_buffer_offset = rf->len % BUFFER_SIZE;
248
+ for (i = 0; i <= last_buffer_number; i++) {
249
+ len = (i == last_buffer_number ? last_buffer_offset : BUFFER_SIZE);
250
+ os_write_bytes(other_o, rf->buffers[i], len);
251
+ }
252
+ }
253
+
254
+ static const struct OutStreamMethods RAM_OUT_STREAM_METHODS = {
255
+ ramo_flush_i,
256
+ ramo_seek_i,
257
+ ramo_close_i
258
+ };
259
+
260
+ OutStream *ram_new_buffer()
261
+ {
262
+ RAMFile *rf = rf_new("");
263
+ OutStream *os = os_new();
264
+
265
+ DEREF(rf);
266
+ os->file.rf = rf;
267
+ os->pointer = 0;
268
+ os->m = &RAM_OUT_STREAM_METHODS;
269
+ return os;
270
+ }
271
+
272
+ void ram_destroy_buffer(OutStream *os)
273
+ {
274
+ rf_close(os->file.rf);
275
+ free(os);
276
+ }
277
+
278
+ static OutStream *ram_new_output(Store *store, const char *filename)
279
+ {
280
+ RAMFile *rf = (RAMFile *)h_get(store->dir.ht, filename);
281
+ OutStream *os = os_new();
282
+
283
+ if (rf == NULL) {
284
+ rf = rf_new(filename);
285
+ h_set(store->dir.ht, rf->name, rf);
286
+ }
287
+ REF(rf);
288
+ os->pointer = 0;
289
+ os->file.rf = rf;
290
+ os->m = &RAM_OUT_STREAM_METHODS;
291
+ return os;
292
+ }
293
+
294
+ static void rami_read_i(InStream *is, uchar *b, int len)
295
+ {
296
+ RAMFile *rf = is->file.rf;
297
+
298
+ int offset = 0;
299
+ int buffer_number, buffer_offset, bytes_in_buffer, bytes_to_copy;
300
+ int remainder = len;
301
+ off_t start = is->d.pointer;
302
+ uchar *buffer;
303
+
304
+ while (remainder > 0) {
305
+ buffer_number = (int) (start / BUFFER_SIZE);
306
+ buffer_offset = start % BUFFER_SIZE;
307
+ bytes_in_buffer = BUFFER_SIZE - buffer_offset;
308
+
309
+ if (bytes_in_buffer >= remainder) {
310
+ bytes_to_copy = remainder;
311
+ }
312
+ else {
313
+ bytes_to_copy = bytes_in_buffer;
314
+ }
315
+ buffer = rf->buffers[buffer_number];
316
+ memcpy(b + offset, buffer + buffer_offset, bytes_to_copy);
317
+ offset += bytes_to_copy;
318
+ start += bytes_to_copy;
319
+ remainder -= bytes_to_copy;
320
+ }
321
+
322
+ is->d.pointer += len;
323
+ }
324
+
325
+ static off_t rami_length_i(InStream *is)
326
+ {
327
+ return is->file.rf->len;
328
+ }
329
+
330
+ static void rami_seek_i(InStream *is, off_t pos)
331
+ {
332
+ is->d.pointer = pos;
333
+ }
334
+
335
+ static void rami_close_i(InStream *is)
336
+ {
337
+ RAMFile *rf = is->file.rf;
338
+ DEREF(rf);
339
+ rf_close(rf);
340
+ }
341
+
342
+ static const struct InStreamMethods RAM_IN_STREAM_METHODS = {
343
+ rami_read_i,
344
+ rami_seek_i,
345
+ rami_length_i,
346
+ rami_close_i
347
+ };
348
+
349
+ static InStream *ram_open_input(Store *store, const char *filename)
350
+ {
351
+ RAMFile *rf = (RAMFile *)h_get(store->dir.ht, filename);
352
+ InStream *is = NULL;
353
+
354
+ if (rf == NULL) {
355
+ /*
356
+ Hash *ht = store->dir.ht;
357
+ int i;
358
+ printf("\nlooking for %s, %ld\n", filename, str_hash(filename));
359
+ for (i = 0; i <= ht->mask; i++) {
360
+ if (ht->table[i].value)
361
+ printf("%s, %ld -- %ld\n", (char *)ht->table[i].key,
362
+ str_hash(ht->table[i].key), ht->table[i].hash);
363
+ }
364
+ */
365
+ RAISE(FILE_NOT_FOUND_ERROR,
366
+ "tried to open \"%s\" but it doesn't exist", filename);
367
+ }
368
+ REF(rf);
369
+ is = is_new();
370
+ is->file.rf = rf;
371
+ is->d.pointer = 0;
372
+ is->m = &RAM_IN_STREAM_METHODS;
373
+
374
+ return is;
375
+ }
376
+
377
+ #define LOCK_OBTAIN_TIMEOUT 5
378
+
379
+ static int ram_lock_obtain(Lock *lock)
380
+ {
381
+ int ret = true;
382
+ if (ram_exists(lock->store, lock->name))
383
+ ret = false;
384
+ ram_touch(lock->store, lock->name);
385
+ return ret;
386
+ }
387
+
388
+ static int ram_lock_is_locked(Lock *lock)
389
+ {
390
+ return ram_exists(lock->store, lock->name);
391
+ }
392
+
393
+ static void ram_lock_release(Lock *lock)
394
+ {
395
+ ram_remove(lock->store, lock->name);
396
+ }
397
+
398
+ static Lock *ram_open_lock_i(Store *store, const char *lockname)
399
+ {
400
+ Lock *lock = ALLOC(Lock);
401
+ char lname[100];
402
+ snprintf(lname, 100, "%s%s.lck", LOCK_PREFIX, lockname);
403
+ lock->name = estrdup(lname);
404
+ lock->store = store;
405
+ lock->obtain = &ram_lock_obtain;
406
+ lock->release = &ram_lock_release;
407
+ lock->is_locked = &ram_lock_is_locked;
408
+ return lock;
409
+ }
410
+
411
+ static void ram_close_lock_i(Lock *lock)
412
+ {
413
+ free(lock->name);
414
+ free(lock);
415
+ }
416
+
417
+
418
+ Store *open_ram_store()
419
+ {
420
+ Store *new_store = store_new();
421
+
422
+ new_store->dir.ht = h_new_str(NULL, rf_close);
423
+ new_store->touch = &ram_touch;
424
+ new_store->exists = &ram_exists;
425
+ new_store->remove = &ram_remove;
426
+ new_store->rename = &ram_rename;
427
+ new_store->count = &ram_count;
428
+ new_store->clear = &ram_clear;
429
+ new_store->clear_all = &ram_clear_all;
430
+ new_store->clear_locks = &ram_clear_locks;
431
+ new_store->length = &ram_length;
432
+ new_store->each = &ram_each;
433
+ new_store->new_output = &ram_new_output;
434
+ new_store->open_input = &ram_open_input;
435
+ new_store->open_lock_i = &ram_open_lock_i;
436
+ new_store->close_lock_i = &ram_close_lock_i;
437
+ new_store->close_i = &ram_close_i;
438
+ return new_store;
439
+ }
440
+
441
+ struct CopyFileArg
442
+ {
443
+ Store *to_store, *from_store;
444
+ };
445
+
446
+ static void copy_files(const char *fname, void *arg)
447
+ {
448
+ struct CopyFileArg *cfa = (struct CopyFileArg *)arg;
449
+ OutStream *os = cfa->to_store->new_output(cfa->to_store, fname);
450
+ InStream *is = cfa->from_store->open_input(cfa->from_store, fname);
451
+ int len = (int)is_length(is);
452
+ uchar *buffer = ALLOC_N(uchar, len + 1);
453
+
454
+ is_read_bytes(is, buffer, len);
455
+ os_write_bytes(os, buffer, len);
456
+
457
+ is_close(is);
458
+ os_close(os);
459
+ free(buffer);
460
+ }
461
+
462
+ Store *open_ram_store_and_copy(Store *from_store, bool close_dir)
463
+ {
464
+ Store *store = open_ram_store();
465
+ struct CopyFileArg cfa;
466
+ cfa.to_store = store;
467
+ cfa.from_store = from_store;
468
+
469
+ from_store->each(from_store, &copy_files, &cfa);
470
+
471
+ if (close_dir) {
472
+ store_deref(from_store);
473
+ }
474
+
475
+ return store;
476
+ }