Back to index

im-sdk  12.3.91
lexmlconf.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright 1990-2001 Sun Microsystems, Inc. All Rights Reserved.
00003 
00004 Permission is hereby granted, free of charge, to any person obtaining a
00005 copy of this software and associated documentation files (the
00006 "Software"), to deal in the Software without restriction, including
00007 without limitation the rights to use, copy, modify, merge, publish,
00008 distribute, sublicense, and/or sell copies of the Software, and to
00009 permit persons to whom the Software is furnished to do so, subject to
00010 the following conditions: The above copyright notice and this
00011 permission notice shall be included in all copies or substantial
00012 portions of the Software.
00013 
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00016 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00017 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00018 IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
00019 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
00020 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
00021 THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
00022 ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.
00023 
00024 
00025 Except as contained in this notice, the names of The Open Group and/or
00026 Sun Microsystems, Inc. shall not be used in advertising or otherwise to
00027 promote the sale, use or other dealings in this Software without prior
00028 written authorization from The Open Group and/or Sun Microsystems,
00029 Inc., as applicable.
00030 
00031 
00032 X Window System is a trademark of The Open Group
00033 
00034 OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
00035 logo, LBX, X Window System, and Xinerama are trademarks of the Open
00036 Group. All other trademarks and registered trademarks mentioned herein
00037 are the property of their respective owners. No right, title or
00038 interest in or to any trademark, service mark, logo or trade name of
00039 Sun Microsystems, Inc. or its licensors is granted.
00040 
00041 */
00042 
00043 #ifdef HAVE_CONFIG_H
00044 #include <config.h>
00045 #endif
00046 #include <errno.h>
00047 #include <libxml/parser.h>
00048 #include <libxml/tree.h>
00049 #include <string>
00050 #include "lexmlconf.h"
00051 #include "IMLog.hh"
00052 #include "IMKeyUtils.hh"
00053 #include "keysyms.h"
00054 
00055 #define       EMPTY_NODE_ERROR(n)         LOG_ERROR("<%s> is an empty node.", n)
00056 #define       DUPLICATED_NODE_ERROR(n, p) LOG_ERROR("<%s> had the duplicated node `<%s>'", p, n)
00057 #define       UNKNOWN_NODE_ERROR(n, p)    LOG_WARNING("<%s> had an unknown node `<%s>'", p, n)
00058 #define       INVALID_NODE_ERROR(n, v)    LOG_ERROR("<%s> is an invalid node. [%s]", n, v)
00059 #define       MISSING_NODE_ERROR(n, p)    LOG_ERROR("<%s> is missing in <%s>", n, p)
00060 
00061 
00062 struct _LEEntry {
00063        char *language;
00064        IIIMLEInfoList *list;
00065        struct _LEEntry *next;
00066 };
00067 struct _HotKeyEntry {
00068        char *language;
00069        HotKeyList *list;
00070        struct _HotKeyEntry *next;
00071 };
00072 struct _IIIMLEXMLConfPrivate {
00073        struct _LEEntry     *entries;
00074        IIIMLELanguageList  *lang_list;
00075        struct _HotKeyEntry *hotkeys;
00076 };
00077 
00078 static IIIMLEInfoList     *iiim_le_info_list_new     (IIIMLEInfo         *leinfo);
00079 static IIIMLEInfoList     *iiim_le_info_list_add     (IIIMLEInfoList     *list,
00080                                                 IIIMLEInfo         *leinfo);
00081 static IIIMLEInfo         *iiim_le_info_list_find    (IIIMLEInfoList     *list,
00082                                                 IIIMLEInfo         *leinfo);
00083 static void                iiim_le_info_list_free    (IIIMLEInfoList     *list);
00084 static IIIMLEInfo         *iiim_le_info_new          (const char         *language,
00085                                                 const char         *modulename);
00086 static void                iiim_le_info_free         (IIIMLEInfo         *leinfo);
00087 static IIIMLELanguageList *iiim_le_lang_list_new     (const char         *langugae);
00088 static IIIMLELanguageList *iiim_le_lang_list_add     (IIIMLELanguageList *list,
00089                                                 const char         *language);
00090 static IIIMLELanguageList *iiim_le_lang_list_remove  (IIIMLELanguageList *list,
00091                                                 const char         *language);
00092 static void                iiim_le_lang_list_free    (IIIMLELanguageList *list);
00093 static void                iiim_le_xmlconf_remove_hotkeys(IIIMLEXMLConf *conf);
00094 
00095 static void        parse_key_node    (IIIMLEXMLConf *conf,
00096                                   xmlNodePtr    &node,
00097                                   std::string   &modname);
00098 static void        parse_module_node (IIIMLEXMLConf *conf,
00099                                   xmlNodePtr    &node,
00100                                   std::string   &language);
00101 static void        parse_le_node     (IIIMLEXMLConf *conf,
00102                                   xmlNodePtr    &node);
00103 static void        parse_les_node    (IIIMLEXMLConf *conf,
00104                                   xmlNodePtr    &node);
00105 
00106 IMLog *__imlog = NULL;
00107 
00108 
00109 static IIIMLEInfoList *
00110 iiim_le_info_list_new(IIIMLEInfo *leinfo)
00111 {
00112        IIIMLEInfoList *list;
00113 
00114        list = (IIIMLEInfoList *)malloc(sizeof (IIIMLEInfoList) * 1);
00115        list->data = leinfo;
00116        list->next = NULL;
00117 
00118        return list;
00119 }
00120 
00121 static IIIMLEInfoList *
00122 iiim_le_info_list_add(IIIMLEInfoList *list,
00123                     IIIMLEInfo     *leinfo)
00124 {
00125        IIIMLEInfoList *l, *ll;
00126 
00127        l = iiim_le_info_list_new(leinfo);
00128        if (list != NULL) {
00129               for (ll = list; ll->next != NULL; ll = ll->next);
00130               ll->next = l;
00131               ll = list;
00132        } else {
00133               ll = l;
00134        }
00135 
00136        return ll;
00137 }
00138 
00139 static IIIMLEInfoList *
00140 iiim_le_info_list_prepend(IIIMLEInfoList *list,
00141                        IIIMLEInfo     *leinfo)
00142 {
00143        IIIMLEInfoList *l;
00144 
00145        l = iiim_le_info_list_new(leinfo);
00146        if (list != NULL) {
00147               l->next = list;
00148        }
00149 
00150        return l;
00151 }
00152 
00153 static IIIMLEInfoList *
00154 iiim_le_info_list_remove(IIIMLEInfoList *list,
00155                       IIIMLEInfo     *leinfo)
00156 {
00157        IIIMLEInfoList *tmp, *prev = NULL;
00158 
00159        tmp = list;
00160        while (tmp) {
00161               if (tmp->data == leinfo) {
00162                      if (prev)
00163                             prev->next = tmp->next;
00164                      else
00165                             list = tmp->next;
00166                      iiim_le_info_free(tmp->data);
00167                      free(tmp);
00168 
00169                      break;
00170               }
00171               prev = tmp;
00172               tmp = prev->next;
00173        }
00174 
00175        return list;
00176 }
00177 
00178 static IIIMLEInfo *
00179 iiim_le_info_list_find(IIIMLEInfoList *list,
00180                      IIIMLEInfo     *leinfo)
00181 {
00182        IIIMLEInfoList *l;
00183 
00184        if (leinfo == NULL || leinfo->language == NULL || leinfo->lename == NULL)
00185               return NULL;
00186 
00187        for (l = list; l != NULL; l = l->next) {
00188               IIIMLEInfo *ll = l->data;
00189 
00190               if (!strcmp(ll->language, leinfo->language) &&
00191                   !strcmp(ll->lename, leinfo->lename)) {
00192                      return ll;
00193               }
00194        }
00195 
00196        return NULL;
00197 }
00198 
00199 static void
00200 iiim_le_info_list_free(IIIMLEInfoList *list)
00201 {
00202        IIIMLEInfoList *last;
00203 
00204        while (list) {
00205               last = list;
00206               list = last->next;
00207               if (last->data)
00208                      iiim_le_info_free(last->data);
00209               free(last);
00210        }
00211 }
00212 
00213 static IIIMLEInfo *
00214 iiim_le_info_new(const char *language,
00215                const char *modulename)
00216 {
00217        IIIMLEInfo *leinfo;
00218 
00219        if (language == NULL || modulename == NULL)
00220               return NULL;
00221 
00222        leinfo = (IIIMLEInfo *)malloc(sizeof (IIIMLEInfo) * 1);
00223        leinfo->language = strdup(language);
00224        leinfo->lename = strdup(modulename);
00225 
00226        return leinfo;
00227 }
00228 
00229 static void
00230 iiim_le_info_free(IIIMLEInfo *leinfo)
00231 {
00232        if (leinfo == NULL)
00233               return;
00234 
00235        if (leinfo->language)
00236               free(leinfo->language);
00237        if (leinfo->lename)
00238               free(leinfo->lename);
00239        free(leinfo);
00240 }
00241 
00242 static IIIMLELanguageList *
00243 iiim_le_lang_list_new(const char *language)
00244 {
00245        IIIMLELanguageList *list;
00246 
00247        list = (IIIMLELanguageList *)malloc(sizeof (IIIMLELanguageList) * 1);
00248        list->language = strdup(language);
00249        list->next = NULL;
00250 
00251        return list;
00252 }
00253 
00254 static IIIMLELanguageList *
00255 iiim_le_lang_list_add(IIIMLELanguageList *list,
00256                     const char         *language)
00257 {
00258        IIIMLELanguageList *ll, *prev;
00259 
00260        if (list != NULL) {
00261               for (ll = list, prev = list; ll != NULL; prev = ll, ll = prev->next) {
00262                      if (!strcmp(ll->language, language)) {
00263                             return list;
00264                      }
00265               }
00266               prev->next = iiim_le_lang_list_new(language);
00267               ll = list;
00268        } else {
00269               ll = iiim_le_lang_list_new(language);
00270        }
00271 
00272        return ll;
00273 }
00274 
00275 static IIIMLELanguageList *
00276 iiim_le_lang_list_remove(IIIMLELanguageList *list,
00277                       const char         *language)
00278 {
00279        IIIMLELanguageList *tmp, *prev = NULL;
00280 
00281        tmp = list;
00282        while (tmp) {
00283               if (!strcmp(tmp->language, language)) {
00284                      if (prev)
00285                             prev->next = tmp->next;
00286                      else
00287                             list = tmp->next;
00288                      if (tmp->language)
00289                             free(tmp->language);
00290                      free(tmp);
00291 
00292                      break;
00293               }
00294               prev = tmp;
00295               tmp = prev->next;
00296        }
00297 
00298        return list;
00299 }
00300 
00301 static void
00302 iiim_le_lang_list_free(IIIMLELanguageList *list)
00303 {
00304        IIIMLELanguageList *last;
00305 
00306        while (list) {
00307               last = list;
00308               list = last->next;
00309               if (last->language)
00310                      free(last->language);
00311               free(last);
00312        }
00313 }
00314 
00315 static int
00316 _symbol2mask(const char *mod)
00317 {
00318        struct _modlist {
00319               char *symbol;
00320               int id;
00321        } modlist[] = {
00322               {"Shift", 1},
00323               {"Control", 2},
00324               {"Meta", 4},
00325               {"Alt", 8},
00326               {"AltGr", 16},
00327               {NULL, 0},
00328        };
00329        char *m, *p, *pp, *next;
00330        int retval = 0, i;
00331 
00332        if (mod == NULL)
00333               return 0;
00334 
00335        m = p = strdup(mod);
00336        while (p) {
00337               pp = strchr(p, ' ');
00338               if (pp != NULL) {
00339                      *pp = 0;
00340                      next = pp + 1;
00341               } else {
00342                      next = NULL;
00343               }
00344               for (i = 0; modlist[i].symbol != NULL; i++) {
00345                      if (!strcasecmp(modlist[i].symbol, p)) {
00346                             retval |= modlist[i].id;
00347                             break;
00348                      }
00349               }
00350               p = next;
00351        }
00352        free(m);
00353 
00354        return retval;
00355 }
00356 
00357 static int
00358 _compare_modifiers(const char *mod1, const char *mod2)
00359 {
00360        int mask1, mask2;
00361 
00362        mask1 = _symbol2mask(mod1);
00363        mask2 = _symbol2mask(mod2);
00364 
00365        return mask1 - mask2;
00366 }
00367 
00368 static void
00369 parse_key_node(IIIMLEXMLConf *conf,
00370               xmlNodePtr    &node,
00371               std::string   &language)
00372 {
00373        xmlChar *mod, *k;
00374        std::string modifier, key;
00375        HotKeyStruct *hotkey;
00376 
00377        mod = xmlGetProp(node, (xmlChar *)"modifier");
00378        k = xmlGetProp(node, (xmlChar *)"name");
00379        modifier = (const char *)mod;
00380        key = (const char *)k;
00381        if (mod != NULL)
00382               xmlFree(mod);
00383        if (k != NULL)
00384               xmlFree(k);
00385        if (key.empty()) {
00386               LOG_DEBUG("<key> needs 'name' attribute.");
00387               return;
00388        }
00389 
00390        LOG_DEBUG("<key modifier=\"%s\" name=\"%s\">", modifier.c_str(), key.c_str());
00391 
00392        hotkey = iiim_le_hotkey_struct_new(key.c_str(), modifier.c_str());
00393        iiim_le_xmlconf_append_hotkey(conf, hotkey, language.c_str());
00394 
00395        node = node->xmlChildrenNode;
00396 
00397        while (node != NULL) {
00398               if (xmlStrcmp(node->name, (xmlChar *)"text") == 0 ||
00399                   xmlStrcmp(node->name, (xmlChar *)"comment") == 0) {
00400                      /* ignore text and comment node */
00401                      node = node->next;
00402               } else {
00403                      /* ignore the unknown nodes */
00404                      UNKNOWN_NODE_ERROR(node->name, "key");
00405                      node = node->next;
00406               }
00407        }
00408 }
00409 
00410 static void
00411 parse_hotkey_node(IIIMLEXMLConf *conf,
00412                 xmlNodePtr    &node,
00413                 std::string   &language)
00414 {
00415        xmlNodePtr topnode = NULL;
00416        std::string path;
00417 
00418        LOG_DEBUG("<hotkey>");
00419 
00420        node = node->xmlChildrenNode;
00421 
00422        while (node != NULL) {
00423               if (xmlStrcmp(node->name, (xmlChar *)"key") == 0) {
00424                      topnode = node;
00425                      parse_key_node(conf, node, language);
00426                      node = topnode->next;
00427               } else if (xmlStrcmp(node->name, (xmlChar *)"text") == 0
00428                         || xmlStrcmp(node->name, (xmlChar *)"comment") == 0) {
00429                      /* ignore text and comment node */
00430                      node = node->next;
00431               } else {
00432                      /* ignore the unknown nodes */
00433                      UNKNOWN_NODE_ERROR(node->name, "hotkey");
00434                      node = node->next;
00435               }
00436        }
00437 }
00438 
00439 static void
00440 parse_module_node(IIIMLEXMLConf *conf,
00441                 xmlNodePtr    &node,
00442                 std::string   &language)
00443 {
00444        xmlChar *p;
00445        std::string path;
00446 
00447        p = xmlGetProp(node, (xmlChar *)"path");
00448        path = (const char *)p;
00449        if (p != NULL)
00450               xmlFree(p);
00451        if (path.empty()) {
00452               LOG_DEBUG("<module> needs 'path' attribute.");
00453               return;
00454        }
00455 
00456        LOG_DEBUG("<module path=\"%s\">", path.c_str());
00457        iiim_le_xmlconf_append_module(conf, path.c_str(), language.c_str());
00458 
00459        node = node->xmlChildrenNode;
00460 
00461        while (node != NULL) {
00462               if (xmlStrcmp(node->name, (xmlChar *)"text") == 0
00463                         || xmlStrcmp(node->name, (xmlChar *)"comment") == 0) {
00464                      /* ignore text and comment node */
00465                      node = node->next;
00466               } else {
00467                      /* ignore the unknown nodes */
00468                      UNKNOWN_NODE_ERROR(node->name, "module");
00469                      node = node->next;
00470               }
00471        }
00472 }
00473 
00474 static void
00475 parse_le_node(IIIMLEXMLConf *conf, xmlNodePtr &node)
00476 {
00477        xmlNodePtr topnode = NULL;
00478        xmlChar *l;
00479        std::string lang;
00480 
00481        l = xmlGetProp(node, (xmlChar *)"lang");
00482        lang = (const char *)l;
00483 
00484        if (l != NULL)
00485               xmlFree(l);
00486        if (lang.empty()) {
00487               LOG_DEBUG("<LanguageEngine> needs 'lang' attribute.");
00488               return;
00489        }
00490 
00491        node = node->xmlChildrenNode;
00492 
00493        while (node != NULL) {
00494               if (xmlStrcmp(node->name, (xmlChar *)"module") == 0) {
00495                      topnode = node;
00496                      parse_module_node(conf, node, lang);
00497                      node = topnode->next;
00498               } else if (xmlStrcmp(node->name, (xmlChar *)"hotkey") == 0) {
00499                      topnode = node;
00500                      parse_hotkey_node(conf, node, lang);
00501                      node = topnode->next;
00502               } else if (xmlStrcmp(node->name, (xmlChar *)"text") == 0 ||
00503                         xmlStrcmp(node->name, (xmlChar *)"comment") == 0) {
00504                      /* ignore text and comment node */
00505                      node = node->next;
00506               } else {
00507                      /* ignore the unknown nodes */
00508                      UNKNOWN_NODE_ERROR(node->name, "LanguageEngine");
00509                      node = node->next;
00510               }
00511        }
00512 }
00513 
00514 static void
00515 parse_les_node(IIIMLEXMLConf *conf, xmlNodePtr &node)
00516 {
00517        xmlNodePtr topnode = NULL;
00518 
00519        while (node != NULL) {
00520               if (xmlStrcmp(node->name, (xmlChar *)"LanguageEngine") == 0) {
00521                      topnode = node;
00522                      parse_le_node(conf, node);
00523                      node = topnode->next;
00524                      topnode = NULL;
00525               } else if (xmlStrcmp(node->name, (xmlChar *)"text") == 0
00526                         || xmlStrcmp(node->name, (xmlChar *)"comment") == 0) {
00527                      /* ignore text and comment node */
00528                      node = node->next;
00529               } else {
00530                      /* ignore the unknown nodes */
00531                      UNKNOWN_NODE_ERROR(node->name, "LanguageEngines");
00532                      node = node->next;
00533               }
00534        }
00535 }
00536 
00537 void
00538 iiim_log_init(const char *name)
00539 {
00540        if (__imlog == NULL)
00541               __imlog = IMLog::construct(name);
00542 }
00543 
00544 void
00545 iiim_log_debug_mode(void)
00546 {
00547        IMLog::get_instance()->set_log_level(IMLog::DEBUGLOG);
00548        IMLog::get_instance()->set_default_destination(IMLog::IMLOG_STDERR);
00549 }
00550 
00551 IIIMLEXMLConf *
00552 iiim_le_xmlconf_new(const char *filename)
00553 {
00554        IIIMLEXMLConf *conf;
00555 
00556        /* need to initialize IMLog instance here to use LOG_* macros. */
00557        iiim_log_init(__FILE__);
00558 
00559        if (filename == NULL)
00560               return NULL;
00561 
00562        conf = (IIIMLEXMLConf *) malloc(sizeof (IIIMLEXMLConf) * 1);
00563        conf->filename = strdup(filename);
00564        conf->priv = (IIIMLEXMLConfPrivate *)malloc(sizeof (IIIMLEXMLConfPrivate) * 1);
00565        conf->priv->entries = NULL;
00566        conf->priv->lang_list = NULL;
00567        conf->priv->hotkeys = NULL;
00568 
00569        return conf;
00570 }
00571 
00572 static void
00573 iiim_le_xmlconf_remove_modules(IIIMLEXMLConf *conf)
00574 {
00575        struct _LEEntry *e, *tmp;
00576 
00577        e = conf->priv->entries;
00578        while (e) {
00579               tmp = e;
00580               e = tmp->next;
00581               free(tmp->language);
00582               iiim_le_info_list_free(tmp->list);
00583               free(tmp);
00584        }
00585        conf->priv->entries = NULL;
00586        if (conf->priv->lang_list)
00587               iiim_le_lang_list_free(conf->priv->lang_list);
00588        conf->priv->lang_list = NULL;
00589 }
00590 
00591 void
00592 iiim_le_xmlconf_free(IIIMLEXMLConf *conf)
00593 {
00594        if (conf == NULL)
00595               return;
00596 
00597        if (conf->filename)
00598               free(conf->filename);
00599        iiim_le_xmlconf_remove_modules(conf);
00600        iiim_le_xmlconf_remove_hotkeys(conf);
00601        free(conf->priv);
00602 
00603        free(conf);
00604 }
00605 
00606 static int
00607 _parse_xml(IIIMLEXMLConf *conf, xmlDocPtr doc)
00608 {
00609     xmlNodePtr root = NULL, node, topnode = NULL;
00610     int retval = 0;
00611 
00612     if ((root = xmlDocGetRootElement(doc)) == NULL)
00613        goto ensure;
00614     if (xmlStrcmp(root->name, (xmlChar *)"iiimf") != 0)
00615        goto ensure;
00616 
00617     node = root->xmlChildrenNode;
00618     while (node != NULL) {
00619        if (xmlStrcmp(node->name, (xmlChar *)"LanguageEngines") == 0) {
00620            topnode = node;
00621            node = node->xmlChildrenNode;
00622            parse_les_node(conf, node);
00623            node = topnode->next;
00624            topnode = NULL;
00625        } else if (xmlStrcmp(node->name, (xmlChar *)"text") == 0
00626                  || xmlStrcmp(node->name, (xmlChar *)"comment") == 0) {
00627            /* ignore text and comment node */
00628            node = node->next;
00629        } else {
00630            /* ignore the unknown nodes */
00631            UNKNOWN_NODE_ERROR(node->name, "iiimf");
00632            node = node->next;
00633        }
00634     }
00635     retval = 1;
00636 
00637   ensure:
00638     if (doc != NULL)
00639        xmlFreeDoc(doc);
00640 
00641     return retval;
00642 }
00643 
00644 int
00645 iiim_le_xmlconf_load_file(IIIMLEXMLConf *conf)
00646 {
00647 #ifdef HAVE_XMLCTXTREAD
00648     xmlParserCtxtPtr parser = NULL;
00649 #endif
00650     xmlDocPtr doc = NULL;
00651     int retval = 0;
00652 
00653     if (conf == NULL)
00654            return 0;
00655     if (conf->filename == NULL)
00656            return 0;
00657 
00658     /* make sure that there is no older data */
00659     if (!iiim_le_xmlconf_is_empty_module(conf)) {
00660            iiim_le_xmlconf_remove_modules(conf);
00661            iiim_le_xmlconf_remove_hotkeys(conf);
00662     }
00663 
00664 #ifdef HAVE_XMLCTXTREAD
00665     parser = xmlNewParserCtxt();
00666     if ((doc = xmlCtxtReadFile(parser, conf->filename, "UTF-8", 0)) == NULL) {
00667 #else
00668     if ((doc = xmlParseFile(conf->filename)) == NULL) {
00669 #endif
00670        goto ensure;
00671 #ifdef HAVE_XMLCTXTREAD
00672     }
00673 #else
00674     }
00675 #endif
00676 
00677     retval = _parse_xml(conf, doc);
00678 
00679   ensure:
00680 #ifdef HAVE_XMLCTXTREAD
00681     if (parser != NULL)
00682        xmlFreeParserCtxt(parser);
00683 #endif
00684 
00685     return retval;
00686 }
00687 
00688 int
00689 iiim_le_xmlconf_load_with_nsio(IIIMLEXMLConf *conf,
00690                             iml_desktop_t *iml_desktop)
00691 {
00692     xmlDocPtr doc = NULL;
00693     int retval = 0;
00694     iml_nsc_create_t nsc_create = (iml_nsc_create_t)(iml_desktop->If->nsc_get_function("_nsc_create"));
00695     iml_nsc_free_t nsc_free = (iml_nsc_free_t)(iml_desktop->If->nsc_get_function("_nsc_free"));
00696     iml_nsc_open_t nsc_open = (iml_nsc_open_t)(iml_desktop->If->nsc_get_function("open"));
00697     iml_nsc_close_t nsc_close = (iml_nsc_close_t)(iml_desktop->If->nsc_get_function("close"));
00698     iml_nsc_read_t nsc_read = (iml_nsc_read_t)(iml_desktop->If->nsc_get_function("read"));
00699     iml_nsc_lstat_t nsc_lstat = (iml_nsc_lstat_t)(iml_desktop->If->nsc_get_function("lstat"));
00700     iml_nsc_t nsc = NULL;
00701     int fd = 0, size;
00702     size_t len;
00703     char *buffer = NULL;
00704     struct stat st;
00705 
00706     if (conf == NULL)
00707            return 0;
00708     if (conf->filename == NULL)
00709            return 0;
00710 
00711     /* make sure that there is no older data */
00712     if (!iiim_le_xmlconf_is_empty_module(conf)) {
00713            iiim_le_xmlconf_remove_modules(conf);
00714            iiim_le_xmlconf_remove_hotkeys(conf);
00715     }
00716 
00717     /* FIXME: read the conf here */
00718     nsc = (iml_nsc_t)nsc_create("IIIMLEXMLConf", IML_NSC_TYPE_DESKTOP, iml_desktop);
00719     if (nsc_lstat(nsc, conf->filename, &st) == -1) {
00720            LOG_DEBUG("Failed to stat %s via the namespace I/O: %s", conf->filename, strerror(errno));
00721            goto ensure;
00722     }
00723     size = st.st_size;
00724     buffer = (char *)malloc(sizeof (char) * (size + 1));
00725     if ((fd = nsc_open(nsc, conf->filename, O_RDONLY)) == -1) {
00726            LOG_DEBUG("Failed to open %s via the namespace I/O: %s", conf->filename, strerror(errno));
00727            goto ensure;
00728     }
00729     if ((len = nsc_read(nsc, fd, buffer, size)) == -1) {
00730            LOG_DEBUG("Failed to read %s via the namespace I/O: %s", conf->filename, strerror(errno));
00731            goto ensure;
00732     }
00733     nsc_close(nsc, fd);
00734     fd = 0;
00735 
00736     if ((doc = xmlParseMemory(buffer, size)) == NULL) {
00737            goto ensure;
00738     }
00739 
00740     retval = _parse_xml(conf, doc);
00741 
00742   ensure:
00743     if (fd > 0)
00744            nsc_close(nsc, fd);
00745     if (buffer)
00746            free(buffer);
00747     if (nsc)
00748            nsc_free(nsc);
00749 
00750     return retval;
00751 }
00752 
00753 int
00754 iiim_le_xmlconf_save_file(IIIMLEXMLConf *conf)
00755 {
00756        xmlDocPtr doc = NULL;
00757        xmlNodePtr root, les, le, node, key;
00758        xmlAttrPtr attr;
00759        int retval = 1;
00760        struct _LEEntry *ent;
00761 
00762        if (conf == NULL)
00763               return 0;
00764 
00765        doc = xmlNewDoc((xmlChar *)"1.0");
00766        doc->encoding = xmlStrdup((xmlChar *)"UTF-8");
00767        root = xmlNewDocNode(doc, NULL, (xmlChar *)"iiimf", NULL);
00768        xmlDocSetRootElement(doc, root);
00769        les = xmlNewTextChild(root, NULL, (xmlChar *)"LanguageEngines", NULL);
00770        xmlSaveFile(conf->filename, doc);
00771 
00772        if (conf->priv->entries != NULL) {
00773               for (ent = conf->priv->entries; ent != NULL; ent = ent->next) {
00774                      IIIMLEInfoList *l;
00775                      struct _HotKeyEntry *hent;
00776                      HotKeyList *hlist, *h;
00777 
00778                      le = xmlNewTextChild(les, NULL, (xmlChar *)"LanguageEngine", NULL);
00779                      attr = xmlNewProp(le, (xmlChar *)"lang", (xmlChar *)ent->language);
00780                      for (l = ent->list; l != NULL; l = l->next) {
00781                             IIIMLEInfo *ll = l->data;
00782 
00783                             node = xmlNewTextChild(le, NULL, (xmlChar *)"module", NULL);
00784                             attr = xmlNewProp(node, (xmlChar *)"path", (xmlChar *)ll->lename);
00785                      }
00786                      for (hent = conf->priv->hotkeys; hent != NULL; hent = hent->next) {
00787                             if (!strcmp(hent->language, ent->language)) {
00788                                    node = xmlNewTextChild(le, NULL, (xmlChar *)"hotkey", NULL);
00789                                    hlist = hent->list;
00790                                    for (h = hlist; h != NULL; h = h->next) {
00791                                           key = xmlNewTextChild(node, NULL, (xmlChar *)"key", NULL);
00792                                           if (h->hotkey->modifiers != NULL)
00793                                                  attr = xmlNewProp(key, (xmlChar *)"modifier", (xmlChar *)h->hotkey->modifiers);
00794                                           attr = xmlNewProp(key, (xmlChar *)"name", (xmlChar *)h->hotkey->key);
00795                                    }
00796                             }
00797                      }
00798               }
00799        } else {
00800               struct _HotKeyEntry *hent;
00801               HotKeyList *hlist, *h;
00802 
00803               /* try to store the hotkeys only */
00804               for (hent = conf->priv->hotkeys; hent != NULL; hent = hent->next) {
00805                      le = xmlNewTextChild(les, NULL, (xmlChar *)"LanguageEngine", NULL);
00806                      attr = xmlNewProp(le, (xmlChar *)"lang", (xmlChar *)hent->language);
00807 
00808                      node = xmlNewTextChild(le, NULL, (xmlChar *)"hotkey", NULL);
00809                      hlist = hent->list;
00810                      for (h = hlist; h != NULL; h = h->next) {
00811                             key = xmlNewTextChild(node, NULL, (xmlChar *)"key", NULL);
00812                             if (h->hotkey->modifiers != NULL)
00813                                    attr = xmlNewProp(key, (xmlChar *)"modifier", (xmlChar *)h->hotkey->modifiers);
00814                             attr = xmlNewProp(key, (xmlChar *)"name", (xmlChar *)h->hotkey->key);
00815                      }
00816               }
00817        }
00818        if (xmlSaveFile(conf->filename, doc) > 0)
00819               retval = true;
00820 
00821        if (doc != NULL)
00822               xmlFreeDoc(doc);
00823 
00824        return 1;
00825 }
00826 
00827 int
00828 iiim_le_xmlconf_is_empty_module(IIIMLEXMLConf *conf)
00829 {
00830        if (conf == NULL)
00831               return 0;
00832        return conf->priv->entries == NULL;
00833 }
00834 
00835 int
00836 iiim_le_xmlconf_append_module(IIIMLEXMLConf *conf,
00837                            const char    *modulename,
00838                            const char    *language)
00839 {
00840        IIIMLEInfo *leinfo, *le;
00841        struct _LEEntry *ent;
00842        int stored = 0;
00843 
00844        if (conf == NULL)
00845               return 0;
00846 
00847        leinfo = iiim_le_info_new(language, modulename);
00848        if (leinfo == NULL)
00849               return 0;
00850 
00851        for (ent = conf->priv->entries; ent != NULL; ent = ent->next) {
00852               if (!strcmp(ent->language, language)) {
00853                      le = iiim_le_info_list_find(ent->list, leinfo);
00854                      if (le != NULL) {
00855                             LOG_DEBUG("LE (lang:%s, %s) has already been registered.", language, le->lename);
00856                             iiim_le_info_free(leinfo);
00857 
00858                             return 0;
00859                      }
00860                      LOG_DEBUG("Adding LE (lang:%s, %s)", language, modulename);
00861                      ent->list = iiim_le_info_list_add(ent->list, leinfo);
00862                      stored = 1;
00863                      break;
00864               }
00865        }
00866        if (!stored) {
00867               struct _LEEntry *entry, *tmp;
00868 
00869               entry = (struct _LEEntry *)malloc(sizeof (struct _LEEntry) * 1);
00870 
00871               LOG_DEBUG("Adding LE (lang:%s, %s)", language, modulename);
00872               entry->language = strdup(language);
00873               entry->list = iiim_le_info_list_new(leinfo);
00874               entry->next = NULL;
00875               if (conf->priv->entries != NULL) {
00876                      for (tmp = conf->priv->entries; tmp->next != NULL; tmp = tmp->next);
00877                      tmp->next = entry;
00878               } else {
00879                      conf->priv->entries = entry;
00880               }
00881        }
00882        conf->priv->lang_list = iiim_le_lang_list_add(conf->priv->lang_list,
00883                                                 language);
00884 
00885        return 1;
00886 }
00887 
00888 int
00889 iiim_le_xmlconf_prepend_module(IIIMLEXMLConf *conf,
00890                             const char    *modulename,
00891                             const char    *language)
00892 {
00893        IIIMLEInfo *leinfo, *le;
00894        struct _LEEntry *ent;
00895        int stored = 0;
00896 
00897        if (conf == NULL)
00898               return 0;
00899        leinfo = iiim_le_info_new(language, modulename);
00900        if (leinfo == NULL)
00901               return 0;
00902 
00903        for (ent = conf->priv->entries; ent != NULL; ent = ent->next) {
00904               if (!strcmp(ent->language, language)) {
00905                      le = iiim_le_info_list_find(ent->list, leinfo);
00906                      if (le != NULL) {
00907                             LOG_DEBUG("Removing old entry of LE (lang:%s, %s)", language, le->lename);
00908                             ent->list = iiim_le_info_list_remove(ent->list, le);
00909                      }
00910                      LOG_DEBUG("Prepending LE (lang:%s, %s)", language, modulename);
00911                      ent->list = iiim_le_info_list_prepend(ent->list, leinfo);
00912                      stored = 1;
00913                      break;
00914               }
00915        }
00916        if (!stored) {
00917               struct _LEEntry *entry, *tmp;
00918               IIIMLEInfo *info;
00919 
00920               entry = (struct _LEEntry *)malloc(sizeof (struct _LEEntry) * 1);
00921               info = iiim_le_info_new(language, modulename);
00922 
00923               LOG_DEBUG("Prepending LE (lang:%s, %s)", language, modulename);
00924               entry->language = strdup(language);
00925               entry->list = iiim_le_info_list_new(info);
00926               entry->next = NULL;
00927               if (conf->priv->entries != NULL) {
00928                      for (tmp = conf->priv->entries; tmp->next != NULL; tmp = tmp->next);
00929                      tmp->next = entry;
00930               } else {
00931                      conf->priv->entries = entry;
00932               }
00933        }
00934        conf->priv->lang_list = iiim_le_lang_list_add(conf->priv->lang_list,
00935                                                 language);
00936 
00937        return 1;
00938 }
00939 
00940 int
00941 iiim_le_xmlconf_remove_module(IIIMLEXMLConf *conf,
00942                            const char    *modulename,
00943                            const char    *language)
00944 {
00945        IIIMLEInfo *leinfo, *le;
00946        struct _LEEntry *ent, *prev;
00947        int removed = 0;
00948 
00949        if (conf == NULL || modulename == NULL || language == NULL)
00950               return 0;
00951 
00952        leinfo = iiim_le_info_new(language, modulename);
00953 
00954        for (ent = conf->priv->entries, prev = NULL; ent != NULL; prev = ent, ent = prev->next) {
00955               if (!strcmp(ent->language, language)) {
00956                      le = iiim_le_info_list_find(ent->list, leinfo);
00957                      if (le != NULL) {
00958                             LOG_DEBUG("Removing LE (lang:%s, %s)", language, le->lename);
00959                             ent->list = iiim_le_info_list_remove(ent->list, le);
00960                             if (ent->list == NULL) {
00961                                    free(ent->language);
00962                                    conf->priv->lang_list = iiim_le_lang_list_remove(conf->priv->lang_list,
00963                                                                               language);
00964                                    if (prev != NULL) {
00965                                           prev->next = ent->next;
00966                                    } else {
00967                                           conf->priv->entries = NULL;
00968                                    }
00969                                    free(ent);
00970                             }
00971                             removed = 1;
00972                             break;
00973                      } else {
00974                             break;
00975                      }
00976               }
00977        }
00978 
00979        iiim_le_info_free(leinfo);
00980 
00981        return removed;
00982 }
00983 
00984 IIIMLEInfoList *
00985 iiim_le_xmlconf_get_le_info_list(IIIMLEXMLConf *conf,
00986                              const char    *language)
00987 {
00988        struct _LEEntry *ent;
00989        IIIMLEInfoList *retval = NULL;
00990 
00991        if (conf == NULL || language == NULL || language[0] == 0)
00992               return NULL;
00993 
00994        for (ent = conf->priv->entries; ent != NULL; ent = ent->next) {
00995               if (!strcmp(ent->language, language)) {
00996                      retval = ent->list;
00997                      break;
00998               }
00999        }
01000 
01001        return retval;
01002 }
01003 
01004 IIIMLELanguageList *
01005 iiim_le_xmlconf_get_lang_list(IIIMLEXMLConf *conf)
01006 {
01007        return conf->priv->lang_list;
01008 }
01009 
01010 int
01011 iiim_le_xmlconf_is_empty_hotkey(IIIMLEXMLConf *conf)
01012 {
01013        if (conf == NULL)
01014               return 0;
01015        return conf->priv->hotkeys == NULL;
01016 }
01017 
01018 int
01019 iiim_le_xmlconf_append_hotkey(IIIMLEXMLConf *conf,
01020                            HotKeyStruct  *hotkey,
01021                            const char    *language)
01022 {
01023        HotKeyList *list;
01024        struct _HotKeyEntry *ent;
01025        int stored = 0;
01026 
01027        if (conf == NULL || hotkey == NULL || language == NULL)
01028               return 0;
01029 
01030        for (ent = conf->priv->hotkeys; ent != NULL; ent = ent->next) {
01031               if (!strcmp(ent->language, language)) {
01032                      list = iiim_le_hotkey_list_find(ent->list, hotkey);
01033                      if (list != NULL) {
01034                             LOG_DEBUG("Hotkey (lang:%s, key:%s, modifier:%s) has already been registered.", language, hotkey->key, hotkey->modifiers);
01035                             return 0;
01036                      }
01037                      LOG_DEBUG("Adding Hotkey (lang:%s, key:%s, modifier:%s)", language, hotkey->key, hotkey->modifiers);
01038                      ent->list = iiim_le_hotkey_list_add(ent->list, hotkey);
01039                      stored = 1;
01040                      break;
01041               }
01042        }
01043        if (!stored) {
01044               struct _HotKeyEntry *entry, *tmp;
01045 
01046               entry = (struct _HotKeyEntry *)malloc(sizeof (struct _HotKeyEntry) * 1);
01047 
01048               LOG_DEBUG("Adding Hotkey (lang:%s, key:%s, modifier:%s)", language, hotkey->key, hotkey->modifiers);
01049               entry->language = strdup(language);
01050               entry->list = iiim_le_hotkey_list_new(hotkey);
01051               entry->next = NULL;
01052               if (conf->priv->hotkeys != NULL) {
01053                      for (tmp = conf->priv->hotkeys; tmp->next != NULL; tmp = tmp->next);
01054                      tmp->next = entry;
01055               } else {
01056                      conf->priv->hotkeys = entry;
01057               }
01058        }
01059 
01060        return 1;
01061 }
01062 
01063 int
01064 iiim_le_xmlconf_remove_hotkey(IIIMLEXMLConf *conf,
01065                            HotKeyStruct  *hotkey,
01066                            const char    *language)
01067 {
01068        HotKeyList *list;
01069        struct _HotKeyEntry *ent, *prev;
01070        int removed = 0;
01071 
01072        if (conf == NULL || hotkey == NULL || language == NULL)
01073               return 0;
01074 
01075        for (ent = conf->priv->hotkeys, prev = NULL; ent != NULL; prev = ent, ent = prev->next) {
01076               if (!strcmp(ent->language, language)) {
01077                      list = iiim_le_hotkey_list_find(ent->list, hotkey);
01078                      if (list != NULL) {
01079                             LOG_DEBUG("Removing Hotkey (lang:%s, key:%s, modifiers:%s)", language, hotkey->key, hotkey->modifiers);
01080                             ent->list = iiim_le_hotkey_list_remove(ent->list, hotkey);
01081                             if (ent->list == NULL) {
01082                                    if (prev != NULL) {
01083                                           prev->next = ent->next;
01084                                    } else {
01085                                           conf->priv->hotkeys = NULL;
01086                                    }
01087                             }
01088                             removed = 1;
01089                             break;
01090                      } else {
01091                             break;
01092                      }
01093               }
01094        }
01095 
01096        return removed;
01097 }
01098 
01099 static void
01100 iiim_le_xmlconf_remove_hotkeys(IIIMLEXMLConf *conf)
01101 {
01102        struct _HotKeyEntry *ent, *tmp;
01103 
01104        if (conf == NULL)
01105               return;
01106 
01107        ent = conf->priv->hotkeys;
01108        while (ent) {
01109               tmp = ent;
01110               ent = tmp->next;
01111               free(tmp->language);
01112               iiim_le_hotkey_list_free(tmp->list);
01113               free(tmp);
01114        }
01115        conf->priv->hotkeys = NULL;
01116 }
01117 
01118 int
01119 iiim_le_xmlconf_clear_hotkey(IIIMLEXMLConf *conf,
01120                           const char    *language)
01121 {
01122        struct _HotKeyEntry *ent, *prev;
01123        int removed = 0;
01124 
01125        if (conf == NULL || language == NULL)
01126               return 0;
01127 
01128        for (ent = conf->priv->hotkeys, prev = NULL; ent != NULL; prev = ent, ent = prev->next) {
01129               if (!strcmp(ent->language, language)) {
01130                      LOG_DEBUG("Clearing Hotkey (lang:%s)", language);
01131                      iiim_le_hotkey_list_free(ent->list);
01132                      if (prev != NULL) {
01133                             prev->next = ent->next;
01134                      } else {
01135                             conf->priv->hotkeys = NULL;
01136                      }
01137                      free(ent->language);
01138                      free(ent);
01139                      removed = 1;
01140                      break;
01141               }
01142        }
01143 
01144        return removed;
01145 }
01146 
01147 HotKeyList *
01148 iiim_le_xmlconf_get_hotkey_list (IIIMLEXMLConf *conf,
01149                              const char    *language)
01150 {
01151        struct _HotKeyEntry *ent;
01152 
01153        if (conf == NULL || language == NULL)
01154               return NULL;
01155 
01156        for (ent = conf->priv->hotkeys; ent != NULL; ent = ent->next) {
01157               if (!strcmp(ent->language, language)) {
01158                      return ent->list;
01159               }
01160        }
01161 
01162        return NULL;
01163 }
01164 
01165 HotKeyStruct *
01166 iiim_le_hotkey_struct_new(const char *name,
01167                        const char *modifiers)
01168 {
01169        HotKeyStruct *retval;
01170        int i;
01171 
01172        retval = (HotKeyStruct *)malloc(sizeof (HotKeyStruct) * 1);
01173        if (modifiers) {
01174               retval->modifiers = strdup(modifiers);
01175               retval->modmask = _symbol2mask(modifiers);
01176        } else {
01177               retval->modifiers = NULL;
01178               retval->modmask = 0;
01179        }
01180        retval->key = strdup(name);
01181        for (i = 0; keysymtable[i].keyname != NULL; i++) {
01182               if (!strcasecmp(name, keysymtable[i].keyname)) {
01183                      retval->keycode = keysymtable[i].keysym;
01184                      break;
01185               }
01186        }
01187 
01188        return retval;
01189 }
01190 
01191 void
01192 iiim_le_hotkey_struct_free(HotKeyStruct *hotkey)
01193 {
01194        if (hotkey == NULL)
01195               return;
01196 
01197        if (hotkey->modifiers)
01198               free(hotkey->modifiers);
01199        if (hotkey->key)
01200               free(hotkey->key);
01201        free(hotkey);
01202 }
01203 
01204 HotKeyList *
01205 iiim_le_hotkey_list_new(HotKeyStruct *hotkey)
01206 {
01207        HotKeyList *list;
01208 
01209        list = (HotKeyList *)malloc(sizeof (HotKeyList) * 1);
01210        list->hotkey = hotkey;
01211        list->next = NULL;
01212 
01213        return list;
01214 }
01215 
01216 HotKeyList *
01217 iiim_le_hotkey_list_add(HotKeyList   *list,
01218                      HotKeyStruct *hotkey)
01219 {
01220        HotKeyList *retval, *l, *prev;
01221 
01222        if (list != NULL) {
01223               for (l = list, prev = list; l != NULL; prev = l, l = prev->next) {
01224                      if (iiim_le_hotkey_list_find(list, hotkey) != NULL) {
01225                             return list;
01226                      }
01227               }
01228               prev->next = iiim_le_hotkey_list_new(hotkey);
01229               retval = list;
01230        } else {
01231               retval = iiim_le_hotkey_list_new(hotkey);
01232        }
01233 
01234        return retval;
01235 }
01236 
01237 HotKeyList *
01238 iiim_le_hotkey_list_remove(HotKeyList *list,
01239                         HotKeyStruct *hotkey)
01240 {
01241        HotKeyList *tmp, *prev = NULL;
01242 
01243        tmp = list;
01244        while (tmp) {
01245               if (!strcasecmp(tmp->hotkey->key, hotkey->key) &&
01246                   !_compare_modifiers(tmp->hotkey->modifiers, hotkey->modifiers)) {
01247                      if (prev)
01248                             prev->next = tmp->next;
01249                      else
01250                             list = tmp->next;
01251                      iiim_le_hotkey_struct_free(tmp->hotkey);
01252                      free(tmp);
01253 
01254                      break;
01255               }
01256               prev = tmp;
01257               tmp = prev->next;
01258        }
01259 
01260        return list;
01261 }
01262 
01263 HotKeyList *
01264 iiim_le_hotkey_list_find(HotKeyList   *list,
01265                       HotKeyStruct *hotkey)
01266 {
01267        HotKeyList *l;
01268 
01269        if (hotkey == NULL)
01270               return NULL;
01271 
01272        for (l = list; l != NULL; l = l->next) {
01273               if (!strcasecmp(l->hotkey->key, hotkey->key) &&
01274                   !_compare_modifiers(l->hotkey->modifiers, hotkey->modifiers)) {
01275                      return l;
01276               }
01277        }
01278 
01279        return NULL;
01280 }
01281 
01282 void
01283 iiim_le_hotkey_list_free(HotKeyList *list)
01284 {
01285        HotKeyList *last;
01286 
01287        while (list) {
01288               last = list;
01289               list = last->next;
01290               if (last->hotkey)
01291                      iiim_le_hotkey_struct_free(last->hotkey);
01292               free(last);
01293        }
01294 }