1 /* index.c --
2 * Created: Sat Mar 15 16:47:42 2003 by Aleksey Cheusov <vle@gmx.net>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 1, or (at your option) any
7 * later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include "dictP.h"
20
21 #include "dictd.h"
22 #include "plugin.h"
23 #include "strategy.h"
24 #include "data.h"
25 #include "index.h"
26
27 #ifndef HAVE_DLFCN_H
28 #include <ltdl.h>
29 #else
30 #include <dlfcn.h>
31 #endif
32
33 #include <maa.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36
dict_search_plugin(lst_List l,const char * const word,const dictDatabase * database,int strategy,int * extra_result,const dictPluginData ** extra_data,int * extra_data_size)37 int dict_search_plugin (
38 lst_List l,
39 const char *const word,
40 const dictDatabase *database,
41 int strategy,
42 int *extra_result,
43 const dictPluginData **extra_data,
44 int *extra_data_size)
45 {
46 int ret;
47 int failed = 0;
48 const char * const * defs;
49 const int * defs_sizes;
50 int defs_count;
51 const char * err_msg;
52 int i;
53 dictWord * def;
54 int len;
55
56 int match = strategy & DICT_MATCH_MASK;
57 int strategy_real = strategy & ~DICT_MATCH_MASK;
58
59 assert (database);
60 assert (database -> plugin);
61
62 if (strategy_real == DICT_STRAT_DOT){
63 strategy = (match | database -> default_strategy);
64 PRINTF (DBG_SEARCH, (":S: def strategy for database '%s': %d\n",
65 database -> databaseName, strategy));
66 }
67
68 PRINTF (DBG_SEARCH, (":S: searching for '%s' in '%s' using strat '%d'\n",
69 word, database -> databaseName, strategy));
70
71 failed = database -> plugin -> dictdb_search (
72 database -> plugin -> data,
73 word, -1,
74 strategy,
75 &ret,
76 extra_data, extra_data_size,
77 &defs, &defs_sizes, &defs_count);
78
79 database -> plugin -> dictdb_free_called = 1;
80
81 if (extra_result)
82 *extra_result = ret;
83
84 if (failed){
85 err_msg = database -> plugin -> dictdb_error (
86 database -> plugin -> data);
87
88 fprintf (stderr, ":E: Plugin failed: %s\n", (err_msg ? err_msg : ""));
89 PRINTF (DBG_SEARCH, (":E: Plugin failed: %s\n", err_msg ? err_msg : ""));
90 }else{
91 switch (ret){
92 case DICT_PLUGIN_RESULT_FOUND:
93 PRINTF (DBG_SEARCH, (":S: found %i definitions\n", defs_count));
94 break;
95 case DICT_PLUGIN_RESULT_NOTFOUND:
96 PRINTF (DBG_SEARCH, (":S: not found\n"));
97 return 0;
98 case DICT_PLUGIN_RESULT_EXIT:
99 PRINTF (DBG_SEARCH, (":S: exiting\n"));
100 return 0;
101 case DICT_PLUGIN_RESULT_PREPROCESS:
102 PRINTF (DBG_SEARCH, (":S: preprocessing\n"));
103 break;
104 default:
105 err_fatal (__func__, "invalid pligin's exit status\n");
106 }
107
108 for (i = 0; i < defs_count; ++i){
109 def = xmalloc (sizeof (dictWord));
110 memset (def, 0, sizeof (*def));
111
112 def -> database = database;
113 def -> start = def -> end = 0;
114
115 len = defs_sizes [i];
116 if (-1 == len)
117 len = strlen (defs [i]);
118
119 if (
120 strategy & DICT_MATCH_MASK &&
121 ret != DICT_PLUGIN_RESULT_PREPROCESS)
122 {
123 def -> word = xstrdup (defs [i]);
124 def -> def = def -> word;
125 def -> def_size = -1;
126 }else{
127 def -> word = xstrdup (word);
128 def -> def = defs [i];
129 def -> def_size = len;
130 }
131
132 if (ret == DICT_PLUGIN_RESULT_PREPROCESS){
133 lst_push (l, def);
134 }else{
135 lst_append (l, def);
136 }
137 }
138
139 return defs_count;
140 }
141
142 return 0;
143 }
144
145 /* reads data without headword 00-... */
dict_plugin_data(const dictDatabase * db,const dictWord * dw)146 static char *dict_plugin_data (const dictDatabase *db, const dictWord *dw)
147 {
148 char *buf = dict_data_obtain (db, dw);
149 char *p = buf;
150 int len;
151
152 assert (db);
153 assert (db -> index);
154
155 if (!strncmp (p, DICT_ENTRY_PLUGIN_DATA, strlen (DICT_ENTRY_PLUGIN_DATA))){
156 while (*p != '\n')
157 ++p;
158 }
159
160 while (*p == '\n')
161 ++p;
162
163 len = strlen (p);
164
165 while (len > 0 && p [len - 1] == '\n')
166 --len;
167
168 p [len] = 0;
169
170 p = xstrdup (p);
171 xfree (buf);
172
173 return p;
174 }
175
176 /* set data fields from 00-database-plugin-data entry */
177 /* return a number of inserted items */
plugin_initdata_set_data_file(dictPluginData * data,int data_size,const dictDatabase * db)178 static int plugin_initdata_set_data_file (
179 dictPluginData *data, int data_size,
180 const dictDatabase *db)
181 {
182 char *plugin_data;
183 int ret = 0;
184 lst_List list;
185 dictWord *dw;
186
187 if (data_size <= 0)
188 err_fatal (__func__, "invalid initial array size");
189
190 list = lst_create ();
191
192 ret = dict_search_database_ (
193 list, DICT_ENTRY_PLUGIN_DATA, db, DICT_STRAT_EXACT);
194
195 if (0 == ret){
196 dict_destroy_list (list);
197 return 0;
198 }
199
200 dw = (dictWord *) lst_pop (list);
201 plugin_data = dict_plugin_data (db, dw);
202
203 dict_destroy_datum (dw);
204
205 data -> id = DICT_PLUGIN_INITDATA_DICT;
206 data -> data = plugin_data;
207 data -> size = -1;
208
209 dict_destroy_list (list);
210
211 return 1;
212 }
213
214 /* set data fields from db -> plugin_data */
215 /* return a number of inserted items */
plugin_initdata_set_data_array(dictPluginData * data,int data_size,const dictDatabase * db)216 static int plugin_initdata_set_data_array (
217 dictPluginData *data, int data_size,
218 const dictDatabase *db)
219 {
220 if (data_size <= 0)
221 err_fatal (__func__, "invalid initial array size");
222
223 if (db -> plugin_data){
224 data [0].id = DICT_PLUGIN_INITDATA_DICT;
225 data [0].data = xstrdup (db -> plugin_data);
226 data [0].size = -1;
227
228 return 1;
229 }else{
230 return 0;
231 }
232 }
233
234 /* return a number of inserted items */
plugin_initdata_set_data(dictPluginData * data,int data_size,const dictDatabase * db)235 static int plugin_initdata_set_data (
236 dictPluginData *data, int data_size,
237 const dictDatabase *db)
238 {
239 if (db -> plugin_data)
240 return plugin_initdata_set_data_array (data, data_size, db);
241 else if (db -> index)
242 return plugin_initdata_set_data_file (data, data_size, db);
243 else
244 return 0;
245 }
246
plugin_initdata_set_dbnames(dictPluginData * data,int data_size)247 static int plugin_initdata_set_dbnames (dictPluginData *data, int data_size)
248 {
249 const dictDatabase *db;
250 int count;
251 int i;
252
253 if (data_size <= 0)
254 err_fatal (__func__, "too small initial array");
255
256 count = lst_length (DictConfig -> dbl);
257 if (count == 0)
258 return 0;
259
260 if (count > data_size)
261 err_fatal (__func__, "too small initial array");
262
263 for (i = 1; i <= count; ++i){
264 db = (const dictDatabase *)(lst_nth_get (DictConfig -> dbl, i));
265
266 data -> id = DICT_PLUGIN_INITDATA_DBNAME;
267 if (db -> databaseName){
268 data -> size = strlen (db -> databaseName);
269 data -> data = xstrdup (db -> databaseName);
270 }else{
271 data -> size = 0;
272 data -> data = NULL;
273 }
274
275 ++data;
276 }
277
278 return count;
279 }
280
plugin_initdata_set_stratnames(dictPluginData * data,int data_size,const dictDatabase * db)281 static int plugin_initdata_set_stratnames (
282 dictPluginData *data,
283 int data_size,
284 const dictDatabase *db)
285 {
286 dictStrategy const * const *strats;
287 int count;
288 int ret = 0;
289 int i;
290 dictPluginData_strategy datum;
291
292 if (data_size <= 0)
293 err_fatal (__func__, "too small initial array");
294
295 count = get_strategy_count ();
296 assert (count > 0);
297
298 strats = get_strategies ();
299
300 for (i = 0; i < count; ++i){
301 if (
302 !db -> strategy_disabled ||
303 !db -> strategy_disabled [strats [i] -> number])
304 {
305 data -> id = DICT_PLUGIN_INITDATA_STRATEGY;
306
307 if (
308 strlen (strats [i] -> name) + 1 >
309 sizeof (datum.name))
310 {
311 err_fatal (__func__, "too small initial array");
312 }
313
314 datum.number = strats [i] -> number;
315 strcpy (datum.name, strats [i] -> name);
316
317 data -> size = sizeof (datum);
318 data -> data = xmalloc (sizeof (datum));
319
320 memcpy ((void *) data -> data, &datum, sizeof (datum));
321
322 ++data;
323 ++ret;
324 }
325 }
326
327 return ret;
328 }
329
plugin_initdata_set_defdbdir(dictPluginData * data,int data_size)330 static int plugin_initdata_set_defdbdir (dictPluginData *data, int data_size)
331 {
332 if (data_size <= 0)
333 err_fatal (__func__, "too small initial array");
334
335 data -> size = -1;
336 data -> data = xstrdup (DICT_DICTIONARY_PATH);
337 data -> id = DICT_PLUGIN_INITDATA_DEFDBDIR;
338
339 return 1;
340 }
341
plugin_initdata_set_alphabet_8bit(dictPluginData * data,int data_size)342 static int plugin_initdata_set_alphabet_8bit (
343 dictPluginData *data, int data_size)
344 {
345 if (data_size <= 0)
346 err_fatal (__func__, "too small initial array");
347
348 data -> size = -1;
349 data -> data = xstrdup (global_alphabet_8bit);
350 data -> id = DICT_PLUGIN_INITDATA_ALPHABET_8BIT;
351
352 return 1;
353 }
354
plugin_initdata_set_alphabet_ascii(dictPluginData * data,int data_size)355 static int plugin_initdata_set_alphabet_ascii (
356 dictPluginData *data, int data_size)
357 {
358 if (data_size <= 0)
359 err_fatal (__func__, "too small initial array");
360
361 data -> size = -1;
362 data -> data = xstrdup (global_alphabet_ascii);
363 data -> id = DICT_PLUGIN_INITDATA_ALPHABET_ASCII;
364
365 return 1;
366 }
367
368 /* all dict [i]->data are xmalloc'ed */
plugin_initdata_set(dictPluginData * data,int data_size,const dictDatabase * db)369 static int plugin_initdata_set (
370 dictPluginData *data, int data_size,
371 const dictDatabase *db)
372 {
373 int count = 0;
374 dictPluginData *p = data;
375
376 count = plugin_initdata_set_defdbdir (data, data_size);
377 data += count;
378 data_size -= count;
379
380 count = plugin_initdata_set_dbnames (data, data_size);
381 data += count;
382 data_size -= count;
383
384 count = plugin_initdata_set_stratnames (data, data_size, db);
385 data += count;
386 data_size -= count;
387
388 count = plugin_initdata_set_data (data, data_size, db);
389 data += count;
390 data_size -= count;
391
392 count = plugin_initdata_set_alphabet_8bit (data, data_size);
393 data += count;
394 data_size -= count;
395
396 count = plugin_initdata_set_alphabet_ascii (data, data_size);
397 data += count;
398 data_size -= count;
399
400 return data - p;
401 }
402
plugin_init_data_free(dictPluginData * data,int data_size)403 static void plugin_init_data_free (
404 dictPluginData *data, int data_size)
405 {
406 int i=0;
407
408 for (i = 0; i < data_size; ++i){
409 if (data -> data)
410 xfree ((void *) data -> data);
411
412 ++data;
413 }
414 }
415
416 /* Reads plugin's file name from .dict file */
417 /* do not free() returned value*/
dict_plugin_filename(const dictDatabase * db,const dictWord * dw)418 static char *dict_plugin_filename (
419 const dictDatabase *db,
420 const dictWord *dw)
421 {
422 static char filename [FILENAME_MAX];
423
424 char *buf = dict_data_obtain (db, dw);
425 char *p = buf;
426 int len;
427
428 if (!strncmp (p, DICT_ENTRY_PLUGIN, strlen (DICT_ENTRY_PLUGIN))){
429 while (*p != '\n')
430 ++p;
431 }
432
433 while (*p == '\n' || isspace ((unsigned char) *p))
434 ++p;
435
436 len = strlen (p);
437
438 while (
439 len > 0 &&
440 (p [len - 1] == '\n' || isspace ((unsigned char) p [len - 1])))
441 {
442 --len;
443 }
444
445 p [len] = 0;
446
447 if (p [0] != '.' && p [0] != '/'){
448 if (sizeof (filename) < strlen (DICT_PLUGIN_PATH) + strlen (p) + 1)
449 err_fatal (__func__, "too small initial array\n");
450
451 strcpy (filename, DICT_PLUGIN_PATH);
452 strcat (filename, p);
453 }else{
454 strlcpy (filename, p, sizeof (filename));
455 }
456
457 xfree (buf);
458
459 return filename;
460 }
461
462
dict_plugin_test(dictPlugin * plugin,int version,int ret)463 static void dict_plugin_test (dictPlugin *plugin, int version, int ret)
464 {
465 const char *err_msg = NULL;
466
467 if (ret){
468 err_msg = plugin -> dictdb_error (
469 plugin -> data);
470
471 if (err_msg){
472 err_fatal (
473 __func__,
474 "%s\n",
475 plugin -> dictdb_error (plugin -> data));
476 }else{
477 err_fatal (
478 __func__,
479 "Error code %i\n", ret);
480 }
481 }
482
483 switch (version){
484 case 0:
485 break;
486 /*
487 case 1:
488 if (!i -> plugin -> dictdb_set)
489 err_fatal (__func__, "'%s' function is not found\n", DICT_PLUGINFUN_SET);
490 break;
491 */
492 default:
493 err_fatal (__func__, "Invalid version returned by plugin\n");
494 }
495 }
496
dict_plugin_dlsym(dictPlugin * plugin)497 static void dict_plugin_dlsym (dictPlugin *plugin)
498 {
499 PRINTF(DBG_INIT, (":I: getting functions addresses\n"));
500
501 plugin -> dictdb_open = (dictdb_open_type)
502 lt_dlsym (plugin -> handle, DICT_PLUGINFUN_OPEN);
503 plugin -> dictdb_free = (dictdb_free_type)
504 lt_dlsym (plugin -> handle, DICT_PLUGINFUN_FREE);
505 plugin -> dictdb_search = (dictdb_search_type)
506 lt_dlsym (plugin -> handle, DICT_PLUGINFUN_SEARCH);
507 plugin -> dictdb_close = (dictdb_close_type)
508 lt_dlsym (plugin -> handle, DICT_PLUGINFUN_CLOSE);
509 plugin -> dictdb_error = (dictdb_error_type)
510 lt_dlsym (plugin -> handle, DICT_PLUGINFUN_ERROR);
511 plugin -> dictdb_set = (dictdb_set_type)
512 lt_dlsym (plugin -> handle, DICT_PLUGINFUN_SET);
513
514 if (!plugin -> dictdb_open ||
515 !plugin -> dictdb_search ||
516 !plugin -> dictdb_free ||
517 !plugin -> dictdb_error ||
518 !plugin -> dictdb_close)
519 {
520 PRINTF(DBG_INIT, (":I: faild\n"));
521 exit (1);
522 }
523 }
524
create_plugin(const char * datababsename,const char * plugin_filename,const dictPluginData * plugin_init_data,int plugin_init_data_size)525 static dictPlugin *create_plugin (
526 const char *datababsename,
527 const char *plugin_filename,
528 const dictPluginData *plugin_init_data,
529 int plugin_init_data_size)
530 {
531 dictPlugin *plugin;
532 int ret;
533 int version;
534
535 PRINTF(
536 DBG_INIT, (
537 ":I: Initializing db/plugin '%s'/'%s'\n",
538 datababsename ? datababsename : "(null)", plugin_filename));
539
540 plugin = xmalloc (sizeof (dictPlugin));
541 memset (plugin, 0, sizeof (dictPlugin));
542
543 PRINTF(DBG_INIT, (":I: opening plugin\n"));
544 plugin -> handle = lt_dlopen (plugin_filename);
545 if (!plugin -> handle){
546 PRINTF(DBG_INIT, (":I: faild: %s\n", dlerror ()));
547 exit (1);
548 }
549
550 dict_plugin_dlsym (plugin);
551
552 PRINTF(DBG_INIT, (":I: initializing plugin\n"));
553 ret = plugin -> dictdb_open (
554 plugin_init_data, plugin_init_data_size, &version, &plugin -> data);
555
556 dict_plugin_test (plugin, version, ret);
557
558 return plugin;
559 }
560
dict_plugin_init(dictDatabase * db)561 int dict_plugin_init (dictDatabase *db)
562 {
563 int ret = 0;
564 lst_List list;
565 const char *plugin_filename = NULL;
566 dictWord *dw;
567
568 dictPluginData init_data [3000];
569 int init_data_size = 0;
570
571 if (db -> pluginFilename){
572 plugin_filename = db -> pluginFilename;
573 }else if (db -> index){
574
575 list = lst_create ();
576
577 ret = dict_search_database_ (list, DICT_ENTRY_PLUGIN, db, DICT_STRAT_EXACT);
578 switch (ret){
579 case 1: case 2:
580 dw = (dictWord *) lst_pop (list);
581
582 plugin_filename = dict_plugin_filename (db, dw);
583
584 dict_destroy_datum (dw);
585 break;
586 case 0:
587 break;
588 default:
589 err_internal( __func__, "Corrupted .index file'\n" );
590 }
591
592 dict_destroy_list (list);
593 }
594
595 if (plugin_filename){
596 init_data_size = plugin_initdata_set (
597 init_data, sizeof (init_data)/sizeof (init_data [0]),
598 db);
599
600 db -> plugin = create_plugin (
601 db -> databaseName,
602 plugin_filename, init_data, init_data_size);
603
604 plugin_init_data_free (init_data, init_data_size);
605 }
606
607 return 0;
608 }
609
dict_plugin_destroy(dictDatabase * db)610 void dict_plugin_destroy ( dictDatabase *db )
611 {
612 int ret;
613
614 if (!db)
615 return;
616
617 if (!db -> plugin)
618 return;
619
620 if (db -> plugin -> dictdb_close){
621 ret = db -> plugin -> dictdb_close (db -> plugin -> data);
622 if (ret){
623 PRINTF(DBG_INIT, ("exiting plugin failed"));
624 exit (1);
625 }
626 }
627
628 ret = lt_dlclose (db -> plugin -> handle);
629 if (ret)
630 PRINTF(DBG_INIT, ("%s", lt_dlerror ()));
631
632 xfree (db -> plugin);
633 db -> plugin = NULL;
634 }
635
call_dictdb_free(lst_List db_list)636 void call_dictdb_free (lst_List db_list)
637 {
638 const dictDatabase *db = NULL;
639 lst_Position pos;
640
641 LST_ITERATE (db_list, pos, db){
642 if (db -> plugin){
643 if (db -> plugin -> dictdb_free_called){
644 db -> plugin -> dictdb_free (db -> plugin -> data);
645
646 db -> plugin -> dictdb_free_called = 0;
647 }
648 }
649 }
650 }
651