ecd6ec71232df3b80b820bc1e85ca39606009692
[profile/ivi/isf.git] / ism / src / scim_backend.cpp
1 /* ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable. */
2
3 /*
4  * Smart Common Input Method
5  *
6  * Copyright (c) 2002-2005 James Su <suzhe@tsinghua.org.cn>
7  *
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this program; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
22  * Boston, MA  02111-1307  USA
23  *
24  * $Id: scim_backend.cpp,v 1.38.2.1 2006/09/24 16:00:52 suzhe Exp $
25  *
26  */
27
28 #define Uses_SCIM_FILTER_MANAGER
29 #define Uses_SCIM_BACKEND
30 #define Uses_SCIM_IMENGINE
31 #define Uses_SCIM_IMENGINE_MODULE
32 #define Uses_SCIM_CONFIG_PATH
33 #define Uses_STL_ALGORITHM
34 #define Uses_SCIM_PANEL_AGENT
35
36
37 #include <malloc.h>
38 #include <string.h>
39 #include "scim_private.h"
40 #include "scim.h"
41 #include "scim_stl_map.h"
42 #include "isf_query_utility.h"
43
44
45 namespace scim {
46
47 #if SCIM_USE_STL_EXT_HASH_MAP
48 typedef __gnu_cxx::hash_map <String, IMEngineFactoryPointer, scim_hash_string >     IMEngineFactoryRepository;
49 #elif SCIM_USE_STL_HASH_MAP
50 typedef std::hash_map <String, IMEngineFactoryPointer, scim_hash_string >           IMEngineFactoryRepository;
51 #else
52 typedef std::map <String, IMEngineFactoryPointer>                                   IMEngineFactoryRepository;
53 #endif
54
55 typedef std::vector <IMEngineFactoryPointer>                                        IMEngineFactoryPointerVector;
56
57
58 class LocaleEqual
59 {
60     String m_lhs;
61 public:
62     LocaleEqual (const String &lhs) : m_lhs (lhs) { }
63
64     bool operator () (const String &rhs) const {
65         if (m_lhs == rhs) return true;
66         if (scim_get_locale_language (m_lhs) == scim_get_locale_language (rhs) &&
67             scim_get_locale_encoding (m_lhs) == scim_get_locale_encoding (rhs) &&
68             m_lhs.find ('.') != String::npos && rhs.find ('.') != String::npos)
69             return true;
70         return false;
71     }
72 };
73
74 class IMEngineFactoryPointerLess
75 {
76 public:
77     bool operator () (const IMEngineFactoryPointer &lhs, const IMEngineFactoryPointer &rhs) const {
78         return (lhs->get_language () < rhs->get_language ()) ||
79                (lhs->get_language () == rhs->get_language () && lhs->get_name () < rhs->get_name ());
80     }
81 };
82
83 class BackEndBase::BackEndBaseImpl
84 {
85     IMEngineFactoryRepository    m_factory_repository;
86     String                       m_supported_unicode_locales;
87     ConfigPointer                m_config;
88
89 public:
90     BackEndBaseImpl (const ConfigPointer &config)
91         : m_config (config)
92     {
93         String locales;
94
95         /* Set the default supported locales. */
96         locales = scim_global_config_read (SCIM_GLOBAL_CONFIG_SUPPORTED_UNICODE_LOCALES, String ("en_US.UTF-8"));
97
98         std::vector <String> locale_list;
99         std::vector <String> real_list;
100
101         scim_split_string_list (locale_list, locales);
102
103         for (std::vector <String>::iterator i = locale_list.begin (); i!= locale_list.end (); ++i) {
104             *i = scim_validate_locale (*i);
105             if (i->length () && scim_get_locale_encoding (*i) == "UTF-8" &&
106                 std::find_if (real_list.begin (), real_list.end (), LocaleEqual (*i)) == real_list.end ())
107                 real_list.push_back (*i);
108         }
109
110         m_supported_unicode_locales = scim_combine_string_list (real_list);
111     }
112
113     void clear ()
114     {
115         m_factory_repository.clear ();
116     }
117
118     void dump_factories ()
119     {
120         IMEngineFactoryRepository::const_iterator it;
121         std::cout << "Factories in backend:" << std::endl;
122         for (it = m_factory_repository.begin (); it != m_factory_repository.end (); ++it) {
123             if (it->second.null ())
124                 std::cout << "\t" << it->first << ": null" << std::endl;
125             else
126                 std::cout << "\t" << it->first << ": valid" << std::endl;
127         }
128     }
129
130     String get_all_locales () const
131     {
132         String locale;
133
134         std::vector <String> locale_list;
135         std::vector <String> real_list;
136
137         IMEngineFactoryRepository::const_iterator it;
138
139         for (it = m_factory_repository.begin (); it != m_factory_repository.end (); ++it) {
140             if (locale.length () == 0)
141                 locale += it->second->get_locales ();
142             else
143                 locale += (String (",") + it->second->get_locales ());
144         }
145
146         if (m_supported_unicode_locales.length ())
147             locale += (String (",") + m_supported_unicode_locales);
148
149         scim_split_string_list (locale_list, locale);
150
151         for (std::vector <String>::iterator i = locale_list.begin (); i!= locale_list.end (); i++) {
152             locale = scim_validate_locale (*i);
153             if (locale.length () &&
154                 std::find_if (real_list.begin (), real_list.end (), LocaleEqual (locale)) == real_list.end ())
155                 real_list.push_back (locale);
156         }
157
158         return scim_combine_string_list (real_list);
159     }
160
161     IMEngineFactoryPointer get_factory (const String &uuid) const
162     {
163         IMEngineFactoryRepository::const_iterator it = m_factory_repository.find (uuid);
164
165         if (it != m_factory_repository.end ())
166             return it->second;
167
168         return IMEngineFactoryPointer (0);
169     }
170
171     uint32 get_factories_for_encoding (std::vector<IMEngineFactoryPointer> &factories,
172                                        const String                        &encoding)  const
173     {
174         IMEngineFactoryRepository::const_iterator it;
175
176         factories.clear ();
177
178         for (it = m_factory_repository.begin (); it != m_factory_repository.end (); ++it) {
179             if ((encoding.length () == 0 || it->second->validate_encoding (encoding)))
180                 factories.push_back (it->second);
181         }
182
183         sort_factories (factories);
184
185         return factories.size ();
186     }
187
188     uint32 get_factories_for_language (std::vector<IMEngineFactoryPointer> &factories,
189                                        const String                        &language)  const
190     {
191         IMEngineFactoryRepository::const_iterator it;
192
193         factories.clear ();
194
195         for (it = m_factory_repository.begin (); it != m_factory_repository.end (); ++it) {
196             if ((language.length () == 0 || it->second->get_language () == language))
197                 factories.push_back (it->second);
198         }
199
200         sort_factories (factories);
201
202         return factories.size ();
203     }
204
205     uint32 get_factory_list (std::vector<String> &uuids) const
206     {
207         IMEngineFactoryRepository::const_iterator it;
208         for (it = m_factory_repository.begin (); it != m_factory_repository.end (); ++it)
209             uuids.push_back(it->first);
210
211         return m_factory_repository.size ();
212     }
213
214     IMEngineFactoryPointer get_default_factory (const String &language, const String &encoding) const
215     {
216         if (!language.length ()) return IMEngineFactoryPointer ();
217
218         IMEngineFactoryPointerVector factories;
219
220         if (get_factories_for_encoding (factories, encoding) > 0) {
221             IMEngineFactoryPointer lang_first;
222             IMEngineFactoryPointerVector::iterator it;
223
224             String def_uuid;
225
226             def_uuid = m_config->read (String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) +
227                                        String ("/") + String ("~other"),
228                                        String (""));
229
230             /* Match by Normalized language exactly. */
231             for (it = factories.begin (); it != factories.end (); ++it) {
232                 if (scim_get_normalized_language ((*it)->get_language ()) == language && lang_first.null ())
233                     lang_first = *it;
234
235                 if ((*it)->get_uuid () == def_uuid)
236                     return *it;
237             }
238
239             if (!lang_first.null ())
240                 return lang_first;
241
242             /* Match by short language name. */
243             for (it = factories.begin (); it != factories.end (); ++it)
244                 if ((*it)->get_language () == language.substr (0,2))
245                     return *it;
246
247             return factories [0];
248         }
249
250         return IMEngineFactoryPointer ();
251     }
252
253     void set_default_factory (const String &language, const String &uuid)
254     {
255         if (!language.length () || !uuid.length ()) return;
256
257         IMEngineFactoryPointerVector factories;
258         if (get_factories_for_encoding (factories, "") > 0) {
259             IMEngineFactoryPointerVector::iterator it;
260             for (it = factories.begin (); it != factories.end (); ++it) {
261                 if ((*it)->get_uuid () == uuid) {
262                     m_config->write (String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + String ("~other"), uuid);
263                     m_config->flush ();
264                     return;
265                 }
266             }
267         }
268     }
269
270     IMEngineFactoryPointer get_next_factory (const String &language, const String &encoding, const String &cur_uuid) const
271     {
272         IMEngineFactoryPointerVector factories;
273
274         if (get_factories_for_encoding (factories, encoding) > 0) {
275             IMEngineFactoryPointer lang_first;
276             IMEngineFactoryPointerVector::iterator it, itl;
277
278             for (it = factories.begin (); it != factories.end (); ++it) {
279                 if ((language.length () == 0 || (*it)->get_language () == language) && lang_first.null ())
280                     lang_first = *it;
281
282                 if ((*it)->get_uuid () == cur_uuid) {
283                     for (itl = it + 1; itl != factories.end (); ++itl) {
284                         if (language.length () == 0 || (*itl)->get_language () == language)
285                             return *itl;
286                     }
287                     if (!lang_first.null ()) return lang_first;
288
289                     return factories [0];
290                 }
291             }
292         }
293
294         return IMEngineFactoryPointer ();
295     }
296
297     IMEngineFactoryPointer get_previous_factory (const String &language, const String &encoding, const String &cur_uuid) const
298     {
299         IMEngineFactoryPointerVector factories;
300
301         if (get_factories_for_encoding (factories, encoding) > 0) {
302             IMEngineFactoryPointer lang_last;
303             IMEngineFactoryPointerVector::iterator it, itl;
304
305             for (it = factories.begin (); it != factories.end (); ++it) {
306                 if ((language.length () == 0 || (*it)->get_language () == language))
307                     lang_last = *it;
308             }
309
310             for (it = factories.begin (); it != factories.end (); ++it) {
311                 if ((*it)->get_uuid () == cur_uuid) {
312                     for (itl = it; itl != factories.begin (); --itl) {
313                         if (language.length () == 0 || (*(itl-1))->get_language () == language)
314                             return *(itl-1);
315                     }
316
317                     if (!lang_last.null ()) return lang_last;
318
319                     return factories [factories.size () - 1];
320                 }
321             }
322         }
323
324         return IMEngineFactoryPointer ();
325     }
326
327     bool add_factory (const IMEngineFactoryPointer &factory)
328     {
329         if (!factory.null ()) {
330             String uuid = factory->get_uuid ();
331
332             if (uuid.length ()) {
333                 m_factory_repository [uuid] = factory;
334                 return true;
335             }
336         }
337
338         return false;
339     }
340
341     void add_specific_factory (const String &uuid, const IMEngineFactoryPointer &factory)
342     {
343         m_factory_repository [uuid] = factory;
344         return;
345     }
346
347 private:
348     void sort_factories (std::vector<IMEngineFactoryPointer> &factories) const
349     {
350         std::sort (factories.begin (), factories.end (), IMEngineFactoryPointerLess ());
351     }
352 };
353
354 BackEndBase::BackEndBase (const ConfigPointer &config)
355     : m_impl (new BackEndBase::BackEndBaseImpl (config))
356 {
357 }
358
359 BackEndBase::~BackEndBase ()
360 {
361     delete m_impl;
362 }
363
364 String
365 BackEndBase::get_all_locales () const
366 {
367     return m_impl->get_all_locales ();
368 }
369
370 IMEngineFactoryPointer
371 BackEndBase::get_factory (const String &uuid) const
372 {
373     return m_impl->get_factory (uuid);
374 }
375
376 uint32
377 BackEndBase::get_factories_for_encoding (std::vector<IMEngineFactoryPointer> &factories, const String &encoding) const
378 {
379     return m_impl->get_factories_for_encoding (factories, encoding);
380 }
381
382 uint32
383 BackEndBase::get_factories_for_language (std::vector<IMEngineFactoryPointer> &factories, const String &language) const
384 {
385     return m_impl->get_factories_for_language (factories, language);
386 }
387
388 uint32
389 BackEndBase::get_factory_list (std::vector<String> &uuids) const
390 {
391     return m_impl->get_factory_list (uuids);
392 }
393
394 IMEngineFactoryPointer
395 BackEndBase::get_default_factory (const String &language, const String &encoding) const
396 {
397     return m_impl->get_default_factory (language, encoding);
398 }
399
400 void
401 BackEndBase::set_default_factory (const String &language, const String &uuid)
402 {
403     m_impl->set_default_factory (language, uuid);
404 }
405
406 IMEngineFactoryPointer
407 BackEndBase::get_next_factory (const String &language, const String &encoding, const String &cur_uuid) const
408 {
409     return m_impl->get_next_factory (language, encoding, cur_uuid);
410 }
411
412 IMEngineFactoryPointer
413 BackEndBase::get_previous_factory (const String &language, const String &encoding, const String &cur_uuid) const
414 {
415     return m_impl->get_previous_factory (language, encoding, cur_uuid);
416 }
417
418 bool
419 BackEndBase::add_factory (const IMEngineFactoryPointer &factory)
420 {
421     return m_impl->add_factory (factory);
422 }
423
424 void
425 BackEndBase::add_specific_factory (const String &uuid, 
426                     const IMEngineFactoryPointer &factory)
427 {
428     m_impl->add_specific_factory (uuid, factory);
429     return;
430 }
431
432 void
433 BackEndBase::clear ()
434 {
435     m_impl->clear ();
436 }
437
438 void
439 BackEndBase::dump_factories ()
440 {
441     m_impl->dump_factories ();
442 }
443
444 /* Implementation of CommonBackEnd. */
445 struct CommonBackEnd::CommonBackEndImpl {
446     std::vector<IMEngineModule *> m_engine_modules;
447     FilterManager       *m_filter_manager;
448     std::vector<String>  m_disabled_factories;
449     std::vector<String>  m_modules;
450     std::map <String, String> m_factory_module_repository;
451
452     CommonBackEndImpl () : m_filter_manager (0) { }
453 };
454
455 CommonBackEnd::CommonBackEnd (const ConfigPointer       &config,
456                               const std::vector<String> &modules)
457     : BackEndBase (config),
458       m_impl (new CommonBackEndImpl)
459 {
460 }
461
462 CommonBackEnd::~CommonBackEnd ()
463 {
464     clear ();
465
466     for (unsigned int i = 0; i < m_impl->m_engine_modules.size (); i++) {
467         if (m_impl->m_engine_modules [i]) {
468             m_impl->m_engine_modules [i]->unload ();
469             delete m_impl->m_engine_modules [i];
470             m_impl->m_engine_modules [i] = NULL;
471         }
472     }
473     delete m_impl->m_filter_manager;
474     delete m_impl;
475 }
476
477 void
478 CommonBackEnd::initialize (const ConfigPointer       &config,
479                            const std::vector<String> &modules,
480                            const bool                is_load_resource,
481                            const bool                is_load_info)
482 {
483     SCIM_DEBUG_BACKEND (1) << __FUNCTION__ << "...\n";
484
485     IMEngineFactoryPointer factory;
486     std::vector<String>    new_modules = modules;
487
488     int all_factories_count = 0;
489     int module_factories_count = 0;
490
491     if (config.null ()) return;
492
493     /* Get disabled factories list. */
494     m_impl->m_disabled_factories = scim_global_config_read (SCIM_GLOBAL_CONFIG_DISABLED_IMENGINE_FACTORIES, m_impl->m_disabled_factories);
495
496     /* Put socket module to the end of list. */
497     if (new_modules.size () > 1) {
498         for (std::vector<String>::iterator it = new_modules.begin (); it != new_modules.end (); ++it) {
499             if (*it == "socket") {
500                 new_modules.erase (it);
501                 new_modules.push_back ("socket");
502                 break;
503             }
504         }
505     }
506
507     /* Try to load all IMEngine modules */
508     try {
509         m_impl->m_filter_manager = new FilterManager (config);
510     } catch (const std::exception & err) {
511         std::cerr << err.what () << "\n";
512         return;
513     }
514
515     if (is_load_info) {
516         /*for (size_t i = 0; i < new_modules.size (); ++i)
517             add_module_info (config, new_modules [i]);*/
518         add_module_info_from_cache_file (config, new_modules);
519         return;
520     }
521
522     /* load IMEngine modules */
523     for (size_t i = 0; i < new_modules.size (); ++i) {
524         module_factories_count = add_module (config, new_modules [i], is_load_resource);
525         all_factories_count += module_factories_count;
526     }
527
528     factory = new ComposeKeyFactory ();
529
530     if (all_factories_count == 0 ||
531         std::find (m_impl->m_disabled_factories.begin (),
532                    m_impl->m_disabled_factories.end (),
533                    factory->get_uuid ()) == m_impl->m_disabled_factories.end ()) {
534         factory = m_impl->m_filter_manager->attach_filters_to_factory (factory);
535         add_factory (factory);
536     }
537 }
538
539 int
540 CommonBackEnd::add_module (const ConfigPointer &config,
541                            const String         module,
542                            bool                 is_load_resource)
543 {
544     SCIM_DEBUG_BACKEND (1) << __FUNCTION__ << " : " << module << "\n";
545
546     IMEngineFactoryPointer  factory;
547     IMEngineModule         *engine_module = NULL;
548     int  module_factories_count = 0;
549     bool first_load = false;
550
551     if (config.null ()) return 0;
552
553     if (module.length () > 0) {
554         /* Check if the module is already loaded */
555         if (std::find (m_impl->m_modules.begin (), m_impl->m_modules.end (), module) == m_impl->m_modules.end ()) {
556             engine_module = new IMEngineModule;
557             m_impl->m_engine_modules.push_back (engine_module);
558             m_impl->m_modules.push_back (module);
559             engine_module->load (module, config);
560             first_load = true;
561         } else {
562             for (size_t i = 0; i < m_impl->m_modules.size (); i++) {
563                 if (m_impl->m_modules [i] == module) {
564                     engine_module = m_impl->m_engine_modules [i];
565                     break;
566                 }
567             }
568         }
569
570         if (engine_module && engine_module->valid ()) {
571             size_t number = engine_module->number_of_factories ();
572             for (size_t j = 0; j < number; ++j) {
573
574                 /* Try to load a IMEngine Factory. */
575                 try {
576                     factory = engine_module->create_factory (j);
577                 } catch (const std::exception & err) {
578                     std::cerr << err.what () << "\n";
579                     factory.reset ();
580                 }
581
582                 if (!factory.null ()) {
583                     /* Check if it's disabled. */
584                     if (std::find (m_impl->m_disabled_factories.begin (),
585                                    m_impl->m_disabled_factories.end (),
586                                    factory->get_uuid ()) == m_impl->m_disabled_factories.end ()) {
587
588                         /* Add it into disabled list to prevent from loading again. */
589                         /*m_impl->m_disabled_factories.push_back (factory->get_uuid ());*/
590
591                         if (is_load_resource)
592                             factory->load_resource ();
593
594                         /* Only load filter for none socket IMEngines. */
595                         if (module != "socket")
596                             factory = m_impl->m_filter_manager->attach_filters_to_factory (factory);
597
598                         add_factory (factory);
599
600                         module_factories_count ++;
601
602                         SCIM_DEBUG_BACKEND (1) << "    Loading IMEngine Factory " << j << " : " << "OK\n";
603                     } else {
604                         SCIM_DEBUG_BACKEND (1) << "    Loading IMEngine Factory " << j << " : " << "Disabled\n";
605                         factory.reset ();
606                     }
607                 } else {
608                     SCIM_DEBUG_BACKEND (1) << "    Loading IMEngine Factory " << j << " : " << "Failed\n";
609                 }
610             }
611             if (module_factories_count) {
612                 SCIM_DEBUG_BACKEND (1) << module << " IMEngine module is successfully loaded.\n";
613             } else {
614                 SCIM_DEBUG_BACKEND (1) << "No Factory loaded from " << module << " IMEngine module!\n";
615                 if (first_load)
616                     engine_module->unload ();
617             }
618         } else {
619             SCIM_DEBUG_BACKEND (1) << "Failed to load " << module << " IMEngine module.\n";
620         }
621     }
622
623     return module_factories_count;
624 }
625
626 void
627 CommonBackEnd::add_module_info (const ConfigPointer &config, const String module_name)
628 {
629     SCIM_DEBUG_BACKEND (1) << __FUNCTION__ << " : " << module_name << "\n";
630
631     if (module_name.length () <= 0 || module_name == "socket")
632         return;
633
634     IMEngineFactoryPointer factory;
635     IMEngineModule         ime_module;
636
637     ime_module.load (module_name, config);
638
639     if (ime_module.valid ()) {
640         for (size_t j = 0; j < ime_module.number_of_factories (); ++j) {
641             try {
642                 factory = ime_module.create_factory (j);
643             } catch (...) {
644                 factory.reset ();
645             }
646
647             if (!factory.null ()) {
648                 if (m_impl->m_factory_module_repository.find (factory->get_uuid ())
649                         == m_impl->m_factory_module_repository.end ()) {
650                     add_specific_factory (factory->get_uuid (), IMEngineFactoryPointer (0));
651                     m_impl->m_factory_module_repository[factory->get_uuid ()] = module_name;
652                 }
653
654                 factory.reset ();
655             }
656         }
657
658         ime_module.unload ();
659     }
660 }
661
662 void
663 CommonBackEnd::add_factory_by_uuid (const ConfigPointer &config, const String uuid)
664 {
665     SCIM_DEBUG_BACKEND (1) << __FUNCTION__ << " : " << uuid << "\n";
666
667     if (m_impl->m_factory_module_repository.find (uuid) == m_impl->m_factory_module_repository.end ())
668         return;
669
670     String module = m_impl->m_factory_module_repository[uuid];
671     add_module (config, module, true);
672 }
673
674 void
675 CommonBackEnd::release_module (const std::vector<String> &use_uuids, const String del_uuid)
676 {
677     SCIM_DEBUG_BACKEND (1) << __FUNCTION__ << " : " << del_uuid << "\n";
678
679     if (m_impl->m_factory_module_repository.find (del_uuid) == m_impl->m_factory_module_repository.end ())
680         return;
681
682     String module = m_impl->m_factory_module_repository[del_uuid];
683     std::vector<String> uuids;
684     std::map <String, String>::iterator it = m_impl->m_factory_module_repository.begin ();
685
686     uuids.clear ();
687     for (; it != m_impl->m_factory_module_repository.end (); it++) {
688         if (it->second == module)
689             uuids.push_back (it->first);
690     }
691
692     for (unsigned int i = 0; i < uuids.size (); i++) {
693         for (unsigned int j = 0; j < use_uuids.size (); j++) {
694             if (uuids[i] == use_uuids[j])
695                 return;
696         }
697     }
698
699     /* unload the module */
700     std::vector<String>::iterator it2 = uuids.begin ();
701     for (; it2 != uuids.end (); it2++)
702         add_specific_factory (*it2, IMEngineFactoryPointer (0));
703
704     std::vector<String>::iterator it3 = m_impl->m_modules.begin ();
705     for (; it3 != m_impl->m_modules.end (); it3++) {
706         if (*it3 == module) {
707             m_impl->m_modules.erase (it3);
708             break;
709         }
710     }
711
712     std::vector<IMEngineModule *>::iterator it4 = m_impl->m_engine_modules.begin ();
713     for (; it4 != m_impl->m_engine_modules.end (); it4++) {
714         if ((*it4)->get_module_name () == module) {
715             (*it4)->unload ();
716             delete (*it4);
717             m_impl->m_engine_modules.erase (it4);
718             break;
719         }
720     }
721     malloc_trim (0);
722 }
723
724 void
725 CommonBackEnd::add_module_info_from_cache_file (const ConfigPointer &config, std::vector<String> &modules)
726 {
727     SCIM_DEBUG_BACKEND (1) << __FUNCTION__ << "...\n";
728
729     FILE *engine_list_file = NULL;
730     FILE *user_engine_file = NULL;
731     char buf[MAXLINE];
732     bool isFirst = false;
733     std::vector<String> current_modules;
734
735     current_modules.clear ();
736
737     String user_file_name = String (USER_ENGINE_FILE_NAME);
738     String sys_file_name  = String (SYS_ENGINE_FILE_NAME);
739
740     engine_list_file = fopen (user_file_name.c_str (), "r");
741     if (engine_list_file == NULL) {
742         std::cerr <<  user_file_name << " doesn't exist.\n";
743         isFirst = true;
744
745         engine_list_file = fopen (sys_file_name.c_str (), "r");
746         if (engine_list_file == NULL) {
747             std::cerr <<  sys_file_name << " doesn't exist.\n";
748             goto failed_open;
749         }
750     }
751
752     /*
753      * If we start the system firstly, the engine list file in user directory
754      * doesn't exit, we should create it.
755      */
756     if (isFirst) {
757         user_engine_file = fopen (user_file_name.c_str (), "a");
758         if (user_engine_file == NULL)
759             std::cerr << "failed to open " << user_file_name << "\n";
760     }
761
762     while (fgets (buf, MAXLINE, engine_list_file) != NULL) {
763         if (isFirst && user_engine_file != NULL) {
764             if (fputs (buf, user_engine_file) == EOF)
765                 std::cerr << "failed to write " << user_file_name << "\n";
766         }
767
768         ISEINFO info;
769         isf_get_ise_info_from_string (buf, info);
770         std::vector<String>::iterator iter = std::find (modules.begin (), modules.end (), info.module);
771         if (info.mode == TOOLBAR_KEYBOARD_MODE && iter != modules.end ()) {
772             if (m_impl->m_factory_module_repository.find (info.uuid) == m_impl->m_factory_module_repository.end ()) {
773                 add_specific_factory (info.uuid, IMEngineFactoryPointer (0));
774                 m_impl->m_factory_module_repository[info.uuid] = info.module;
775             }
776
777             std::vector<String>::iterator iter2 = std::find (current_modules.begin (), current_modules.end (), info.module);
778             if (iter2 == current_modules.end ())
779                 current_modules.push_back (info.module);
780         }
781     }
782
783     if (isFirst && user_engine_file != NULL)
784         fclose (user_engine_file);
785     fclose (engine_list_file);
786
787 failed_open:
788     update_module_info (config, current_modules, modules);
789 }
790
791 void
792 CommonBackEnd::update_module_info (const ConfigPointer &config,
793                                    std::vector<String> &current_modules,
794                                    std::vector<String> &modules)
795 {
796     SCIM_DEBUG_BACKEND (1) << __FUNCTION__ << "...\n";
797
798     std::vector<String> imengine_list;
799     scim_get_imengine_module_list (imengine_list);
800     for (size_t i = 0; i < imengine_list.size (); ++i) {
801         if (std::find (modules.begin (), modules.end (), imengine_list [i]) != modules.end ()
802                 && std::find (current_modules.begin (), current_modules.end (), imengine_list [i]) == current_modules.end ())
803                 add_imengine_module_info (imengine_list [i], config);
804     }
805 }
806
807 void
808 CommonBackEnd::add_imengine_module_info (const String module_name, const ConfigPointer &config)
809 {
810     SCIM_DEBUG_BACKEND (1) << __FUNCTION__ << " : " << module_name << "\n";
811
812     if (module_name.length () <= 0 || module_name == "socket")
813         return;
814
815     IMEngineFactoryPointer factory;
816     IMEngineModule         ime_module;
817
818     String filename = String (USER_ENGINE_FILE_NAME);
819     FILE *engine_list_file = fopen (filename.c_str (), "a");
820     if (engine_list_file == NULL) {
821         std::cerr << "failed to open " << filename << "\n";
822         return;
823     }
824
825     ime_module.load (module_name, config);
826
827     if (ime_module.valid ()) {
828         for (size_t j = 0; j < ime_module.number_of_factories (); ++j) {
829             try {
830                 factory = ime_module.create_factory (j);
831             } catch (...) {
832                 factory.reset ();
833             }
834
835             if (!factory.null ()) {
836                 String uuid = factory->get_uuid ();
837                 String name = utf8_wcstombs (factory->get_name ());
838                 String language = isf_get_normalized_language (factory->get_language ());
839                 String icon = factory->get_icon_file ();
840                 char mode[12];
841                 char option[12];
842
843                 snprintf (mode, sizeof (mode), "%d", (int)TOOLBAR_KEYBOARD_MODE);
844                 snprintf (option, sizeof (option), "%d", 0);
845
846                 String line = isf_combine_ise_info_string (name, uuid, module_name, language,
847                                                            icon, String (mode), String (option), factory->get_locales ());
848                 if (fputs (line.c_str (), engine_list_file) < 0) {
849                     std::cerr << "write to ise cache file failed:" << line << "\n";
850                     break;
851                 }
852
853                 add_specific_factory (uuid, IMEngineFactoryPointer (0));
854                 m_impl->m_factory_module_repository[uuid] = module_name;
855
856                 factory.reset ();
857             }
858         }
859         ime_module.unload ();
860     }
861
862     fclose (engine_list_file);
863 }
864
865
866 } /* namespace scim */
867
868 /*
869 vi:ts=4:nowrap:ai:expandtab
870 */