(take_action_list): Move the handling of candidate-list
[m17n/m17n-lib.git] / src / input.c
index 61baa7a..2de5547 100644 (file)
@@ -1,5 +1,5 @@
 /* input.c -- input method module.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
@@ -220,6 +220,7 @@ typedef MPlist *(*MIMExternalFunc) (MPlist *plist);
 
 typedef struct
 {
+  MSymbol name;
   void *handle;
   MPlist *func_list;           /* function name vs (MIMExternalFunc *) */
 } MIMExternalModule;
@@ -1200,13 +1201,17 @@ load_macros (MInputMethodInfo *im_info, MPlist *plist)
   return 0;
 }
 
-/* Load an external module from PLIST into IM_INFO->externals.
+/* Load an external module from PLIST, and return a pointer to
+   MIMExternalModule.
+
    PLIST has this form:
       PLIST ::= ( MODULE-NAME FUNCTION * )
-   IM_INFO->externals is a plist of MODULE-NAME vs (MIMExternalModule *).  */
+   IM_INFO->externals is a plist of MODULE-NAME vs (MIMExternalModule *).
 
-static int
-load_external_module (MInputMethodInfo *im_info, MPlist *plist)
+   On error, return NULL.  */
+
+static MIMExternalModule *
+load_external_module (MPlist *plist)
 {
   void *handle;
   MSymbol module;
@@ -1227,10 +1232,7 @@ load_external_module (MInputMethodInfo *im_info, MPlist *plist)
 
   handle = dlopen (module_file, RTLD_NOW);
   if (MFAILP (handle))
-    {
-      fprintf (stderr, "%s\n", dlerror ());
-      return -1;
-    }
+    return NULL;
   func_list = mplist ();
   MPLIST_DO (plist, MPLIST_NEXT (plist))
     {
@@ -1243,15 +1245,23 @@ load_external_module (MInputMethodInfo *im_info, MPlist *plist)
     }
 
   MSTRUCT_MALLOC (external, MERROR_IM);
+  external->name = module;
   external->handle = handle;
   external->func_list = func_list;
-  mplist_add (im_info->externals, module, external);
-  return 0;
+  return external;
 
  err_label:
-  dlclose (handle);
   M17N_OBJECT_UNREF (func_list);
-  return -1;
+  dlclose (handle);
+  return NULL;
+}
+
+static void
+unload_external_module (MIMExternalModule *external)
+{
+  dlclose (external->handle);
+  M17N_OBJECT_UNREF (external->func_list);
+  free (external);
 }
 
 static void
@@ -1380,11 +1390,7 @@ fini_im_info (MInputMethodInfo *im_info)
     {
       MPLIST_DO (plist, im_info->externals)
        {
-         MIMExternalModule *external = MPLIST_VAL (plist);
-
-         dlclose (external->handle);
-         M17N_OBJECT_UNREF (external->func_list);
-         free (external);
+         unload_external_module (MPLIST_VAL (plist));
          MPLIST_KEY (plist) = Mt;
        }
       M17N_OBJECT_UNREF (im_info->externals);
@@ -1566,7 +1572,7 @@ update_global_info (void)
 }
 
 
-/* Return an IM_INFO for the an method specified by LANGUAGE, NAME,
+/* Return an IM_INFO for the input method specified by LANGUAGE, NAME,
    and EXTRA.  KEY, if not Mnil, tells which kind of information about
    the input method is necessary, and the returned IM_INFO may contain
    only that information.  */
@@ -2290,9 +2296,13 @@ load_im_info (MPlist *plist, MInputMethodInfo *im_info)
              im_info->externals = mplist ();
            MPLIST_DO (elt, MPLIST_NEXT (elt))
              {
+               MIMExternalModule *external;
+
                if (MFAILP (MPLIST_PLIST_P (elt)))
                  continue;
-               load_external_module (im_info, MPLIST_PLIST (elt));
+               external = load_external_module (MPLIST_PLIST (elt));
+               if (external)
+                 mplist_add (im_info->externals, external->name, external);
              }
          }
        else if (key == Mstate)
