Back to index

im-sdk  12.3.91
letools.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 #ifdef HAVE_CONFIG_H
00003 #include "config.h"
00004 #endif
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <dlfcn.h>
00008 #include <sys/stat.h>
00009 #include <sys/types.h>
00010 #include <pwd.h>
00011 #include <unistd.h>
00012 #include <errno.h>
00013 #include <string.h>
00014 #include "lexmlconf.h"
00015 #include "SunIM.h"
00016 #include "IMArg.h"
00017 #include "keysyms.h"
00018 
00019 typedef struct _LangList {
00020     char *language;
00021     struct _LangList *next;
00022 } LangList;
00023 
00024 typedef enum _ActionType {
00025     ACT_NONE = 0,
00026     ACT_ARG,
00027     ACT_INSTALL,
00028     ACT_REMOVE,
00029     ACT_DEFAULT,
00030     ACT_LANG,
00031     ACT_HOTKEY,
00032     ACT_ADDKEY,
00033     ACT_DELKEY,
00034     ACT_APPENDMOD = 100,
00035     ACT_PREPENDMOD,
00036     ACT_REMOVEMOD,
00037     ACT_MODLIST,
00038     ACT_APPENDKEY,
00039     ACT_REMOVEKEY
00040 } ActionType;
00041 
00042 struct _Action {
00043     ActionType  type;
00044     char       *filename;
00045     LangList   *langlist;
00046     int         verbose;
00047     int         globalmode;
00048     HotKeyList *addhotkey;
00049     HotKeyList *removehotkey;
00050     int         clearhotkey;
00051 };
00052 
00053 typedef struct _Action Action;
00054 
00055 static LangList *
00056 lang_list_new(const char *lang)
00057 {
00058     LangList *l;
00059 
00060     l = (LangList *)malloc(sizeof (LangList) * 1);
00061     l->language = strdup(lang);
00062     l->next = NULL;
00063 
00064     return l;
00065 }
00066 
00067 static LangList *
00068 lang_list_add(LangList *list, const char *lang)
00069 {
00070     LangList *l, *ll;
00071 
00072     l = lang_list_new(lang);
00073     if (list != NULL) {
00074        for (ll = list; ll->next != NULL; ll = ll->next);
00075        ll->next = l;
00076        ll = list;
00077     } else {
00078        ll = l;
00079     }
00080 
00081     return ll;
00082 }
00083 
00084 static void
00085 lang_list_free(LangList *list)
00086 {
00087     LangList *last;
00088 
00089     while (list) {
00090        last = list;
00091        list = list->next;
00092        if (last->language)
00093            free(last->language);
00094        free(last);
00095     }
00096 }
00097 
00098 static void
00099 read_supported_lang(Action     *act,
00100                   const char *modname)
00101 {
00102     if (act->langlist == NULL) {
00103        /* need to get lang info from module */
00104        void *h = NULL;
00105        void (*f)(IMArgList, int);
00106        IMArgList a;
00107        IMLocale *l;
00108 
00109        if ((h = dlopen(act->filename, RTLD_LAZY)) == NULL) {
00110            fprintf(stderr, "Cannot open `%s'\n", act->filename);
00111            exit(1);
00112        }
00113        if ((f = (void (*) (IMArgList, int)) dlsym(h, "if_GetIfInfo")) == NULL) {
00114            fprintf(stderr, "`%s' is not valid module.\n", act->filename);
00115            exit(1);
00116        }
00117        a = (IMArg *)malloc(sizeof (IMArg) * 2);
00118        a->id = 4;
00119        f(a, 1);
00120        for (l = (IMLocale *)a->value; l->id != NULL; l++) {
00121            act->langlist = lang_list_add(act->langlist, l->id);
00122        }
00123        free(a);
00124        dlclose(h);
00125     }
00126 }
00127 
00128 void
00129 usage(const char *name)
00130 {
00131     fprintf(stderr,
00132            "Usage: %s [-v][-g][--default][--lang LANG][--add-hotkey KEY][--remove-hotkey KEY]<--install MODULE|--remove MODULE>\n"
00133            "Options:\n"
00134            "  -v                   display more information\n"
00135            "  -g                   work for the global configuration\n"
00136            "  --default            register MODULE as default.\n"
00137            "                must use --install together\n"
00138            "  --lang LANG          specify LANG for the action.\n"
00139            "  --add-hotkey KEY     add the hotkey for LANG\n"
00140            "                e.g. --add-hotkey '<Shift>space'\n"
00141            "  --remove-hotkey KEY  remove the hotkey for LANG\n"
00142            "  --clear-hotkey       clean up the hotkey configuration\n"
00143            "                must use --install or --lang together\n"
00144            "\n"
00145            "Actions:\n"
00146            "  --install MODULE     install MODULE to the configuration file\n"
00147            "  --remove MODULE      remove MODULE from the configuration file\n"
00148            "  --list        shows the available LEs\n"
00149            "                must use --lang together.\n"
00150            , name);
00151 }
00152 
00153 #ifndef HAVE_STRNDUP
00154 static char *
00155 strndup(const char *s, size_t n)
00156 {
00157     size_t slen;
00158     char *dst;
00159     size_t copied = 0;
00160 
00161     if (s != NULL) {
00162        slen = strlen(s);
00163        if (slen >= n)
00164            copied = n;
00165        else
00166            copied = slen;
00167     }
00168 
00169     dst = (char*)malloc (copied + 1);
00170     if (dst == NULL)
00171        return NULL;
00172 
00173     dst[copied] = '\0';
00174     return (char *) memcpy (dst, s, copied);
00175 }
00176 #endif
00177 
00178 static HotKeyStruct *
00179 parse_hotkey(char *keys)
00180 {
00181     HotKeyStruct *hstruct = NULL;
00182     size_t len = strlen(keys);
00183     long i, j, l, mask = 0;
00184     char *mod, *key = NULL, *tmp;
00185     const char *p;
00186     static struct {
00187        const char *symbol;
00188        int mask;
00189     } modifiers[] = {
00190        {"shift", 1},
00191        {"control", 2},
00192        {"meta", 4},
00193        {"alt", 8},
00194        {"altgr", 16},
00195        {NULL, 0},
00196     };
00197 
00198     for (i = 0; i < len; i++) {
00199        if (keys[i] == '<') {
00200            tmp = strchr(&keys[i+1], '>');
00201            if (tmp != NULL) {
00202               p = &keys[i+1];
00203               l = tmp - p;
00204               mod = strndup(p, l);
00205               for (j = 0; modifiers[j].symbol != NULL; j++) {
00206                   if (!strcasecmp(modifiers[j].symbol, mod)) {
00207                      mask |= modifiers[j].mask;
00208                      p = NULL;
00209                      i += (l + 1);
00210                      break;
00211                   }
00212               }
00213               if (p != NULL)
00214                   fprintf(stderr, "Unknown modifier symbol: %s\n", mod);
00215               if (mod)
00216                   free(mod);
00217            }
00218        } else {
00219            if (key != NULL) {
00220               fprintf(stderr, "Specified a key twice. ignoring previous key %s...\n", key);
00221               free(key);
00222            }
00223            tmp = strchr(&keys[i], '<');
00224            if (tmp != NULL) {
00225               p = &keys[i];
00226               key = strndup(p, tmp - p);
00227               i += (tmp - p - 1);
00228            } else {
00229               key = strdup(&keys[i]);
00230               i = len;
00231            }
00232        }
00233     }
00234     if (key != NULL) {
00235        char buffer[1024];
00236        size_t n = 1024, pos = 0;
00237        int i, found = 0;
00238 
00239        for (i = 0; keysymtable[i].keyname != NULL; i++) {
00240            if (!strcasecmp(key, keysymtable[i].keyname)) {
00241               found = 1;
00242               break;
00243            }
00244        }
00245        if (found == 0) {
00246            fprintf(stderr, "Unknown key: %s\n", key);
00247            free(key);
00248 
00249            return NULL;
00250        }
00251        buffer[0] = 0;
00252        for (i = 0; mask != 0; i++) {
00253            if ((mask & modifiers[i].mask) != 0) {
00254               size_t len = strlen(modifiers[i].symbol);
00255 
00256               n -= len;
00257               if (n > 0) {
00258                   if (pos > 0)
00259                      strcat(buffer, " ");
00260                   strcat(buffer, modifiers[i].symbol);
00261                   pos += len;
00262               } else {
00263                   fprintf(stderr, "Buffer overflow.\n");
00264                   free(key);
00265 
00266                   return NULL;
00267               }
00268               mask ^= modifiers[i].mask;
00269            }
00270        }
00271        hstruct = iiim_le_hotkey_struct_new(key, buffer);
00272        free(key);
00273     } else {
00274        fprintf(stderr, "No key specified.");
00275 
00276        return NULL;
00277     }
00278 
00279     return hstruct;
00280 }
00281 
00282 static Action *
00283 parse_arg(int argc, char **argv)
00284 {
00285     Action *act = (Action *)malloc(sizeof (Action) * 1);
00286     ActionType cur = ACT_NONE, next = ACT_NONE;
00287     int defaultflag = 0;
00288     int i;
00289     HotKeyStruct *hstruct;
00290 
00291     act->type = ACT_NONE;
00292     act->filename = NULL;
00293     act->verbose = 0;
00294     act->globalmode = 0;
00295     act->langlist = NULL;
00296     act->clearhotkey = 0;
00297     act->addhotkey = NULL;
00298     act->removehotkey = NULL;
00299     for (i = 1; i < argc; i++) {
00300        if (next == ACT_ARG && strncmp(argv[i], "-", 1) == 0) {
00301            fprintf(stderr, "missing argument\n");
00302            exit(1);
00303        }
00304        if (strcmp(argv[i], "--install") == 0) {
00305            cur = ACT_INSTALL;
00306            next = ACT_ARG;
00307        } else if (strcmp(argv[i], "--remove") == 0) {
00308            cur = ACT_REMOVE;
00309            next = ACT_ARG;
00310        } else if (strcmp(argv[i], "--lang") == 0) {
00311            cur = ACT_LANG;
00312            next = ACT_ARG;
00313        } else if (strcmp(argv[i], "--default") == 0) {
00314            cur = ACT_DEFAULT;
00315            next = ACT_NONE;
00316            defaultflag = 1;
00317            if (act->type == ACT_APPENDMOD)
00318               act->type = ACT_PREPENDMOD;
00319        } else if (strcmp(argv[i], "--clear-hotkey") == 0) {
00320            act->clearhotkey = 1;
00321            next = ACT_NONE;
00322        } else if (strcmp(argv[i], "--list") == 0) {
00323            act->type = ACT_MODLIST;
00324            next = ACT_NONE;
00325        } else if (strcmp(argv[i], "--add-hotkey") == 0) {
00326            cur = ACT_ADDKEY;
00327            next = ACT_ARG;
00328        } else if (strcmp(argv[i], "--remove-hotkey") == 0) {
00329            cur = ACT_DELKEY;
00330            next = ACT_ARG;
00331        } else if (strcmp(argv[i], "--help") == 0) {
00332            usage(argv[0]);
00333            exit(1);
00334        } else if (strcmp(argv[i], "-v") == 0) {
00335            act->verbose = 1;
00336            next = ACT_NONE;
00337        } else if (strcmp(argv[i], "-g") == 0) {
00338            act->globalmode = 1;
00339            next = ACT_NONE;
00340        } else if (strncmp(argv[i], "-", 1) == 0) {
00341            fprintf(stderr, "unknown option `%s'\n", argv[i]);
00342            exit(1);
00343        } else {
00344            switch (cur) {
00345               case ACT_INSTALL:
00346                   if (defaultflag)
00347                      act->type = ACT_PREPENDMOD;
00348                   else
00349                      act->type = ACT_APPENDMOD;
00350                   if (act->filename)
00351                      free(act->filename);
00352                   act->filename = strdup(argv[i]);
00353                   break;
00354               case ACT_REMOVE:
00355                   act->type = ACT_REMOVEMOD;
00356                   if (act->filename)
00357                      free(act->filename);
00358                   act->filename = strdup(argv[i]);
00359                   break;
00360               case ACT_LANG:
00361                   act->langlist = lang_list_add(act->langlist, argv[i]);
00362                   break;
00363               case ACT_ADDKEY:
00364                   hstruct = parse_hotkey(argv[i]);
00365                   if (hstruct != NULL)
00366                      act->addhotkey = iiim_le_hotkey_list_add(act->addhotkey, hstruct);
00367                   break;
00368               case ACT_DELKEY:
00369                   hstruct = parse_hotkey(argv[i]);
00370                   if (hstruct != NULL)
00371                      act->removehotkey = iiim_le_hotkey_list_add(act->removehotkey, hstruct);
00372                   break;
00373               default:
00374                   fprintf(stderr, "unknown parameter `%s'\n", argv[i]);
00375                   exit(1);
00376            }
00377            next = ACT_NONE;
00378        }
00379     }
00380 
00381     return act;
00382 }
00383 
00384 int
00385 main (int argc, char **argv)
00386 {
00387     char *conffile = NULL;
00388     Action *act;
00389     IIIMLEXMLConf *conf = NULL;
00390     struct stat s;
00391     int notfoundconf = 0, i, need_store = 0;
00392     LangList *ll;
00393     IIIMLEInfoList *modlist, *m;
00394     IIIMLELanguageList *langlist, *lelang;
00395     HotKeyList *hlist;
00396 
00397     if (argc < 2) {
00398        usage(argv[0]);
00399        exit(1);
00400     }
00401     act = parse_arg(argc, argv);
00402     if (act->globalmode) {
00403        conffile = strdup(XMLCONFDIR "/le.xml.conf");
00404     } else {
00405        struct passwd *pass;
00406        size_t len;
00407        uid_t uid;
00408 
00409        uid = getuid();
00410        pass = getpwuid(uid);
00411        len = strlen(pass->pw_dir);
00412        conffile = (char *)malloc(sizeof (char) * (len + 19));
00413        sprintf(conffile, "%s/.iiim/le.xml.conf", pass->pw_dir);
00414        endpwent();
00415     }
00416     conf = iiim_le_xmlconf_new(conffile);
00417     if (act->verbose) {
00418        iiim_log_debug_mode();
00419     }
00420     if (stat(conffile, &s) >= 0) {
00421        /* if conffile exists, parse it */
00422        if (act->verbose)
00423            fprintf(stderr, "Loading %s...", conffile);
00424        iiim_le_xmlconf_load_file(conf);
00425     } else {
00426        notfoundconf = 1;
00427     }
00428     switch (act->type) {
00429        case ACT_MODLIST:
00430            langlist = iiim_le_xmlconf_get_lang_list(conf);
00431            for (lelang = langlist; lelang != NULL; lelang = lelang->next) {
00432               printf("Language: %s\n", lelang->language);
00433               modlist = iiim_le_xmlconf_get_le_info_list(conf, lelang->language);
00434               for (m = modlist, i = 1; m != NULL; m = m->next, i++) {
00435                   IIIMLEInfo *info = m->data;
00436 
00437                   printf(" %d. %s\n", i, info->lename);
00438               }
00439            }
00440            break;
00441        case ACT_APPENDMOD:
00442            need_store = 1;
00443            read_supported_lang(act, act->filename);
00444            for (ll = act->langlist; ll != NULL; ll = ll->next) {
00445               if (act->clearhotkey)
00446                   iiim_le_xmlconf_clear_hotkey(conf, ll->language);
00447               iiim_le_xmlconf_append_module(conf, act->filename, ll->language);
00448               for (hlist = act->removehotkey; hlist != NULL; hlist = hlist->next) {
00449                   iiim_le_xmlconf_remove_hotkey(conf, hlist->hotkey, ll->language);
00450               }
00451               for (hlist = act->addhotkey; hlist != NULL; hlist = hlist->next) {
00452                   iiim_le_xmlconf_append_hotkey(conf, hlist->hotkey, ll->language);
00453               }
00454            }
00455            break;
00456        case ACT_PREPENDMOD:
00457            need_store = 1;
00458            read_supported_lang(act, act->filename);
00459            for (ll = act->langlist; ll != NULL; ll = ll->next) {
00460               if (act->clearhotkey)
00461                   iiim_le_xmlconf_clear_hotkey(conf, ll->language);
00462               iiim_le_xmlconf_prepend_module(conf, act->filename, ll->language);
00463               for (hlist = act->removehotkey; hlist != NULL; hlist = hlist->next) {
00464                   iiim_le_xmlconf_remove_hotkey(conf, hlist->hotkey, ll->language);
00465               }
00466               for (hlist = act->addhotkey; hlist != NULL; hlist = hlist->next) {
00467                   iiim_le_xmlconf_append_hotkey(conf, hlist->hotkey, ll->language);
00468               }
00469            }
00470            break;
00471        case ACT_REMOVEMOD:
00472            need_store = 1;
00473            read_supported_lang(act, act->filename);
00474            for (ll = act->langlist; ll != NULL; ll = ll->next) {
00475               iiim_le_xmlconf_remove_module(conf, act->filename, ll->language);
00476               if (iiim_le_xmlconf_get_le_info_list(conf, ll->language) == NULL)
00477                   iiim_le_xmlconf_clear_hotkey(conf, ll->language);
00478            }
00479            break;
00480        default:
00481            if (act->langlist != NULL &&
00482               (act->addhotkey != NULL || act->removehotkey != NULL)) {
00483               /* Add/Remove the hotkey only */
00484               need_store = 1;
00485               for (ll = act->langlist; ll != NULL; ll = ll->next) {
00486                   for (hlist = act->removehotkey; hlist != NULL; hlist = hlist->next) {
00487                      iiim_le_xmlconf_remove_hotkey(conf, hlist->hotkey, ll->language);
00488                   }
00489                   for (hlist = act->addhotkey; hlist != NULL; hlist = hlist->next) {
00490                      iiim_le_xmlconf_append_hotkey(conf, hlist->hotkey, ll->language);
00491                   }
00492               }
00493            } else if (act->langlist != NULL && act->clearhotkey) {
00494               need_store = 1;
00495               for (ll = act->langlist; ll != NULL; ll = ll->next) {
00496                   /* clean up the hotkey only */
00497                   iiim_le_xmlconf_clear_hotkey(conf, ll->language);
00498               }
00499            } else {
00500               fprintf(stderr, "unkown action: %d\n", act->type);
00501               exit(1);
00502            }
00503     }
00504     if (need_store) {
00505        if (iiim_le_xmlconf_is_empty_module(conf) &&
00506            iiim_le_xmlconf_is_empty_hotkey(conf)) {
00507            if (!notfoundconf) {
00508               /* remove empty conf file. */
00509               if (unlink(conffile) == -1) {
00510                   fprintf(stderr, "Cannot remove `%s' :%s\n", conffile, strerror(errno));
00511                   exit(1);
00512               }
00513            }
00514        } else {
00515            if (act->verbose)
00516               fprintf(stderr, "Storing %s...", conffile);
00517            iiim_le_xmlconf_save_file(conf);
00518            if (act->verbose)
00519               fprintf(stderr, "done\n");
00520        }
00521     }
00522     if (conffile)
00523        free(conffile);
00524     if (act->filename)
00525        free(act->filename);
00526     if (act->langlist)
00527        lang_list_free(act->langlist);
00528     if (act->removehotkey)
00529        iiim_le_hotkey_list_free(act->removehotkey);
00530     if (act)
00531        free(act);
00532     if (conf)
00533        iiim_le_xmlconf_free(conf);
00534 
00535     return 0;
00536 }