39303b2bd80ee88fdb87ed49cc0fcee7335e8c15
[chise/concord.git] / cos.c
1 /* Copyright (C) 2013 MORIOKA Tomohiko
2    This file is part of the CONCORD Library.
3
4    The CONCORD Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The CONCORD Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the CONCORD Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <stdlib.h>
20 #include "sysdep.h"
21 #include "cos-i.h"
22 #include "cos-read.h"
23 #include "cos-print.h"
24
25 const char concord_db_format_version[] = CONCORD_DB_FORMAT_VERSION;
26 const char concord_db_dir[] = CONCORD_DB_DIR;
27 const char concord_system_db_dir[] = CONCORD_SI_DB_DIR;
28
29 CONCORD_DS concord_current_env = NULL;
30
31 int (*COS_Object_retain_function_table
32      [COS_OBJECT_TYPE_MAX - COS_Object_Type_char])
33   (COS_Object)
34   = { cos_retain_string,
35       cos_retain_symbol,
36       cos_retain_cons,
37       cos_retain_container,
38       cos_retain_sexp,
39       cos_retain_binary,
40       cos_retain_ds,
41       cos_retain_genre,
42       cos_retain_feature,
43       cos_retain_index,
44       cos_retain_db_object
45 };
46
47 int (*COS_Object_release_function_table
48      [COS_OBJECT_TYPE_MAX - COS_Object_Type_char])
49   (COS_Object)
50   = { cos_release_string,
51       cos_release_symbol,
52       cos_release_cons,
53       cos_release_container,
54       cos_release_sexp,
55       cos_release_binary,
56       cos_release_ds,
57       cos_release_genre,
58       cos_release_feature,
59       cos_release_index,
60       cos_release_db_object
61 };
62
63
64 COS_object
65 cos_make_int (COS_C_Int num)
66 {
67   return (COS_object)((COS_INT)(num << 1) | 1);
68 }
69
70 int
71 cos_int_p (COS_object obj)
72 {
73   return COS_OBJECT_INT_P (obj);
74 }
75
76 COS_C_Int
77 cos_int_value (COS_object obj)
78 {
79   if (COS_OBJECT_INT_P (obj))
80     return ((COS_INT)obj) >> 1;
81   return INTPTR_MIN;
82 }
83
84
85 COS_object
86 cos_make_char (int code)
87 {
88   return (COS_object)((COS_INT)(code << 2) | 2);
89 }
90
91 int
92 cos_char_p (COS_object obj)
93 {
94   return COS_OBJECT_CHAR_P (obj);
95 }
96
97 int
98 cos_char_id (COS_object obj)
99 {
100   if (COS_OBJECT_CHAR_P (obj))
101     return (((COS_INT)obj) >> 2) & 0x7FFFFFFF;
102   return -1;
103 }
104
105
106 COS_Object
107 cos_allocate_object_0 (enum COS_Object_Type type, size_t size)
108 {
109   COS_Object obj = (COS_Object)malloc (size);
110
111   if (obj == NULL)
112     return NULL;
113
114   obj->header.prefix = COS_OBJECT_PREFIX_OBJECT;
115   obj->header.type = type;
116   obj->header.reference_count = 0;
117
118   return obj;
119 }
120
121 COS_Object
122 cos_retain_object (COS_Object obj)
123 {
124   if (COS_OBJECT_P (obj))
125     {
126       obj->header.reference_count++;
127       (*COS_Object_retain_function_table
128        [((COS_Object)obj)->header.type
129         - COS_FAT_OBJECT_TYPE_MIN])(obj);
130     }
131   return obj;
132 }
133
134 int
135 cos_release_object (COS_object obj)
136 {
137   if (COS_OBJECT_P (obj))
138     {
139       ((COS_Object)obj)->header.reference_count--;
140       if ( ((COS_Object)obj)->header.reference_count <= 0 )
141         return (*COS_Object_release_function_table
142                 [((COS_Object)obj)->header.type
143                  - COS_FAT_OBJECT_TYPE_MIN])(obj);
144     }
145   return 0;
146 }
147
148
149 COS_String
150 cos_make_string (char* str, size_t size)
151 {
152   COS_String obj = COS_ALLOCATE_OBJECT (String);
153
154   if (obj == NULL)
155     return NULL;
156
157   obj->size = size;
158   obj->data = malloc (size + 1);
159   if (obj->data == NULL)
160     {
161       free (obj);
162       return NULL;
163     }
164
165   strncpy ((char*)obj->data, str, size);
166   obj->data[size] = '\0';
167   return obj;
168 }
169
170 COS_String
171 cos_build_string (char* str)
172 {
173 #if 0
174   COS_String obj = COS_ALLOCATE_OBJECT (string);
175
176   if (obj == NULL)
177     return NULL;
178
179   obj->size = strlen (str);
180   obj->data = malloc (obj->size + 1);
181   if (obj->data == NULL)
182     {
183       free (obj);
184       return NULL;
185     }
186
187   strncpy ((char*)obj->data, str, obj->size);
188   obj->data[obj->size] = '\0';
189   return obj;
190 #else
191   return cos_make_string (str, strlen (str));
192 #endif
193 }
194
195 int
196 cos_retain_string (COS_Object obj)
197 {
198   return 0;
199 }
200
201 int
202 cos_release_string (COS_Object obj)
203 {
204   if (obj == NULL)
205     return 0;
206
207   if ( ((COS_String)obj)->data != NULL)
208     free (((COS_String)obj)->data);
209   free (obj);
210   return 0;
211 }
212
213 int cos_string_p (COS_object obj)
214 {
215   return COS_OBJECT_STRING_P (obj);
216 }
217
218 size_t
219 cos_string_size (COS_String string)
220 {
221   return string->size;
222 }
223
224 char*
225 cos_string_data (COS_String string)
226 {
227   return (char*)string->data;
228 }
229
230
231 COS_Cons
232 cos_cons (COS_object car, COS_object cdr)
233 {
234   COS_Cons obj = COS_ALLOCATE_OBJECT (Cons);
235
236   if (obj == NULL)
237     return NULL;
238
239   obj->car = car;
240   obj->cdr = cdr;
241   cos_retain_object (car);
242   cos_retain_object (cdr);
243
244   return obj;
245 }
246
247 int
248 cos_retain_cons (COS_Object obj)
249 {
250   //cos_retain_object (COS_CAR (obj));
251   //cos_retain_object (COS_CDR (obj));
252   return 0;
253 }
254
255 int
256 cos_release_cons (COS_Object obj)
257 {
258   if (obj == NULL)
259     return 0;
260
261   cos_release_object (COS_CAR (obj));
262   cos_release_object (COS_CDR (obj));
263   free (obj);
264   return 0;
265 }
266
267 int
268 cos_cons_p (COS_object obj)
269 {
270   return COS_OBJECT_CONS_P (obj);
271 }
272
273 COS_object
274 cos_car (COS_Cons pair)
275 {
276   if (COS_OBJECT_CONS_P (pair))
277     return COS_CAR (pair);
278   else
279     return NULL;
280 }
281
282 COS_object
283 cos_cdr (COS_Cons pair)
284 {
285   if (COS_OBJECT_CONS_P (pair))
286     return COS_CDR (pair);
287   else
288     return NULL;
289 }
290
291 COS_Cons
292 cos_assoc (COS_object key, COS_Cons alist)
293 {
294   COS_Cons rest = alist;
295
296   while ( COS_OBJECT_CONS_P (rest) )
297     {
298       COS_Cons cell = cos_car (rest);
299
300       if ( cos_car (cell) == key )
301         return cell;
302
303       rest = cos_cdr (rest);
304     }
305   return NULL;
306 }
307
308 COS_object
309 cos_alist_get (COS_Cons alist, COS_object key)
310 {
311   return cos_cdr (cos_assoc (key, alist));
312 }
313
314
315 int
316 cos_retain_container (COS_Object obj)
317 {
318   return 0;
319 }
320
321 int
322 cos_release_container (COS_Object obj)
323 {
324   return 0;
325 }
326
327
328 int
329 cos_retain_sexp (COS_Object obj)
330 {
331   return 0;
332 }
333
334 int
335 cos_release_sexp (COS_Object obj)
336 {
337   return 0;
338 }
339
340
341 int
342 cos_retain_binary (COS_Object obj)
343 {
344   return 0;
345 }
346
347 int
348 cos_release_binary (COS_Object obj)
349 {
350   return 0;
351 }
352
353
354 COS_DS
355 concord_open_env (COS_object ds)
356 {
357   if (COS_OBJECT_DS_P (ds))
358     concord_current_env = (COS_DS)ds;
359   else
360     {
361       char* path;
362
363       if (COS_OBJECT_C_STRING_P (ds))
364         path = (char*)ds;
365       else if (ds == NULL)
366         path = CONCORD_SI_DB_DIR;
367       else
368         return NULL;
369
370       concord_current_env = concord_open_ds (CONCORD_Backend_Berkeley_DB,
371                                              path, 0, 0755);
372     }
373   return concord_current_env;
374 }
375
376 int
377 cos_retain_ds (COS_Object obj)
378 {
379   return 0;
380 }
381
382 int
383 cos_release_ds (COS_Object obj)
384 {
385   return concord_close_ds ((COS_DS)obj);
386 }
387
388 int
389 concord_ds_p (COS_object obj)
390 {
391   return COS_OBJECT_DS_P (obj);
392 }
393
394
395 COS_Genre
396 concord_get_genre (COS_object ds, COS_object genre)
397 {
398   if (COS_OBJECT_C_STRING_P (genre))
399     return concord_ds_get_genre (ds, (char*)genre);
400   else if (COS_OBJECT_SYMBOL_P (genre))
401     return concord_ds_get_genre (ds, (char*)((COS_Symbol)genre)->name->data);
402   else if (COS_OBJECT_GENRE_P (genre))
403     return (COS_Genre)genre;
404   return NULL;
405 }
406
407 int
408 cos_retain_genre (COS_Object obj)
409 {
410   return 0;
411 }
412
413 int
414 cos_release_genre (COS_Object obj)
415 {
416   return concord_close_genre ((COS_Genre)obj);
417 }
418
419
420 COS_Feature
421 concord_get_feature (COS_object ds,
422                      COS_object genre, COS_object feature)
423 {
424   if (COS_OBJECT_FEATURE_P (feature))
425     return feature;
426   else
427     {
428       COS_Genre gobj = concord_get_genre (ds, genre);
429       char* feature_name;
430
431       if (COS_OBJECT_C_STRING_P (feature))
432         feature_name = (char*)feature;
433       else if (COS_OBJECT_STRING_P (feature))
434         feature_name = (char*)((COS_String)feature)->data;
435       else if (COS_OBJECT_SYMBOL_P (feature))
436         feature_name = (char*)((COS_Symbol)feature)->name->data;
437       else
438         return NULL;
439
440       return concord_genre_get_feature (gobj, feature_name);
441     }
442 }
443
444 int
445 cos_retain_feature (COS_Object obj)
446 {
447   return 0;
448 }
449
450 int
451 cos_release_feature (COS_Object obj)
452 {
453   return concord_close_feature ((COS_Feature)obj);
454 }
455
456
457 COS_Feature_INDEX
458 concord_get_feature_index (COS_object ds,
459                            COS_object genre, COS_object feature)
460 {
461   if (COS_OBJECT_FEATURE_INDEX_P (feature))
462     return feature;
463   else
464     {
465       COS_Feature fobj = concord_get_feature (ds, genre, feature);
466       COS_Genre gobj;
467       char* feature_name;
468
469       if (fobj == NULL)
470         return NULL;
471
472       gobj = concord_feature_get_genre (fobj);
473       feature_name = concord_feature_get_name (fobj);
474       return concord_genre_get_index (gobj, feature_name);
475     }
476 }
477
478 int
479 cos_retain_index (COS_Object obj)
480 {
481   return concord_close_index ((COS_Feature_INDEX)obj);
482 }
483
484 int
485 cos_release_index (COS_Object obj)
486 {
487   return concord_close_index ((COS_Feature_INDEX)obj);
488 }
489
490
491 int
492 cos_retain_db_object (COS_Object obj)
493 {
494   return 0;
495 }
496
497 int
498 cos_release_db_object (COS_Object obj)
499 {
500   return 0;
501 }
502
503 COS_object
504 concord_decode_object (COS_object ds, COS_object genre,
505                        COS_object feature, COS_object id)
506 {
507   COS_Feature_INDEX index = concord_get_feature_index (ds, genre, feature);
508   char* id_str;
509   char buf[256];
510   CONCORD_String_Tank obj_st;
511   int cid;
512   size_t end;
513
514   if (index == NULL)
515     return NULL;
516
517   if ( index->decoding_table != NULL )
518     {
519       COS_object ret = cos_hash_table_get (index->decoding_table, id);
520       if (ret != NULL)
521         return ret;
522     }
523   else
524     index->decoding_table = cos_make_hash_table ();
525
526   if (COS_OBJECT_INT_P (id))
527     {
528       snprintf(buf, 256, "%ld", cos_int_value (id));
529       id_str = buf;
530     }
531   else if (COS_OBJECT_CHAR_P (id))
532     {
533       snprintf(buf, 256, "%d", cos_char_id (id));
534       id_str = buf;
535     }
536   else if (COS_OBJECT_SYMBOL_P (id))
537     {
538       id_str = cos_string_data (cos_symbol_name ((COS_Symbol)id));
539     }
540   else if (COS_OBJECT_C_STRING_P (id))
541     {
542       id_str = (char*)id;
543     }
544   else if (COS_OBJECT_STRING_P (id))
545     {
546       id_str = cos_string_data ((COS_String)id);
547     }
548   else
549     return NULL;
550
551   if ( concord_index_strid_get_obj_string (index, id_str, &obj_st) )
552     return NULL;
553
554   {
555     COS_object obj;
556
557     cid = cos_read_char (CONCORD_String_data (&obj_st),
558                          CONCORD_String_size (&obj_st),
559                          0, &end);
560     if ( cid >= 0 )
561       {
562         obj = cos_make_char (cid);
563         cos_retain_object (id);
564         cos_retain_object (obj);
565         cos_hash_table_put (index->decoding_table, id, obj);
566         return obj;
567       }
568   }
569   return NULL;
570 }
571
572 COS_object
573 concord_object_get_feature_value (COS_object object, COS_object feature)
574 {
575   CONCORD_Genre gobj;
576   CONCORD_Feature fobj;
577   COS_object ret;
578
579   if (COS_OBJECT_CHAR_P (object))
580     {
581       if (!COS_OBJECT_DS_P (concord_current_env))
582         {
583           concord_current_env = NULL;
584           return NULL;
585         }
586       gobj = concord_get_genre (concord_current_env, "character");
587     }
588   else
589     return NULL;
590   if (gobj == NULL)
591     return NULL;
592
593   fobj = concord_get_feature (concord_current_env, gobj, feature);
594   if (fobj == NULL)
595     return NULL;
596
597   if ( fobj->value_table != NULL )
598     {
599       ret = cos_hash_table_get (fobj->value_table, object);
600       if (ret != NULL)
601         return ret;
602     }
603   else
604     fobj->value_table = cos_make_hash_table ();
605
606   {
607     char id_buf[256];
608     CONCORD_String_Tank val_st;
609     size_t end;
610
611     if (COS_OBJECT_CHAR_P (object))
612       {
613         cos_utf8_print_char (object, (unsigned char*)id_buf, 256);
614       }
615     else
616       return NULL;
617
618     if ( concord_obj_get_feature_value_string (id_buf, fobj, &val_st) )
619       return NULL;
620
621     ret = cos_read_object (CONCORD_String_data (&val_st),
622                            CONCORD_String_size (&val_st),
623                            0, &end);
624     if ( ret == NULL )
625       return NULL;
626
627     cos_retain_object (object);
628     cos_retain_object (ret);
629     cos_hash_table_put (fobj->value_table, object, ret);
630     return ret;
631   }
632 }