@@ -2994,9 +3004,6 @@ static int
 take_action_list (MInputContext *ic, MPlist *action_list)
 {
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
-  MPlist *candidate_list = ic->candidate_list;
-  int candidate_index = ic->candidate_index;
-  int candidate_show = ic->candidate_show;
   MTextProperty *prop;
 
   MPLIST_DO (action_list, action_list)
@@ -3470,31 +3477,6 @@ take_action_list (MInputContext *ic, MPlist *action_list)
            };
        }
     }
-
-  if (ic->candidate_list)
-    {
-      M17N_OBJECT_UNREF (ic->candidate_list);
-      ic->candidate_list = NULL;
-    }
-  if (ic->cursor_pos > 0
-      && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
-                                    Mcandidate_list)))
-    {
-      ic->candidate_list = mtext_property_value (prop);
-      M17N_OBJECT_REF (ic->candidate_list);
-      ic->candidate_index
-       = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
-                               Mcandidate_index);
-      ic->candidate_from = mtext_property_start (prop);
-      ic->candidate_to = mtext_property_end (prop);
-    }
-
-  if (candidate_list != ic->candidate_list)
-    ic->candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
-  if (candidate_index != ic->candidate_index)
-    ic->candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
-  if (candidate_show != ic->candidate_show)
-    ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;    
   return 0;
 }
 
@@ -3795,7 +3777,7 @@ open_im (MInputMethod *im)
 {
   MInputMethodInfo *im_info = get_im_info (im->language, im->name, Mnil, Mnil);
 
-  if (! im_info || ! im_info->states)
+  if (! im_info || ! im_info->states || MPLIST_LENGTH (im_info->states) == 0)
     MERROR (MERROR_IM, -1);
   im->info = im_info;
 
@@ -3904,7 +3886,37 @@ filter (MInputContext *ic, MSymbol key, void *arg)
   ic_info->key_unhandled = 0;
 
   do {
-    if (handle_key (ic) < 0)
+    MPlist *candidate_list = ic->candidate_list;
+    int candidate_index = ic->candidate_index;
+    int candidate_show = ic->candidate_show;
+    MTextProperty *prop;
+    int result = handle_key (ic);
+
+    if (ic->candidate_list)
+      {
+       M17N_OBJECT_UNREF (ic->candidate_list);
+       ic->candidate_list = NULL;
+      }
+    if (ic->cursor_pos > 0
+       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
+                                      Mcandidate_list)))
+      {
+       ic->candidate_list = mtext_property_value (prop);
+       M17N_OBJECT_REF (ic->candidate_list);
+       ic->candidate_index
+         = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
+                                 Mcandidate_index);
+       ic->candidate_from = mtext_property_start (prop);
+       ic->candidate_to = mtext_property_end (prop);
+      }
+    if (candidate_list != ic->candidate_list)
+      ic->candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
+    if (candidate_index != ic->candidate_index)
+      ic->candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
+    if (candidate_show != ic->candidate_show)
+      ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;    
+
+    if (result < 0)
       {
        /* KEY was not handled.  Delete it from the current key sequence.  */
        if (ic_info->used > 0)
@@ -5923,6 +5935,153 @@ minput_save_config (void)
   return (ret < 0 ? -1 : 1);
 }
 
