OSDN Git Service

implement parser for rfc733 format date text.
[bbk/bchan.git] / src / cache.c
1 /*
2  * cache.c
3  *
4  * Copyright (c) 2009-2011 project bchan
5  *
6  * This software is provided 'as-is', without any express or implied
7  * warranty. In no event will the authors be held liable for any damages
8  * arising from the use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not
15  *    claim that you wrote the original software. If you use this software
16  *    in a product, an acknowledgment in the product documentation would be
17  *    appreciated but is not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  *    misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source
23  *    distribution.
24  *
25  */
26
27 #include        <basic.h>
28 #include        <bstdlib.h>
29 #include        <bstdio.h>
30 #include        <bstring.h>
31 #include        <errcode.h>
32 #include        <btron/btron.h>
33 #include        <bsys/queue.h>
34
35 #include    "cache.h"
36 #include    "residhash.h"
37 #include    "resindexhash.h"
38 #include    "wordlist.h"
39
40 typedef struct datcache_data_t_ datcache_data_t;
41
42 struct datcache_data_t_ {
43         QUEUE queue;
44         UB *data;
45         W len;
46 };
47
48 #define DATCACHE_FLAG_DATAPPENDED 0x00000001
49 #define DATCACHE_FLAG_DATRESETED 0x00000002
50 #define DATCACHE_FLAG_IDINFOUPDATED 0x00000004
51 #define DATCACHE_FLAG_INDEXINFOUPDATED 0x00000008
52 #define DATCACHE_FLAG_LATESTHEADERUPDATED 0x00000010
53 #define DATCACHE_FLAG_NGWORDINFOUPDATED 0x00000020
54
55 struct datcache_t_ {
56         UW flag;
57         W fd;
58         STIME mtime_open;
59         ID semid;
60         datcache_data_t datalist;
61         W s_datsize;
62         W recsize_open;
63         datcache_datareadcontext_t *context;
64         UB *retrinfo;
65         W retrinfo_len;
66         UB *host;
67         W host_len;
68         UB *board;
69         W board_len;
70         UB *thread;
71         W thread_len;
72         UB *latestheader;
73         W latestheader_len;
74         residhash_t residhash;
75         resindexhash_t resindexhash;
76         wordlist_t ngwordlist;
77 };
78
79 struct datcache_datareadcontext_t_ {
80         datcache_t *datcache;
81         datcache_data_t *current;
82         W index;
83 };
84
85 struct datcache_ngwordreadcontext_t_ {
86         wordlist_iterator_t iter;
87 };
88
89 LOCAL datcache_data_t* datcache_data_next(datcache_data_t *data)
90 {
91         return (datcache_data_t*)data->queue.next;
92 }
93
94 LOCAL datcache_data_t* datcache_data_new(UB *data, W len)
95 {
96         datcache_data_t *cache_data;
97
98         cache_data = malloc(sizeof(datcache_data_t));
99         if (cache_data == NULL) {
100                 return NULL;
101         }
102         cache_data->data = malloc(sizeof(UB)*len);
103         if (cache_data->data == NULL) {
104                 free(cache_data);
105                 return NULL;
106         }
107         memcpy(cache_data->data, data, len);
108         cache_data->len = len;
109
110         return cache_data;
111 }
112
113 LOCAL VOID datcache_data_delete(datcache_data_t *cache_data)
114 {
115         QueRemove(&(cache_data->queue));
116         if (cache_data->data != NULL) {
117                 free(cache_data->data);
118         }
119         free(cache_data);
120 }
121
122 LOCAL VOID datcache_setappendedflag(datcache_t *cache)
123 {
124         cache->flag = cache->flag | DATCACHE_FLAG_DATAPPENDED;
125 }
126
127 LOCAL VOID datcache_clearappendedflag(datcache_t *cache)
128 {
129         cache->flag = cache->flag & ~DATCACHE_FLAG_DATAPPENDED;
130 }
131
132 LOCAL Bool datcache_issetappendedflag(datcache_t *cache)
133 {
134         if ((cache->flag & DATCACHE_FLAG_DATAPPENDED) == 0) {
135                 return False;
136         }
137         return True;
138 }
139
140 LOCAL VOID datcache_setresetedflag(datcache_t *cache)
141 {
142         cache->flag = cache->flag | DATCACHE_FLAG_DATRESETED;
143 }
144
145 LOCAL Bool datcache_issetresetedflag(datcache_t *cache)
146 {
147         if ((cache->flag & DATCACHE_FLAG_DATRESETED) == 0) {
148                 return False;
149         }
150         return True;
151 }
152
153 LOCAL VOID datcache_setidinfoupdatedflag(datcache_t *cache)
154 {
155         cache->flag = cache->flag | DATCACHE_FLAG_IDINFOUPDATED;
156 }
157
158 LOCAL Bool datcache_issetidinfoupdatedflag(datcache_t *cache)
159 {
160         if ((cache->flag & DATCACHE_FLAG_IDINFOUPDATED) == 0) {
161                 return False;
162         }
163         return True;
164 }
165
166 LOCAL VOID datcache_setindexinfoupdatedflag(datcache_t *cache)
167 {
168         cache->flag = cache->flag | DATCACHE_FLAG_INDEXINFOUPDATED;
169 }
170
171 LOCAL Bool datcache_issetindexinfoupdatedflag(datcache_t *cache)
172 {
173         if ((cache->flag & DATCACHE_FLAG_INDEXINFOUPDATED) == 0) {
174                 return False;
175         }
176         return True;
177 }
178
179 LOCAL VOID datcache_setngwordinfoupdatedflag(datcache_t *cache)
180 {
181         cache->flag = cache->flag | DATCACHE_FLAG_NGWORDINFOUPDATED;
182 }
183
184 LOCAL Bool datcache_issetngwordinfoupdatedflag(datcache_t *cache)
185 {
186         if ((cache->flag & DATCACHE_FLAG_NGWORDINFOUPDATED) == 0) {
187                 return False;
188         }
189         return True;
190 }
191
192 LOCAL VOID datcache_setlatestheaderupdatedflag(datcache_t *cache)
193 {
194         cache->flag = cache->flag | DATCACHE_FLAG_LATESTHEADERUPDATED;
195 }
196
197 LOCAL Bool datcache_issetlatestheaderupdatedflag(datcache_t *cache)
198 {
199         if ((cache->flag & DATCACHE_FLAG_LATESTHEADERUPDATED) == 0) {
200                 return False;
201         }
202         return True;
203 }
204
205 EXPORT W datcache_appenddata(datcache_t *cache, UB *data, W len)
206 {
207         datcache_data_t *cache_data;
208         W err;
209
210         err = wai_sem(cache->semid, T_FOREVER);
211         if (err < 0) {
212                 return err;
213         }
214
215         if (cache->context != NULL) {
216                 sig_sem(cache->semid);
217                 return -1;
218         }
219
220         cache_data = datcache_data_new(data, len);
221         if (cache_data == NULL) {
222                 sig_sem(cache->semid);
223                 return -1; /* TODO */
224         }
225         QueInsert(&(cache_data->queue), &(cache->datalist.queue));
226         cache->s_datsize += len;
227
228         datcache_setappendedflag(cache);
229
230         sig_sem(cache->semid);
231
232         return 0; /* TODO */
233 }
234
235 EXPORT VOID datcache_cleardata(datcache_t *cache)
236 {
237         datcache_data_t *cache_data;
238         Bool ok;
239         W err;
240
241         err = wai_sem(cache->semid, T_FOREVER);
242         if (err < 0) {
243                 return;
244         }
245
246         if (cache->context != NULL) {
247                 sig_sem(cache->semid);
248                 return;
249         }
250
251         for (;;) {
252                 ok = isQueEmpty(&(cache->datalist.queue));
253                 if (ok == True) {
254                         break;
255                 }
256                 cache_data = (datcache_data_t*)cache->datalist.queue.next;
257                 datcache_data_delete(cache_data);
258         }
259         free(cache->datalist.data);
260
261         cache->datalist.data = NULL;
262         cache->datalist.len = 0;
263         cache->s_datsize = 0;
264
265         datcache_clearappendedflag(cache);
266         datcache_setresetedflag(cache);
267
268         sig_sem(cache->semid);
269 }
270
271 EXPORT Bool datcache_datareadcontext_nextdata(datcache_datareadcontext_t *context, UB **bin, W *len)
272 {
273         datcache_data_t *next;
274
275         if (context->current == NULL) {
276                 return False;
277         }
278
279         *bin = context->current->data + context->index;
280         *len = context->current->len - context->index;
281
282         next = datcache_data_next(context->current);
283         if (next == &(context->datcache->datalist)) {
284                 next = NULL;
285         }
286         context->current = next;
287         context->index = 0;
288
289         return True;
290 }
291
292 LOCAL datcache_datareadcontext_t* datcache_datareadcontext_new(datcache_t *cache)
293 {
294         datcache_datareadcontext_t *context;
295
296         context = malloc(sizeof(datcache_datareadcontext_t*));
297         if (context == NULL) {
298                 return NULL;
299         }
300         context->datcache = cache;
301
302         return context;
303 }
304
305 LOCAL VOID datcache_datareadcontext_delete(datcache_datareadcontext_t *context)
306 {
307         free(context);
308 }
309
310 EXPORT datcache_datareadcontext_t* datcache_startdataread(datcache_t *cache, W start)
311 {
312         datcache_datareadcontext_t *context;
313         datcache_data_t *cache_data;
314         W err,dest;
315
316         err = wai_sem(cache->semid, T_FOREVER);
317         if (err < 0) {
318                 return NULL;
319         }
320
321         if (cache->context != NULL) {
322                 sig_sem(cache->semid);
323                 return NULL;
324         }
325
326         context = datcache_datareadcontext_new(cache);
327         if (context == NULL) {
328                 return NULL;
329         }
330         cache->context = context;
331
332         if (start >= cache->s_datsize) {
333                 context->current = NULL;
334                 context->index = 0;
335                 return context;
336         }
337
338         cache_data = &(cache->datalist);
339         dest = start;
340         for (;;) {
341                 if (dest < cache_data->len) {
342                         break;
343                 }
344                 dest -= cache_data->len;
345                 cache_data = datcache_data_next(cache_data);
346         }
347
348         context->current = cache_data;
349         context->index = dest;
350
351         return context;
352 }
353
354 EXPORT VOID datcache_enddataread(datcache_t *cache, datcache_datareadcontext_t *context)
355 {
356         cache->context = NULL;
357         datcache_datareadcontext_delete(context);
358
359         sig_sem(cache->semid);
360 }
361
362 EXPORT VOID datcache_getlatestheader(datcache_t *cache, UB **header, W *len)
363 {
364         *header = cache->latestheader;
365         *len = cache->latestheader_len;
366 }
367
368 EXPORT W datcache_updatelatestheader(datcache_t *cache, UB *header, W len)
369 {
370         UB *latestheader0;
371
372         latestheader0 = realloc(cache->latestheader, len + 1);
373         if (latestheader0 == NULL) {
374                 return -1;
375         }
376
377         cache->latestheader = latestheader0;
378         memcpy(cache->latestheader, header, len);
379         cache->latestheader_len = len;
380         cache->latestheader[cache->latestheader_len] = '\0';
381
382         datcache_setlatestheaderupdatedflag(cache);
383
384         return 0;
385 }
386
387 EXPORT VOID datcache_gethost(datcache_t *cache, UB **host, W *len)
388 {
389         *host = cache->host;
390         *len = cache->host_len;
391 }
392
393 EXPORT VOID datcache_getborad(datcache_t *cache, UB **borad, W *len)
394 {
395         *borad = cache->board;
396         *len = cache->board_len;
397 }
398
399 EXPORT VOID datcache_getthread(datcache_t *cache, UB **thread, W *len)
400 {
401         *thread = cache->thread;
402         *len = cache->thread_len;
403 }
404
405 LOCAL VOID datcache_setupretrinfo(datcache_t *cache, UB *retrinfo, W len)
406 {
407         W i=0;
408
409         cache->retrinfo = retrinfo;
410         cache->retrinfo_len = len;
411         cache->host = NULL;
412         cache->host_len = 0;
413         cache->board = NULL;
414         cache->board_len = 0;
415         cache->thread = NULL;
416         cache->thread_len = 0;
417
418         if (cache->retrinfo == NULL) {
419                 return;
420         }
421
422         cache->host = cache->retrinfo;
423         for (; i < len; i++) {
424                 if (cache->retrinfo[i] == '\n') {
425                         break;
426                 }
427                 cache->host_len++;
428         }
429
430         i++;
431         cache->board = cache->retrinfo + i;
432         for (; i < len; i++) {
433                 if (cache->retrinfo[i] == '\n') {
434                         break;
435                 }
436                 cache->board_len++;
437         }
438
439         i++;
440         cache->thread = cache->retrinfo + i;
441         for (; i < len; i++) {
442                 if (cache->retrinfo[i] == '\n') {
443                         break;
444                 }
445                 cache->thread_len++;
446         }
447 }
448
449 LOCAL W datcache_preparerec_forwritefile(W fd, W rectype, W subtype, Bool need_truncute)
450 {
451         W err;
452
453         err = fnd_rec(fd, F_TOPEND, 1 << rectype, subtype, NULL);
454         if (err == ER_REC) {
455                 err = ins_rec(fd, NULL, 0, rectype, subtype, 0);
456                 if (err < 0) {
457                         return -1;
458                 }
459                 err = see_rec(fd, -1, 0, NULL);
460                 if (err < 0) {
461                         return -1;
462                 }
463         } else if (err < 0) {
464                 return -1; /* TODO */
465         } else {
466                 if (need_truncute == True) {
467                         err = trc_rec(fd, 0);
468                         if (err < 0) {
469                                 return -1;
470                         }
471                 }
472         }
473
474         return 0; /* TODO */
475 }
476
477 LOCAL W datcache_deleterec_forwritefile(W fd, W rectype, W subtype)
478 {
479         W err;
480
481         err = fnd_rec(fd, F_TOPEND, 1 << rectype, subtype, NULL);
482         if (err == ER_REC) {
483                 return 0; /* TODO */
484         } else if (err < 0) {
485                 return -1; /* TODO */
486         }
487
488         err = del_rec(fd);
489         if (err < 0) {
490                 return -1; /* TODO */
491         }
492
493         return 0; /* TODO */
494 }
495
496 EXPORT W datcache_datasize(datcache_t *cache)
497 {
498         return cache->s_datsize;
499 }
500
501 LOCAL W datcache_writefile_latestheader(datcache_t *cache)
502 {
503         W err;
504
505         if (cache->latestheader_len <= 0) {
506                 return 0;
507         }
508
509         err = datcache_preparerec_forwritefile(cache->fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_HEADER, True);
510         if (err < 0) {
511                 return err;
512         }
513         err = wri_rec(cache->fd, -1, cache->latestheader, cache->latestheader_len, NULL, NULL, 0);
514         if (err < 0) {
515                 return err;
516         }
517
518         return 0;
519 }
520
521 LOCAL W datcache_writefile_residhash(datcache_t *cache)
522 {
523         Bool cont, updated;
524         W err, len;
525         residhash_iterator_t iter;
526         TC *idstr;
527         W idstr_len;
528         UW attr;
529         COLOR color;
530         UB bin[10];
531
532         updated = datcache_issetidinfoupdatedflag(cache);
533         if (updated == False) {
534                 return 0;
535         }
536
537         len = residhash_datanum(&cache->residhash);
538         if (len > 0) {
539                 err = datcache_preparerec_forwritefile(cache->fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_RESIDINFO, True);
540                 if (err < 0) {
541                         return err;
542                 }
543                 residhash_iterator_initialize(&iter, &cache->residhash);
544                 for (;;) {
545                         cont = residhash_iterator_next(&iter, &idstr, &idstr_len, &attr, &color);
546                         if (cont == False) {
547                                 break;
548                         }
549                         *(UH*)bin = idstr_len * 2;
550                         err = wri_rec(cache->fd, -1, bin, 2, NULL, NULL, 0);
551                         if (err < 0) {
552                                 return err;
553                         }
554                         err = wri_rec(cache->fd, -1, (UB*)idstr, idstr_len * 2, NULL, NULL, 0);
555                         if (err < 0) {
556                                 return err;
557                         }
558                         *(UH*)bin = 8;
559                         *(UW*)(bin + 2) = attr;
560                         *(COLOR*)(bin + 2 + 4) = color;
561                         err = wri_rec(cache->fd, -1, bin, 10, NULL, NULL, 0);
562                         if (err < 0) {
563                                 return err;
564                         }
565                 }
566                 residhash_iterator_finalize(&iter);
567         } else {
568                 err = datcache_deleterec_forwritefile(cache->fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_RESIDINFO);
569                 if (err < 0) {
570                         return err;
571                 }
572         }
573
574         return 0;
575 }
576
577 LOCAL W datcache_writefile_resindexhash(datcache_t *cache)
578 {
579         Bool cont, updated;
580         W err, len, index;
581         resindexhash_iterator_t iter;
582         UW attr;
583         COLOR color;
584         UB bin[10];
585
586         updated = datcache_issetindexinfoupdatedflag(cache);
587         if (updated == False) {
588                 return 0;
589         }
590
591         len = resindexhash_datanum(&cache->resindexhash);
592         if (len > 0) {
593                 err = datcache_preparerec_forwritefile(cache->fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_RESINDEXINFO, True);
594                 if (err < 0) {
595                         return err;
596                 }
597                 resindexhash_iterator_initialize(&iter, &cache->resindexhash);
598                 for (;;) {
599                         cont = resindexhash_iterator_next(&iter, &index, &attr, &color);
600                         if (cont == False) {
601                                 break;
602                         }
603                         if (index > 65535) {
604                                 continue;
605                         }
606                         *(UH*)bin = 2;
607                         err = wri_rec(cache->fd, -1, bin, 2, NULL, NULL, 0);
608                         if (err < 0) {
609                                 return err;
610                         }
611                         *(UH*)bin = index & 0xFFFF;
612                         err = wri_rec(cache->fd, -1, bin, 2, NULL, NULL, 0);
613                         if (err < 0) {
614                                 return err;
615                         }
616                         *(UH*)bin = 8;
617                         *(UW*)(bin + 2) = attr;
618                         *(COLOR*)(bin + 2 + 4) = color;
619                         err = wri_rec(cache->fd, -1, bin, 10, NULL, NULL, 0);
620                         if (err < 0) {
621                                 return err;
622                         }
623                 }
624                 resindexhash_iterator_finalize(&iter);
625         } else {
626                 err = datcache_deleterec_forwritefile(cache->fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_RESINDEXINFO);
627                 if (err < 0) {
628                         return err;
629                 }
630         }
631
632         return 0;
633 }
634
635 LOCAL W datcache_writefile_ngwordlist(datcache_t *cache)
636 {
637         Bool cont, updated, empty;
638         W err;
639         wordlist_iterator_t iter;
640         TC *str;
641         W str_len;
642         UB bin[10];
643
644         updated = datcache_issetngwordinfoupdatedflag(cache);
645         if (updated == False) {
646                 return 0;
647         }
648
649         empty = wordlist_isempty(&cache->ngwordlist);
650         if (empty == False) {
651                 err = datcache_preparerec_forwritefile(cache->fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_NGWORDINFO, True);
652                 if (err < 0) {
653                         wordlist_iterator_finalize(&iter);
654                         return err;
655                 }
656
657                 wordlist_iterator_initialize(&iter, &cache->ngwordlist);
658                 for (;;) {
659                         cont = wordlist_iterator_next(&iter, &str, &str_len);
660                         if (cont == False) {
661                                 break;
662                         }
663
664                         *(UH*)bin = str_len * 2;
665                         err = wri_rec(cache->fd, -1, bin, 2, NULL, NULL, 0);
666                         if (err < 0) {
667                                 return err;
668                         }
669                         err = wri_rec(cache->fd, -1, (UB*)str, str_len * 2, NULL, NULL, 0);
670                         if (err < 0) {
671                                 return err;
672                         }
673                         *(UH*)bin = 2;
674                         *(UH*)(bin + 2) = 0;
675                         err = wri_rec(cache->fd, -1, bin, 4, NULL, NULL, 0);
676                         if (err < 0) {
677                                 return err;
678                         }
679                 }
680                 wordlist_iterator_finalize(&iter);
681         } else {
682                 err = datcache_deleterec_forwritefile(cache->fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_NGWORDINFO);
683                 if (err < 0) {
684                         return err;
685                 }
686         }
687
688         return 0;
689 }
690
691 LOCAL W datcache_writedat_appended(datcache_t *cache)
692 {
693         W err, size;
694         F_STATE fstate;
695         datcache_data_t *cache_data;
696
697         err = datcache_preparerec_forwritefile(cache->fd, DATCACHE_RECORDTYPE_MAIN, 0, False);
698         if (err < 0) {
699                 return err;
700         }
701
702         err = loc_rec(cache->fd, F_LOCK);
703         if (err < 0) {
704                 return err;
705         }
706
707         err = ofl_sts(cache->fd, NULL, &fstate, NULL);
708         if (err < 0) {
709                 loc_rec(cache->fd, F_UNLOCK);
710                 return err;
711         }
712         if (cache->mtime_open != fstate.f_mtime) {
713                 loc_rec(cache->fd, F_UNLOCK);
714                 return 0;
715         }
716         err = rea_rec(cache->fd, 0, NULL, 0, &size, NULL);
717         if (err < 0) {
718                 loc_rec(cache->fd, F_UNLOCK);
719                 return err;
720         }
721         if (cache->recsize_open != size) {
722                 loc_rec(cache->fd, F_UNLOCK);
723                 return 0;
724         }
725
726         cache_data = datcache_data_next(&(cache->datalist));
727         for (;;) {
728                 if (cache_data == &(cache->datalist)) {
729                         break;
730                 }
731
732                 err = wri_rec(cache->fd, -1, cache_data->data, cache_data->len, NULL, NULL, 0);
733                 if (err < 0) {
734                         loc_rec(cache->fd, F_UNLOCK);
735                         return err;
736                 }
737
738                 cache_data = datcache_data_next(cache_data);
739         }
740
741         loc_rec(cache->fd, F_UNLOCK);
742
743         return 0;
744 }
745
746 LOCAL W datcache_writedat_allupdateded(datcache_t *cache)
747 {
748         W err;
749         datcache_data_t *cache_data;
750
751         if (cache->s_datsize <= 0) {
752                 return 0;
753         }
754
755         err = datcache_preparerec_forwritefile(cache->fd, DATCACHE_RECORDTYPE_MAIN, 0, True);
756         if (err < 0) {
757                 return err;
758         }
759
760         err = loc_rec(cache->fd, F_LOCK);
761         if (err < 0) {
762                 return err;
763         }
764
765         cache_data = &(cache->datalist);
766         for (;;) {
767                 err = wri_rec(cache->fd, -1, cache_data->data, cache_data->len, NULL, NULL, 0);
768                 if (err < 0) {
769                         loc_rec(cache->fd, F_UNLOCK);
770                         return err;
771                 }
772                 cache_data = datcache_data_next(cache_data);
773                 if (cache_data == &(cache->datalist)) {
774                         break;
775                 }
776         }
777
778         loc_rec(cache->fd, F_UNLOCK);
779
780         return 0;
781 }
782
783 EXPORT W datcache_writefile(datcache_t *cache)
784 {
785         W err;
786         Bool appended, reseted, header_updated;
787
788         appended = datcache_issetappendedflag(cache);
789         reseted = datcache_issetresetedflag(cache);
790         header_updated = datcache_issetlatestheaderupdatedflag(cache);
791
792         if (appended == True) {
793                 if (reseted == True) {
794                         err = datcache_writedat_allupdateded(cache);
795                 } else {
796                         err = datcache_writedat_appended(cache);
797                 }
798                 if (err < 0) {
799                         return err;
800                 }
801         }
802
803         if (header_updated == True) {
804                 err = datcache_writefile_latestheader(cache);
805                 if (err < 0) {
806                         return err;
807                 }
808         }
809
810         err = datcache_writefile_residhash(cache);
811         if (err < 0) {
812                 return err;
813         }
814         err = datcache_writefile_resindexhash(cache);
815         if (err < 0) {
816                 return err;
817         }
818         err = datcache_writefile_ngwordlist(cache);
819         if (err < 0) {
820                 return err;
821         }
822
823         return 0;
824 }
825
826 EXPORT W datcache_addresiddata(datcache_t *cache, TC *idstr, W idstr_len, UW attr, COLOR color)
827 {
828         datcache_setidinfoupdatedflag(cache);
829         return residhash_adddata(&cache->residhash, idstr, idstr_len, attr, color);
830 }
831
832 EXPORT W datcache_searchresiddata(datcache_t *cache, TC *idstr, W idstr_len, UW *attr, COLOR *color)
833 {
834         return residhash_searchdata(&cache->residhash, idstr, idstr_len, attr, color);
835 }
836
837 EXPORT VOID datcache_removeresiddata(datcache_t *cache, TC *idstr, W idstr_len)
838 {
839         datcache_setidinfoupdatedflag(cache);
840         residhash_removedata(&cache->residhash, idstr, idstr_len);
841 }
842
843 EXPORT W datcache_addresindexdata(datcache_t *cache, W index, UW attr, COLOR color)
844 {
845         datcache_setindexinfoupdatedflag(cache);
846         return resindexhash_adddata(&cache->resindexhash, index, attr, color);
847 }
848
849 EXPORT W datcache_searchresindexdata(datcache_t *cache, W index, UW *attr, COLOR *color)
850 {
851         return resindexhash_searchdata(&cache->resindexhash, index, attr, color);
852 }
853
854 EXPORT VOID datcache_removeresindexdata(datcache_t *cache, W index)
855 {
856         datcache_setindexinfoupdatedflag(cache);
857         resindexhash_removedata(&cache->resindexhash, index);
858 }
859
860 EXPORT W datcache_appendngword(datcache_t *cache, TC *str, W len)
861 {
862         datcache_setngwordinfoupdatedflag(cache);
863         return wordlist_appendword(&cache->ngwordlist, str, len);
864 }
865
866 EXPORT VOID datcache_removengword(datcache_t *cache, TC *str, W len)
867 {
868         datcache_setngwordinfoupdatedflag(cache);
869         wordlist_removeword(&cache->ngwordlist, str, len);
870 }
871
872 EXPORT Bool datcache_checkngwordexist(datcache_t *cache, TC *str, W len)
873 {
874         return wordlist_checkexistbyword(&cache->ngwordlist, str, len);
875 }
876
877 EXPORT datcache_ngwordreadcontext_t* datcache_startngwordread(datcache_t *cache)
878 {
879         datcache_ngwordreadcontext_t *context;
880
881         context = malloc(sizeof(datcache_ngwordreadcontext_t));
882         if (context == NULL) {
883                 return NULL;
884         }
885         wordlist_iterator_initialize(&context->iter, &cache->ngwordlist);
886         return context;
887 }
888
889 EXPORT VOID datcache_endngwordread(datcache_t *cache, datcache_ngwordreadcontext_t *context)
890 {
891         wordlist_iterator_finalize(&context->iter);
892         free(context);
893 }
894
895 EXPORT Bool datcache_ngwordreadcontext_nextdata(datcache_ngwordreadcontext_t *context, TC **str, W *len)
896 {
897         return wordlist_iterator_next(&context->iter, str, len);
898 }
899
900 LOCAL W datcache_getrec_fromfile(W fd, W rectype, W subtype, UB **data, W *size)
901 {
902         W err, size0;
903         UB *data0;
904
905         err = fnd_rec(fd, F_TOPEND, 1 << rectype, subtype, NULL);
906         if (err == ER_REC) {
907                 *data = NULL;
908                 *size = 0;
909                 return 0;
910         }
911         if (err < 0) {
912                 return -1; /* TODO */
913         }
914         err = rea_rec(fd, 0, NULL, 0, &size0, NULL);
915         if (err < 0) {
916                 return -1; /* TODO */
917         }
918         if (size0 == 0) {
919                 *data = NULL;
920                 *size = 0;
921                 return 0;
922         }
923         data0 = malloc(size0);
924         if (data0 == NULL) {
925                 return -1; /* TODO */
926         }
927         err = rea_rec(fd, 0, data0, size0, NULL, NULL);
928         if (err < 0) {
929                 free(data0);
930                 return -1; /* TODO */
931         }
932
933         *data = data0;
934         *size = size0;
935
936         return 0;
937 }
938
939 LOCAL W datcache_getdat_fromfile(W fd, UB **data, W *size)
940 {
941         return datcache_getrec_fromfile(fd, DATCACHE_RECORDTYPE_MAIN, 0, data, size);
942 }
943
944 LOCAL W datcache_getretrinfo_fromfile(W fd, UB **data, W *size)
945 {
946         return datcache_getrec_fromfile(fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_RETRIEVE, data, size);
947 }
948
949 LOCAL W datcache_getheader_fromfile(W fd, UB **data, W *size)
950 {
951         return datcache_getrec_fromfile(fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_HEADER, data, size);
952 }
953
954 LOCAL W datcache_readresidinfo(datcache_t *cache)
955 {
956         UB *recdata;
957         W recsize, err = 0, idstr_len, i;
958         TC *idstr;
959         UW attr;
960         COLOR color;
961         UH chunksize;
962
963         err = datcache_getrec_fromfile(cache->fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_RESIDINFO, &recdata, &recsize);
964         if (err < 0) {
965                 return err;
966         }
967
968         if (recsize == 0) {
969                 return 0; /* TODO */
970         }
971
972         for (i = 0; i < recsize; ) {
973                 chunksize = *(UH*)(recdata + i);
974                 i += 2;
975                 idstr = (TC*)(recdata + i);
976                 idstr_len = chunksize / 2;
977                 i += chunksize;
978                 chunksize = *(UH*)(recdata + i);
979                 i += 2;
980                 if (chunksize >= 4) {
981                         attr = *(UW*)(recdata + i);
982                         if (chunksize >= 8) {
983                                 color = *(COLOR*)(recdata + i + 4);
984                         } else {
985                                 color = -1;
986                         }
987                         err = residhash_adddata(&cache->residhash, idstr, idstr_len, attr, color);
988                         if (err < 0) {
989                                 break;
990                         }
991                 }
992                 i += chunksize;
993         }
994
995         free(recdata);
996
997         return err;
998 }
999
1000 LOCAL W datcache_readresindexinfo(datcache_t *cache)
1001 {
1002         UB *recdata;
1003         W recsize, err = 0, i, index;
1004         UW attr;
1005         COLOR color;
1006         UH chunksize;
1007
1008         err = datcache_getrec_fromfile(cache->fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_RESINDEXINFO, &recdata, &recsize);
1009         if (err < 0) {
1010                 return err;
1011         }
1012
1013         if (recsize == 0) {
1014                 return 0; /* TODO */
1015         }
1016
1017         for (i = 0; i < recsize; ) {
1018                 chunksize = *(UH*)(recdata + i);
1019                 i += 2;
1020                 index = *(UH*)(recdata + i);
1021                 i += chunksize;
1022                 chunksize = *(UH*)(recdata + i);
1023                 i += 2;
1024                 if (chunksize >= 4) {
1025                         attr = *(UW*)(recdata + i);
1026                         if (chunksize >= 8) {
1027                                 color = *(COLOR*)(recdata + i + 4);
1028                         } else {
1029                                 color = -1;
1030                         }
1031                         err = resindexhash_adddata(&cache->resindexhash, index, attr, color);
1032                         if (err < 0) {
1033                                 break;
1034                         }
1035                 }
1036                 i += chunksize;
1037         }
1038
1039         free(recdata);
1040
1041         return err;
1042 }
1043
1044 LOCAL W datcache_readngwordinfo(datcache_t *cache)
1045 {
1046         UB *recdata;
1047         W recsize, err = 0, str_len, i;
1048         TC *str;
1049         UH chunksize;
1050
1051         err = datcache_getrec_fromfile(cache->fd, DATCACHE_RECORDTYPE_INFO, DATCACHE_RECORDSUBTYPE_NGWORDINFO, &recdata, &recsize);
1052         if (err < 0) {
1053                 return err;
1054         }
1055
1056         if (recsize == 0) {
1057                 return 0; /* TODO */
1058         }
1059
1060         for (i = 0; i < recsize; ) {
1061                 chunksize = *(UH*)(recdata + i);
1062                 i += 2;
1063                 str = (TC*)(recdata + i);
1064                 str_len = chunksize / 2;
1065                 i += chunksize;
1066                 chunksize = *(UH*)(recdata + i);
1067                 i += 2;
1068                 err = wordlist_appendword(&cache->ngwordlist, str, str_len);
1069                 if (err < 0) {
1070                         break;
1071                 }
1072                 i += chunksize;
1073         }
1074
1075         free(recdata);
1076
1077         return err;
1078 }
1079
1080 EXPORT datcache_t* datcache_new(VID vid)
1081 {
1082         datcache_t *cache;
1083         ID semid;
1084         W fd,err;
1085         W size, retrinfo_len, header_len;
1086         UB *rawdat, *retrinfo, *header;
1087         F_STATE fstate;
1088
1089         fd = oopn_obj(vid, NULL, F_READ|F_WRITE, NULL);
1090         if (fd < 0) {
1091                 return NULL;
1092         }
1093         err = ofl_sts(fd, NULL, &fstate, NULL);
1094         if (err < 0) {
1095                 return NULL;
1096         }
1097         semid = cre_sem(1, SEM_EXCL|DELEXIT);
1098         if (semid < 0) {
1099                 cls_fil(fd);
1100                 return NULL;
1101         }
1102         err = datcache_getdat_fromfile(fd, &rawdat, &size);
1103         if (err < 0) {
1104                 del_sem(semid);
1105                 cls_fil(fd);
1106                 return NULL;
1107         }
1108         err = datcache_getretrinfo_fromfile(fd, &retrinfo, &retrinfo_len);
1109         if (err < 0) {
1110                 if (rawdat != NULL) {
1111                         free(rawdat);
1112                 }
1113                 del_sem(semid);
1114                 cls_fil(fd);
1115                 return NULL;
1116         }
1117         err = datcache_getheader_fromfile(fd, &header, &header_len);
1118         if (err < 0) {
1119                 if (retrinfo != NULL) {
1120                         free(retrinfo);
1121                 }
1122                 if (rawdat != NULL) {
1123                         free(rawdat);
1124                 }
1125                 del_sem(semid);
1126                 cls_fil(fd);
1127                 return NULL;
1128         }
1129
1130         cache = (datcache_t*)malloc(sizeof(datcache_t));
1131         if (cache == NULL) {
1132                 free(retrinfo);
1133                 free(rawdat);
1134                 del_sem(semid);
1135                 cls_fil(fd);
1136                 return NULL;
1137         }
1138         cache->flag = 0;
1139         cache->fd = fd;
1140         cache->mtime_open = fstate.f_mtime;
1141         cache->semid = semid;
1142         QueInit(&(cache->datalist.queue));
1143         cache->datalist.data = rawdat;
1144         cache->datalist.len = size;
1145         cache->s_datsize = size;
1146         cache->recsize_open = size;
1147         cache->context = NULL;
1148
1149         datcache_setupretrinfo(cache, retrinfo, retrinfo_len);
1150         cache->latestheader = header;
1151         cache->latestheader_len = header_len;
1152
1153         err = residhash_initialize(&cache->residhash);
1154         if (err < 0) {
1155                 free(retrinfo);
1156                 free(rawdat);
1157                 del_sem(semid);
1158                 cls_fil(fd);
1159                 free(cache);
1160                 return NULL;
1161         }
1162         err = resindexhash_initialize(&cache->resindexhash);
1163         if (err < 0) {
1164                 residhash_finalize(&cache->residhash);
1165                 free(retrinfo);
1166                 free(rawdat);
1167                 del_sem(semid);
1168                 cls_fil(fd);
1169                 free(cache);
1170                 return NULL;
1171         }
1172         err = wordlist_initialize(&cache->ngwordlist);
1173         if (err < 0) {
1174                 resindexhash_finalize(&cache->resindexhash);
1175                 residhash_finalize(&cache->residhash);
1176                 free(retrinfo);
1177                 free(rawdat);
1178                 del_sem(semid);
1179                 cls_fil(fd);
1180                 free(cache);
1181                 return NULL;
1182         }
1183
1184         err = datcache_readresidinfo(cache);
1185         if (err < 0) {
1186                 wordlist_finalize(&cache->ngwordlist);
1187                 resindexhash_finalize(&cache->resindexhash);
1188                 residhash_finalize(&cache->residhash);
1189                 free(retrinfo);
1190                 free(rawdat);
1191                 del_sem(semid);
1192                 cls_fil(fd);
1193                 free(cache);
1194                 return NULL;
1195         }
1196         err = datcache_readresindexinfo(cache);
1197         if (err < 0) {
1198                 wordlist_finalize(&cache->ngwordlist);
1199                 resindexhash_finalize(&cache->resindexhash);
1200                 residhash_finalize(&cache->residhash);
1201                 free(retrinfo);
1202                 free(rawdat);
1203                 del_sem(semid);
1204                 cls_fil(fd);
1205                 free(cache);
1206                 return NULL;
1207         }
1208         err = datcache_readngwordinfo(cache);
1209         if (err < 0) {
1210                 wordlist_finalize(&cache->ngwordlist);
1211                 resindexhash_finalize(&cache->resindexhash);
1212                 residhash_finalize(&cache->residhash);
1213                 free(retrinfo);
1214                 free(rawdat);
1215                 del_sem(semid);
1216                 cls_fil(fd);
1217                 free(cache);
1218                 return NULL;
1219         }
1220
1221         return cache;
1222 }
1223
1224 EXPORT VOID datcache_delete(datcache_t *cache)
1225 {
1226         datcache_data_t *cache_data;
1227         Bool ok;
1228
1229         wordlist_finalize(&cache->ngwordlist);
1230         resindexhash_finalize(&cache->resindexhash);
1231         residhash_finalize(&cache->residhash);
1232
1233         if (cache->latestheader != NULL) {
1234                 free(cache->latestheader);
1235         }
1236         if (cache->retrinfo != NULL) {
1237                 free(cache->retrinfo);
1238         }
1239
1240         for (;;) {
1241                 ok = isQueEmpty(&(cache->datalist.queue));
1242                 if (ok == True) {
1243                         break;
1244                 }
1245                 cache_data = datcache_data_next(&cache->datalist);
1246                 datcache_data_delete(cache_data);
1247         }
1248         free(cache->datalist.data);
1249         del_sem(cache->semid);
1250         cls_fil(cache->fd);
1251         free(cache);
1252 }