1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2006 Kouhei Sutou <kou@cozmixng.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307 USA
19 *
20 * $Id: tomoe-dict-est.c 1493 2007-06-16 10:59:43Z ikezoe $
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif /* HAVE_CONFIG_H */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <glib.h>
31 #include <glib/gi18n-lib.h>
32 #include <gmodule.h>
33
34 #include <estraier.h>
35
36 #include <tomoe-module-impl.h>
37 #include <tomoe-dict.h>
38 #include <tomoe-candidate.h>
39 #include <tomoe-xml-parser.h>
40 #include <glib-utils.h>
41
42 #define TOMOE_TYPE_DICT_EST tomoe_type_dict_est
43 #define TOMOE_DICT_EST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TOMOE_TYPE_DICT_EST, TomoeDictEst))
44 #define TOMOE_DICT_EST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TOMOE_TYPE_DICT_EST, TomoeDictEstClass))
45 #define TOMOE_IS_DICT_EST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TOMOE_TYPE_DICT_EST))
46 #define TOMOE_IS_DICT_EST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TOMOE_TYPE_DICT_EST))
47 #define TOMOE_DICT_EST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TOMOE_TYPE_DICT_EST, TomoeDictEstClass))
48
49 enum {
50 PROP_0,
51 PROP_NAME,
52 PROP_DATABASE,
53 PROP_EDITABLE
54 };
55
56 typedef struct _TomoeDictEst TomoeDictEst;
57 typedef struct _TomoeDictEstClass TomoeDictEstClass;
58 struct _TomoeDictEst
59 {
60 TomoeDict object;
61 gchar *name;
62 gchar *database;
63
64 gboolean editable;
65
66 ESTDB *db;
67
68 GHashTable *cache;
69 };
70
71 struct _TomoeDictEstClass
72 {
73 TomoeDictClass parent_class;
74 };
75
76 typedef struct _TomoeDictSearchContext {
77 TomoeQuery *query;
78 GList *results;
79 } TomoeDictSearchContext;
80
81 static GType tomoe_type_dict_est = 0;
82 static TomoeDictClass *parent_class;
83
84 static GObject *constructor (GType type,
85 guint n_props,
86 GObjectConstructParam *props);
87 static void dispose (GObject *object);
88 static void set_property (GObject *object,
89 guint prop_id,
90 const GValue *value,
91 GParamSpec *pspec);
92 static void get_property (GObject *object,
93 guint prop_id,
94 GValue *value,
95 GParamSpec *pspec);
96 static const gchar *get_name (TomoeDict *dict);
97 static gboolean register_char (TomoeDict *dict,
98 TomoeChar *chr);
99 static gboolean unregister_char (TomoeDict *dict,
100 const gchar *utf8);
101 static TomoeChar *get_char (TomoeDict *dict,
102 const gchar *utf8);
103 static GList *search (TomoeDict *dict,
104 TomoeQuery *query);
105 static gboolean flush (TomoeDict *dict);
106 static gboolean is_editable (TomoeDict *dict);
107 static gboolean is_available (TomoeDict *dict);
108 static gchar *get_available_private_utf8 (TomoeDict *dict);
109 static gboolean tomoe_dict_est_open (TomoeDictEst *dict);
110 static gboolean tomoe_dict_est_close (TomoeDictEst *dict);
111
112 static void
class_init(TomoeDictEstClass * klass)113 class_init (TomoeDictEstClass *klass)
114 {
115 GObjectClass *gobject_class;
116 TomoeDictClass *dict_class;
117
118 parent_class = g_type_class_peek_parent (klass);
119
120 gobject_class = G_OBJECT_CLASS (klass);
121
122 gobject_class->constructor = constructor;
123 gobject_class->dispose = dispose;
124 gobject_class->set_property = set_property;
125 gobject_class->get_property = get_property;
126
127 dict_class = TOMOE_DICT_CLASS (klass);
128 dict_class->get_name = get_name;
129 dict_class->register_char = register_char;
130 dict_class->unregister_char = unregister_char;
131 dict_class->get_char = get_char;
132 dict_class->search = search;
133 dict_class->flush = flush;
134 dict_class->is_editable = is_editable;
135 dict_class->is_available = is_available;
136 dict_class->get_available_private_utf8 = get_available_private_utf8;
137
138 g_object_class_install_property (
139 gobject_class,
140 PROP_NAME,
141 g_param_spec_string (
142 "name",
143 "Name",
144 "The name of the dictionary",
145 NULL,
146 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
147 g_object_class_install_property (
148 gobject_class,
149 PROP_DATABASE,
150 g_param_spec_string (
151 "database",
152 "Database",
153 "The database name of Hyper Estraier",
154 NULL,
155 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
156 g_object_class_install_property(
157 gobject_class,
158 PROP_EDITABLE,
159 g_param_spec_boolean(
160 "editable",
161 "Editable",
162 "Editable flag",
163 FALSE,
164 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
165 }
166
167 static void
init(TomoeDictEst * dict)168 init (TomoeDictEst *dict)
169 {
170 dict->name = NULL;
171 dict->database = NULL;
172 dict->db = NULL;
173 dict->editable = FALSE;
174 dict->cache = g_hash_table_new_full(g_str_hash, g_str_equal,
175 g_free, g_object_unref);
176 }
177
178 static void
register_type(GTypeModule * type_module)179 register_type (GTypeModule *type_module)
180 {
181 static const GTypeInfo info =
182 {
183 sizeof (TomoeDictEstClass),
184 (GBaseInitFunc) NULL,
185 (GBaseFinalizeFunc) NULL,
186 (GClassInitFunc) class_init,
187 NULL, /* class_finalize */
188 NULL, /* class_data */
189 sizeof (TomoeDictEst),
190 0,
191 (GInstanceInitFunc) init,
192 };
193
194 tomoe_type_dict_est = g_type_module_register_type (type_module,
195 TOMOE_TYPE_DICT,
196 "TomoeDictEst",
197 &info, 0);
198 }
199
200 G_MODULE_EXPORT GList *
TOMOE_MODULE_IMPL_INIT(GTypeModule * type_module)201 TOMOE_MODULE_IMPL_INIT (GTypeModule *type_module)
202 {
203 GList *registered_types = NULL;
204
205 register_type (type_module);
206 if (tomoe_type_dict_est)
207 registered_types =
208 g_list_prepend (registered_types,
209 (gchar *) g_type_name (tomoe_type_dict_est));
210
211 return registered_types;
212 }
213
214 G_MODULE_EXPORT void
TOMOE_MODULE_IMPL_EXIT(void)215 TOMOE_MODULE_IMPL_EXIT (void)
216 {
217 }
218
219 G_MODULE_EXPORT GObject *
TOMOE_MODULE_IMPL_INSTANTIATE(const gchar * first_property,va_list var_args)220 TOMOE_MODULE_IMPL_INSTANTIATE (const gchar *first_property, va_list var_args)
221 {
222 return g_object_new_valist (TOMOE_TYPE_DICT_EST, first_property, var_args);
223 }
224
225 G_MODULE_EXPORT gchar *
TOMOE_MODULE_IMPL_GET_LOG_DOMAIN(void)226 TOMOE_MODULE_IMPL_GET_LOG_DOMAIN (void)
227 {
228 return g_strdup (G_LOG_DOMAIN);
229 }
230
231 static GObject *
constructor(GType type,guint n_props,GObjectConstructParam * props)232 constructor (GType type, guint n_props,
233 GObjectConstructParam *props)
234 {
235 GObject *object;
236 GObjectClass *klass = G_OBJECT_CLASS (parent_class);
237 TomoeDictEst *dict;
238
239 object = klass->constructor (type, n_props, props);
240 dict = TOMOE_DICT_EST (object);
241
242 tomoe_dict_est_open (dict);
243
244 return object;
245 }
246
247 static void
set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)248 set_property (GObject *object,
249 guint prop_id,
250 const GValue *value,
251 GParamSpec *pspec)
252 {
253 TomoeDictEst *dict = TOMOE_DICT_EST (object);
254
255 switch (prop_id) {
256 case PROP_NAME:
257 dict->name = g_value_dup_string (value);
258 break;
259 case PROP_DATABASE:
260 dict->database = g_value_dup_string (value);
261 break;
262 case PROP_EDITABLE:
263 dict->editable = g_value_get_boolean (value);
264 break;
265 default:
266 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
267 break;
268 }
269 }
270
271
272 static void
get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)273 get_property (GObject *object,
274 guint prop_id,
275 GValue *value,
276 GParamSpec *pspec)
277 {
278 TomoeDictEst *dict = TOMOE_DICT_EST (object);
279
280 switch (prop_id) {
281 case PROP_NAME:
282 g_value_set_string (value, dict->name);
283 break;
284 case PROP_DATABASE:
285 g_value_set_string (value, dict->database);
286 break;
287 case PROP_EDITABLE:
288 g_value_set_boolean (value, dict->editable);
289 break;
290 default:
291 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
292 break;
293 }
294 }
295
296 static void
dispose(GObject * object)297 dispose (GObject *object)
298 {
299 TomoeDictEst *dict;
300
301 dict = TOMOE_DICT_EST (object);
302
303 tomoe_dict_est_close (dict);
304
305 if (dict->name)
306 g_free (dict->name);
307 if (dict->database)
308 g_free (dict->database);
309 if (dict->cache)
310 g_hash_table_destroy (dict->cache);
311
312 dict->name = NULL;
313 dict->database = NULL;
314 dict->cache = NULL;
315
316 G_OBJECT_CLASS (parent_class)->dispose (object);
317 }
318
319 static const gchar*
get_name(TomoeDict * _dict)320 get_name (TomoeDict *_dict)
321 {
322 TomoeDictEst *dict = TOMOE_DICT_EST (_dict);
323 g_return_val_if_fail (TOMOE_IS_DICT_EST (dict), NULL);
324 return dict->name;
325 }
326
327 static gboolean
register_char(TomoeDict * _dict,TomoeChar * chr)328 register_char (TomoeDict *_dict, TomoeChar *chr)
329 {
330 TomoeDictEst *dict = TOMOE_DICT_EST (_dict);
331 gboolean success = FALSE;
332 const gchar *original_value;
333 gchar *value;
334 gint n_strokes;
335 const GList *readings, *node;
336 ESTDOC *doc;
337
338 g_return_val_if_fail (TOMOE_IS_DICT_EST (dict), success);
339 g_return_val_if_fail (chr, success);
340
341 doc = est_doc_new ();
342
343 original_value = tomoe_char_get_utf8 (chr);
344 if (original_value) {
345 value = g_strdup_printf ("font:%s", original_value);
346 est_doc_add_attr (doc, "@uri", value);
347 g_free (value);
348
349 est_doc_add_attr (doc, "utf8", original_value);
350
351 value = g_strdup_printf ("%d", g_utf8_get_char (original_value));
352 est_doc_add_attr (doc, "code-point", value);
353 g_free (value);
354 }
355
356 n_strokes = tomoe_char_get_n_strokes (chr);
357 if (n_strokes < 0) {
358 TomoeWriting *writing;
359 writing = tomoe_char_get_writing (chr);
360 if (writing)
361 n_strokes = tomoe_writing_get_n_strokes (writing);
362 }
363
364 if (n_strokes >= 0) {
365 value = g_strdup_printf ("%d", n_strokes);
366 est_doc_add_attr (doc, "n-strokes", value);
367 g_free (value);
368 }
369
370 original_value = tomoe_char_get_variant (chr);
371 if (original_value) {
372 est_doc_add_attr (doc, "variant", original_value);
373 }
374
375 readings = tomoe_char_get_readings (chr);
376 if (readings) {
377 GString *on_readings = NULL, *kun_readings = NULL, *all_readings = NULL;
378 all_readings = g_string_new (NULL);
379 for (node = readings; node; node = g_list_next (node)) {
380 TomoeReading *reading = TOMOE_READING (node->data);
381 const gchar *read_str = tomoe_reading_get_reading (reading);
382 switch (tomoe_reading_get_reading_type (reading)) {
383 case TOMOE_READING_JA_ON:
384 if (on_readings)
385 on_readings = g_string_append_c (on_readings, ' ');
386 else
387 on_readings = g_string_new (NULL);
388 on_readings = g_string_append (on_readings, read_str);
389 break;
390 case TOMOE_READING_JA_KUN:
391 if (kun_readings)
392 kun_readings = g_string_append_c (kun_readings, ' ');
393 else
394 kun_readings = g_string_new (NULL);
395 kun_readings = g_string_append (kun_readings, read_str);
396 break;
397 case TOMOE_READING_UNKNOWN:
398 case TOMOE_READING_INVALID:
399 all_readings = g_string_append_c (all_readings, ' ');
400 all_readings = g_string_append (all_readings, read_str);
401 default:
402 break;
403 }
404 }
405
406 if (on_readings) {
407 est_doc_add_attr (doc, "ja_on_readings", on_readings->str);
408 all_readings = g_string_append_c (all_readings, ' ');
409 all_readings = g_string_append (all_readings, on_readings->str);
410 g_string_free (on_readings, TRUE);
411 }
412 all_readings = g_string_append_c (all_readings, ' ');
413 if (kun_readings) {
414 est_doc_add_attr (doc, "ja_kun_readings", kun_readings->str);
415 all_readings = g_string_append_c (all_readings, ' ');
416 all_readings = g_string_append (all_readings, kun_readings->str);
417 g_string_free (kun_readings, TRUE);
418 }
419 est_doc_add_attr (doc, "all_readings", all_readings->str);
420 g_string_free (all_readings, TRUE);
421 }
422
423 value = tomoe_char_to_xml (chr);
424 est_doc_add_hidden_text (doc, value);
425 g_free (value);
426
427 success = est_db_put_doc (dict->db, doc, ESTPDCLEAN);
428 if (!success) {
429 g_warning ("put error: %s\n", est_err_msg (est_db_error (dict->db)));
430 }
431
432 est_doc_delete (doc);
433
434 return success;
435 }
436
437 static gboolean
unregister_char(TomoeDict * _dict,const gchar * utf8)438 unregister_char (TomoeDict *_dict, const gchar *utf8)
439 {
440 TomoeDictEst *dict = TOMOE_DICT_EST (_dict);
441 gboolean success = FALSE;
442 ESTCOND *cond;
443 int i, *results, n_results;
444 gchar *expr;
445
446 g_return_val_if_fail (TOMOE_IS_DICT_EST (dict), success);
447 g_return_val_if_fail (utf8 && *utf8 != '\0', success);
448
449 cond = est_cond_new ();
450 expr = g_strdup_printf ("utf8 STREQ %s", utf8);
451 est_cond_add_attr (cond, expr);
452 g_free (expr);
453
454 results = est_db_search (dict->db, cond, &n_results, NULL);
455
456 for (i = 0; i < n_results; i++) {
457 gint id;
458 const gchar *utf8;
459
460 id = results[i];
461
462 utf8 = est_db_get_doc_attr (dict->db, id, "utf8");
463 if (utf8)
464 g_hash_table_remove (dict->cache, utf8);
465
466 success = est_db_out_doc (dict->db, id, ESTODCLEAN);
467 if (!success) {
468 g_warning ("out error: %s\n",
469 est_err_msg (est_db_error (dict->db)));
470 break;
471 }
472 }
473 g_free (results);
474 est_cond_delete (cond);
475
476 return success;
477 }
478
479 static TomoeChar *
retrieve_char_by_id(TomoeDictEst * dict,int id)480 retrieve_char_by_id (TomoeDictEst *dict, int id)
481 {
482 TomoeChar *chr = NULL;
483 ESTDOC *doc;
484 const gchar *utf8;
485
486 utf8 = est_db_get_doc_attr (dict->db, id, "utf8");
487 if (!utf8)
488 return NULL;
489
490 chr = g_hash_table_lookup (dict->cache, utf8);
491 if (chr)
492 return chr;
493
494 doc = est_db_get_doc (dict->db, id, 0);
495 if (!doc)
496 return NULL;
497
498 chr = tomoe_char_new_from_xml_data (est_doc_hidden_texts (doc), -1);
499 if (chr)
500 g_hash_table_insert (dict->cache, g_strdup (utf8), chr);
501
502 est_doc_delete (doc);
503
504 return chr;
505 }
506
507 static TomoeChar *
get_char(TomoeDict * _dict,const gchar * utf8)508 get_char (TomoeDict *_dict, const gchar *utf8)
509 {
510 TomoeDictEst *dict = TOMOE_DICT_EST (_dict);
511 TomoeChar *chr = NULL;
512 ESTCOND *cond;
513 int i, *results, n_results;
514 gchar *expr;
515
516 g_return_val_if_fail (TOMOE_IS_DICT_EST (dict), chr);
517 g_return_val_if_fail (utf8 && *utf8 != '\0', chr);
518
519 cond = est_cond_new ();
520 expr = g_strdup_printf ("utf8 STREQ %s", utf8);
521 est_cond_add_attr (cond, expr);
522 g_free (expr);
523
524 results = est_db_search (dict->db, cond, &n_results, NULL);
525 for (i = 0; i < n_results; i++) {
526 chr = retrieve_char_by_id (dict, results[i]);
527 if (chr) break;
528 }
529 g_free (results);
530 est_cond_delete (cond);
531
532 if (chr)
533 g_object_ref (chr);
534
535 return chr;
536 }
537
538 static void
append_search_cond_utf8(TomoeDictEst * dict,ESTCOND * cond,GString * phrase,const gchar * utf8)539 append_search_cond_utf8 (TomoeDictEst *dict, ESTCOND *cond, GString *phrase,
540 const gchar *utf8)
541 {
542 if (utf8) {
543 gchar *escaped_utf8;
544
545 escaped_utf8 = g_markup_escape_text (utf8, -1);
546 g_string_append_printf (phrase, " <utf8>%s</utf8>", escaped_utf8);
547 g_free (escaped_utf8);
548 }
549 }
550
551 static void
append_search_cond_variant(TomoeDictEst * dict,ESTCOND * cond,GString * phrase,const gchar * variant)552 append_search_cond_variant (TomoeDictEst *dict, ESTCOND *cond, GString *phrase,
553 const gchar *variant)
554 {
555 if (variant) {
556 gchar *escaped_variant;
557
558 escaped_variant = g_markup_escape_text (variant, -1);
559 g_string_append_printf (phrase,
560 " <variant>%s</variant>", escaped_variant);
561 g_free (escaped_variant);
562 }
563 }
564
565 static void
append_search_cond_n_strokes(TomoeDictEst * dict,ESTCOND * cond,GString * phrase,gint min_n_strokes,gint max_n_strokes)566 append_search_cond_n_strokes (TomoeDictEst *dict, ESTCOND *cond,
567 GString *phrase,
568 gint min_n_strokes,
569 gint max_n_strokes)
570 {
571 gchar *attr;
572
573 if (min_n_strokes >= 0) {
574 attr = g_strdup_printf ("n-strokes NUMGE %d", min_n_strokes);
575 est_cond_add_attr (cond, attr);
576 g_free (attr);
577 }
578
579 if (max_n_strokes >= 0) {
580 attr = g_strdup_printf ("n-strokes NUMLE %d", max_n_strokes);
581 est_cond_add_attr (cond, attr);
582 g_free (attr);
583 }
584 }
585
586 static void
append_search_cond_readings(TomoeDictEst * dict,ESTCOND * cond,GString * phrase,const GList * readings)587 append_search_cond_readings (TomoeDictEst *dict, ESTCOND *cond, GString *phrase,
588 const GList *readings)
589 {
590 GList *node;
591 for (node = (GList *)readings; node; node = g_list_next (node)) {
592 TomoeReading *reading = TOMOE_READING (node->data);
593 const gchar *read_str = tomoe_reading_get_reading (reading);
594 gchar *expr;
595
596 switch (tomoe_reading_get_reading_type (reading)) {
597 #if 0
598 case TOMOE_READING_JA_ON:
599 expr = g_strdup_printf ("ja_on_readings STRINC %s", read_str);
600 est_cond_add_attr (cond, expr);
601 g_free (expr);
602 expr = g_strdup_printf ("all_readings STRINC %s", read_str);
603 est_cond_add_attr (cond, expr);
604 g_free (expr);
605 break;
606 case TOMOE_READING_JA_KUN:
607 expr = g_strdup_printf ("ja_kun_readings STRINC %s", read_str);
608 est_cond_add_attr (cond, expr);
609 g_free (expr);
610 expr = g_strdup_printf ("all_readings STRINC %s", read_str);
611 est_cond_add_attr (cond, expr);
612 g_free (expr);
613 break;
614 #endif
615 case TOMOE_READING_JA_ON:
616 case TOMOE_READING_JA_KUN:
617 case TOMOE_READING_INVALID:
618 case TOMOE_READING_UNKNOWN:
619 default:
620 expr = g_strdup_printf ("all_readings STRRX (\\s|^)%s", read_str);
621 est_cond_add_attr (cond, expr);
622 g_free (expr);
623 break;
624 }
625 }
626 }
627
628 static void
append_search_cond_radicals(TomoeDictEst * dict,ESTCOND * cond,GString * phrase,const GList * radicals)629 append_search_cond_radicals (TomoeDictEst *dict, ESTCOND *cond, GString *phrase,
630 const GList *radicals)
631 {
632 GList *node;
633 for (node = (GList *)radicals; node; node = g_list_next (node)) {
634 const gchar *radical = node->data;
635 gchar *escaped_radical;
636
637 escaped_radical = g_markup_escape_text (radical, -1);
638 g_string_append_printf (phrase,
639 " <radical>%s</radical>",
640 escaped_radical);
641 g_free (escaped_radical);
642 }
643 }
644
645
646 static GList *
search(TomoeDict * _dict,TomoeQuery * query)647 search (TomoeDict *_dict, TomoeQuery *query)
648 {
649 TomoeDictEst *dict = TOMOE_DICT_EST (_dict);
650 GList *candidates = NULL;
651 ESTCOND *cond;
652 GString *phrase;
653 int i, *results, n_results;
654
655 g_return_val_if_fail (TOMOE_IS_DICT_EST (dict), candidates);
656
657 cond = est_cond_new ();
658 est_cond_set_order (cond, "utf8 STRA");
659
660 phrase = g_string_new ("");
661
662 if (tomoe_query_is_empty (query)) {
663 g_string_assign (phrase, "[UVSET]");
664 } else {
665 append_search_cond_utf8 (dict, cond, phrase,
666 tomoe_query_get_utf8 (query));
667 append_search_cond_variant (dict, cond, phrase,
668 tomoe_query_get_variant (query));
669 append_search_cond_n_strokes (dict, cond, phrase,
670 tomoe_query_get_min_n_strokes (query),
671 tomoe_query_get_max_n_strokes (query));
672 append_search_cond_readings (dict, cond, phrase,
673 tomoe_query_get_readings (query));
674 append_search_cond_radicals (dict, cond, phrase,
675 tomoe_query_get_radicals (query));
676 }
677
678 if (phrase->len > 0)
679 est_cond_set_phrase (cond, phrase->str);
680 g_string_free (phrase, TRUE);
681
682 results = est_db_search (dict->db, cond, &n_results, NULL);
683 for (i = 0; i < n_results; i++) {
684 TomoeChar *chr;
685
686 chr = retrieve_char_by_id (dict, results[i]);
687 if (chr)
688 candidates = g_list_prepend (candidates,
689 tomoe_candidate_new (chr));
690 }
691 g_free (results);
692 est_cond_delete (cond);
693
694 return candidates;
695 }
696
697 static gboolean
flush(TomoeDict * _dict)698 flush (TomoeDict *_dict)
699 {
700 TomoeDictEst *dict = TOMOE_DICT_EST (_dict);
701
702 return est_db_sync (dict->db);
703 }
704
705 static gboolean
is_editable(TomoeDict * _dict)706 is_editable (TomoeDict *_dict)
707 {
708 TomoeDictEst *dict = TOMOE_DICT_EST (_dict);
709
710 g_return_val_if_fail (TOMOE_IS_DICT_EST (dict), FALSE);
711
712 return dict->editable;
713 }
714
715 static gboolean
is_available(TomoeDict * _dict)716 is_available (TomoeDict *_dict)
717 {
718 TomoeDictEst *dict = TOMOE_DICT_EST (_dict);
719
720 g_return_val_if_fail (TOMOE_IS_DICT_EST (dict), FALSE);
721
722 return dict->db != NULL;
723 }
724
725 static gchar *
get_available_private_utf8(TomoeDict * _dict)726 get_available_private_utf8 (TomoeDict *_dict)
727 {
728 TomoeDictEst *dict = TOMOE_DICT_EST (_dict);
729 ESTCOND *cond;
730 gchar *expr;
731 int i, *results, n_results;
732 gunichar result_ucs = TOMOE_CHAR_PRIVATE_USE_AREA_START;
733
734 g_return_val_if_fail (TOMOE_IS_DICT_EST (dict), FALSE);
735
736 cond = est_cond_new ();
737 est_cond_set_order (cond, "utf8 STRD");
738 est_cond_set_max (cond, 1);
739
740 expr = g_strdup_printf ("code-point NUMGE %d",
741 TOMOE_CHAR_PRIVATE_USE_AREA_START);
742 est_cond_add_attr (cond, expr);
743 g_free (expr);
744
745 expr = g_strdup_printf ("code-point NUMLE %d",
746 TOMOE_CHAR_PRIVATE_USE_AREA_END);
747 est_cond_add_attr (cond, expr);
748 g_free (expr);
749
750 results = est_db_search (dict->db, cond, &n_results, NULL);
751 for (i = 0; i < n_results; i++) {
752 TomoeChar *chr;
753 gunichar ucs;
754
755 chr = retrieve_char_by_id (dict, results[i]);
756 ucs = g_utf8_get_char (tomoe_char_get_utf8 (chr));
757 if (ucs >= TOMOE_CHAR_PRIVATE_USE_AREA_START) {
758 if (ucs >= TOMOE_CHAR_PRIVATE_USE_AREA_END) {
759 result_ucs = 0;
760 } else {
761 result_ucs = ucs + 1;
762 }
763 }
764 }
765 g_free (results);
766 est_cond_delete (cond);
767
768 if (result_ucs >= TOMOE_CHAR_PRIVATE_USE_AREA_START) {
769 gint result_len;
770 gchar *result;
771
772 result_len = g_unichar_to_utf8 (result_ucs, NULL);
773 result = g_new (gchar, result_len + 1);
774 g_unichar_to_utf8 (result_ucs, result);
775 result[result_len] = '\0';
776 return result;
777 } else {
778 return NULL;
779 }
780 }
781
782 static gboolean
tomoe_dict_est_open(TomoeDictEst * dict)783 tomoe_dict_est_open (TomoeDictEst *dict)
784 {
785 gboolean success = TRUE;
786 int option, ecode;
787
788 option = dict->editable ? ESTDBWRITER | ESTDBCREAT : ESTDBREADER;
789 dict->db = est_db_open (dict->database, option, &ecode);
790
791 if (!dict->db) {
792 g_warning ("open error: %s\n", est_err_msg (ecode));
793 success = FALSE;
794 }
795
796 return success;
797 }
798
799 static gboolean
tomoe_dict_est_close(TomoeDictEst * dict)800 tomoe_dict_est_close (TomoeDictEst *dict)
801 {
802 gboolean success;
803 int ecode;
804
805 success = est_db_close (dict->db, &ecode);
806 if (!success) {
807 g_warning ("close error: %s\n", est_err_msg (ecode));
808 }
809
810 dict->db = NULL;
811
812 return success;
813 }
814
815 /*
816 vi:ts=4:nowrap:ai:expandtab
817 */
818