+/***en
+    @brief List available input methods.
+
+    The minput_list () function returns a list of currently available
+    input methods whose language is $LANGUAGE.  If $LANGUAGE is #Mnil,
+    all input methods are listed.
+
+    @return
+    The returned value is a plist of this form:
+       ((LANGUAGE-NAME INPUT-METHOD-NAME SANE) ...)
+    The third element SANE of each input method is #Mt if it can be
+    successfully used, or #Mnil if it has some problem (e.g. syntax
+    error of MIM file, unavailable external module, unavailable
+    including input method).  */
+
+#if EXAMPLE_CODE
+#include <stdio.h>
+#include <string.h>
+#include <m17n.h>
+
+int
+main (int argc, char **argv)
+{
+  MPlist *imlist, *pl;
+
+  M17N_INIT ();
+  imlist = minput_list ((argc > 1) ? msymbol (argv[1]) : Mnil);
+  for (pl = imlist; mplist_key (pl) != Mnil; pl = mplist_next (pl))
+    {
+      MPlist *p = mplist_value (pl);
+      MSymbol lang, name, sane;
+
+      lang = mplist_value (p);
+      p = mplist_next (p);
+      name = mplist_value (p);
+      p = mplist_next (p);
+      sane = mplist_value (p);
+
+      printf ("%s %s %s\n", msymbol_name (lang), msymbol_name (name),
+             sane == Mt ? "ok" : "no");
+    }
+
+  m17n_object_unref (imlist);
+  M17N_FINI ();
+  exit (0);
+}
+#endif
+
+MPlist *
+minput_list (MSymbol language)
+{
+  MPlist *plist, *pl;
+  MPlist *imlist = mplist ();
+  
+  MINPUT__INIT ();
+  plist = mdatabase_list (Minput_method, language, Mnil, Mnil);
+  if (! plist)
+    return imlist;
+  MPLIST_DO (pl, plist)
+    {
+      MDatabase *mdb = MPLIST_VAL (pl);
+      MSymbol *tag = mdatabase_tag (mdb);
+      MPlist *imdata, *p, *elm;
+      int num_maps = 0, num_states = 0;
+
+      if (tag[2] == Mnil)
+       continue;
+      imdata = mdatabase_load (mdb);
+      if (! imdata)
+       continue;
+      MPLIST_DO (p, imdata)
+       if (MPLIST_PLIST_P (p))
+         {
+           /* Check these basic functionarity:
+              All external modules (if any) are loadable.
+              All included input method (if any) are loadable.
+              At least one map is defined or included.
+              At least one state is defined or included. */
+           MPlist *elt = MPLIST_PLIST (p);
+           MSymbol key;
+
+           if (MFAILP (MPLIST_SYMBOL_P (elt)))
+             break;
+           key = MPLIST_SYMBOL (elt);
+           if (key == Mmap)
+             num_maps++;
+           else if (key == Mstate)
+             num_states++;
+           else if (key == Mmodule)
+             {
+               MPLIST_DO (elt, MPLIST_NEXT (elt))
+                 {
+                   MIMExternalModule *external;
+
+                   if (MFAILP (MPLIST_PLIST_P (elt)))
+                     break;
+                   external = load_external_module (MPLIST_PLIST (elt));
+                   if (MFAILP (external))
+                     break;
+                   unload_external_module (external);
+                 }
+               if (! MPLIST_TAIL_P (elt))
+                 break;
+             }
+           else if (key == Minclude)
+             {
+               MInputMethodInfo *im_info;
+
+               elt = MPLIST_NEXT (elt);
+               if (MFAILP (MPLIST_PLIST_P (elt)))
+                 break;
+               im_info = get_im_info_by_tags (MPLIST_PLIST (elt));
+               if (MFAILP (im_info))
+                 break;
+               elt = MPLIST_NEXT (elt);
+               if (MFAILP (MPLIST_SYMBOL_P (elt)))
+                 break;
+               key = MPLIST_SYMBOL (elt);
+               if (key == Mmap)
+                 {
+                   if (! im_info->maps)
+                     break;
+                   num_maps++;
+                 }
+               else if (key == Mstate)
+                 {
+                   if (! im_info->states)
+                     break;
+                   num_states++;
+                 }
+             }
+         }
+      elm = mplist ();
+      mplist_add (elm, Msymbol, tag[1]);
+      mplist_add (elm, Msymbol, tag[2]);
+      if (MPLIST_TAIL_P (p) && num_maps > 0 && num_states > 0)
+       mplist_add (elm, Msymbol, Mt);
+      else
+       mplist_add (elm, Msymbol, Mnil);
+      mplist_push (imlist, Mplist, elm);
+      M17N_OBJECT_UNREF (elm);
+      M17N_OBJECT_UNREF (imdata);
+    }
+  M17N_OBJECT_UNREF (plist);
+  return imlist;
+}
+
 /*=*/
 /*** @} */
 /*=*/