(integer_value): Delete the 3rd arg VALUE.
[m17n/m17n-lib.git] / src / input.c
index 2624daa..38883a8 100644 (file)
@@ -17,7 +17,7 @@
 
    You should have received a copy of the GNU Lesser General Public
    License along with the m17n library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    02111-1307, USA.  */
 
 /***en
 #include <dlfcn.h>
 #endif
 
-#include "m17n-gui.h"
+#include "m17n.h"
 #include "m17n-misc.h"
 #include "internal.h"
 #include "mtext.h"
 #include "database.h"
 #include "charset.h"
 
-static int mdebug_mask = MDEBUG_INPUT;
+static int mdebug_flag = MDEBUG_INPUT;
 
 static int fully_initialized;
 
@@ -174,7 +174,7 @@ static MSymbol Mtitle, Mmacro, Mmodule, Mstate, Minclude;
 
 /** Symbols for actions.  */
 static MSymbol Minsert, Mdelete, Mmark, Mmove, Mpushback, Mundo, Mcall, Mshift;
-static MSymbol Mselect, Mshow, Mhide, Mcommit, Munhandle;
+static MSymbol Mselect, Mshow, Mhide, Mcommit, Munhandle, Mpop;
 static MSymbol Mset, Madd, Msub, Mmul, Mdiv, Mequal, Mless, Mgreater;
 static MSymbol Mless_equal, Mgreater_equal;
 static MSymbol Mcond;
@@ -199,6 +199,8 @@ static MSymbol M_key_alias;
 
 static MSymbol Mdescription, Mcommand, Mvariable, Mglobal, Mconfig;
 
+static MSymbol M_gettext;
+
 /** Structure to hold a map.  */
 
 struct MIMMap
@@ -400,6 +402,7 @@ fully_initialize ()
   Mmove = msymbol ("move");
   Mmark = msymbol ("mark");
   Mpushback = msymbol ("pushback");
+  Mpop = msymbol ("pop");
   Mundo = msymbol ("undo");
   Mcall = msymbol ("call");
   Mshift = msymbol ("shift");
@@ -443,6 +446,7 @@ fully_initialize ()
   Mvariable = msymbol ("variable");
   Mglobal = msymbol ("global");
   Mconfig = msymbol ("config");
+  M_gettext = msymbol ("_");
 
   load_im_info_keys = mplist ();
   mplist_add (load_im_info_keys, Mstate, Mnil);
@@ -466,24 +470,27 @@ fully_initialize ()
 
 \f
 static int
-marker_code (MSymbol sym)
+marker_code (MSymbol sym, int surrounding)
 {
   char *name;
 
   if (sym == Mnil)
     return -1;
   name = MSYMBOL_NAME (sym);
-  return ((name[0] == '@'
-          && ((name[1] >= '0' && name[1] <= '9')
-              || name[1] == '<' || name[1] == '>'
-              || name[1] == '=' || name[1] == '+' || name[1] == '-'
-              || name[1] == '[' || name[1] == ']'
-              || name[1] == '@')
-          && name[2] == '\0')
-         ? name[1] : -1);
+  return (name[0] != '@' ? -1
+         : (((name[1] >= '0' && name[1] <= '9')
+             || name[1] == '<' || name[1] == '>' || name[1] == '='
+             || name[1] == '[' || name[1] == ']'
+             || name[1] == '@')
+            && name[2] == '\0') ? name[1]
+         : (name[1] != '+' && name[1] != '-') ? -1
+         : (name[2] == '\0' || surrounding) ? name[1]
+         : -1);
 }
 
 
+/* Return a plist containing an integer value of VAR.  */
+
 static MPlist *
 resolve_variable (MInputContextInfo *ic_info, MSymbol var)
 {
@@ -509,7 +516,7 @@ get_surrounding_text (MInputContext *ic, int len)
   MText *mt = NULL;
 
   mplist_push (ic->plist, Minteger, (void *) len);
-  if (minput__callback (ic, Minput_get_surrounding_text) >= 0
+  if (minput_callback (ic, Minput_get_surrounding_text) >= 0
       && MPLIST_MTEXT_P (ic->plist))
     mt = MPLIST_MTEXT (ic->plist);
   mplist_pop (ic->plist);
@@ -522,12 +529,18 @@ delete_surrounding_text (MInputContext *ic, int pos)
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
 
   mplist_push (ic->plist, Minteger, (void *) pos);
-  minput__callback (ic, Minput_delete_surrounding_text);
+  minput_callback (ic, Minput_delete_surrounding_text);
   mplist_pop (ic->plist);
   if (pos < 0)
-    M17N_OBJECT_UNREF (ic_info->preceding_text);
+    {
+      M17N_OBJECT_UNREF (ic_info->preceding_text);
+      ic_info->preceding_text = NULL;
+    }
   else if (pos > 0)
-    M17N_OBJECT_UNREF (ic_info->following_text);
+    {
+      M17N_OBJECT_UNREF (ic_info->following_text);
+      ic_info->following_text = NULL;
+    }
 }
 
 static int
@@ -537,7 +550,7 @@ get_preceding_char (MInputContext *ic, int pos)
   MText *mt;
   int len;
 
-  if (ic_info->preceding_text)
+  if (pos && ic_info->preceding_text)
     {
       len = mtext_nchars (ic_info->preceding_text);
       if (pos <= len)
@@ -554,6 +567,8 @@ get_preceding_char (MInputContext *ic, int pos)
          M17N_OBJECT_UNREF (ic_info->preceding_text);
          ic_info->preceding_text = mt;
        }
+      else
+       M17N_OBJECT_UNREF (mt);
     }
   else
     ic_info->preceding_text = mt;
@@ -572,10 +587,10 @@ get_following_char (MInputContext *ic, int pos)
   if (ic_info->following_text)
     {
       len = mtext_nchars (ic_info->following_text);
-      if (pos <= len)
-       return mtext_ref_char (ic_info->following_text, pos - 1);
+      if (pos < len)
+       return mtext_ref_char (ic_info->following_text, pos);
     }
-  mt = get_surrounding_text (ic, pos);
+  mt = get_surrounding_text (ic, pos + 1);
   if (! mt)
     return -2;
   len = mtext_nchars (mt);
@@ -586,12 +601,14 @@ get_following_char (MInputContext *ic, int pos)
          M17N_OBJECT_UNREF (ic_info->following_text);
          ic_info->following_text = mt;
        }
+      else
+       M17N_OBJECT_UNREF (mt);
     }
   else
     ic_info->following_text = mt;
-  if (pos > len)
+  if (pos >= len)
     return -1;
-  return mtext_ref_char (ic_info->following_text, pos - 1);
+  return mtext_ref_char (ic_info->following_text, pos);
 }
 
 static int
@@ -602,53 +619,72 @@ surrounding_pos (MSymbol sym)
   if (sym == Mnil)
     return 0;
   name = MSYMBOL_NAME (sym);
-  if ((name[1] == '-' || name[1] == '+')
+  if (name[0] == '@'
+      && (name[1] == '-' || name[1] == '+')
       && name[2] >= '1' && name[2] <= '9')
     return (name[1] == '-' ? - atoi (name + 2) : atoi (name + 2));
   return 0;
 }
 
 static int
-integer_value (MInputContext *ic, MPlist *arg, MPlist **value, int surrounding)
+integer_value (MInputContext *ic, MPlist *arg, int surrounding)
 {
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
-  int code;
+  int code, pos;
   MText *preedit = ic->preedit;
   int len = mtext_nchars (preedit);
 
-  if (value)
-    *value = NULL;
   if (MPLIST_INTEGER_P (arg))
     return MPLIST_INTEGER (arg);
-  if (surrounding
-      && (surrounding = surrounding_pos (MPLIST_SYMBOL (arg))) != 0)
-    return (surrounding < 0
-           ? get_preceding_char (ic, - surrounding)
-           : get_following_char (ic, surrounding));
-  code = marker_code (MPLIST_SYMBOL (arg));
+
+  code = marker_code (MPLIST_SYMBOL (arg), surrounding);
   if (code < 0)
     {
       MPlist *val = resolve_variable (ic_info, MPLIST_SYMBOL (arg));
 
-      if (value)
-       *value = val;
       return (MPLIST_INTEGER_P (val) ? MPLIST_INTEGER (val) : 0);
     }
   if (code == '@')
     return ic_info->key_head;
-  if (code >= '0' && code <= '9')
-    code -= '0';
+  if ((code == '-' || code == '+'))
+    {
+      char *name = MSYMBOL_NAME (MPLIST_SYMBOL (arg));
+
+      if (name[2])
+       {
+         pos = atoi (name + 1);
+         if (pos == 0)
+           return get_preceding_char (ic, 0);
+         if (pos < 0)
+           pos = ic->cursor_pos + pos;
+         else
+           pos = ic->cursor_pos + pos - 1;
+         if (pos < 0)
+           {
+             if (ic->produced && mtext_len (ic->produced) + pos >= 0)
+               return mtext_ref_char (ic->produced,
+                                      mtext_len (ic->produced) + pos);
+             return get_preceding_char (ic, - pos);
+           }
+         else if (pos >= len)
+           return get_following_char (ic, pos - len);
+       }
+      else
+       pos = ic->cursor_pos + (code == '+' ? 1 : -1);
+    }
+  else if (code >= '0' && code <= '9')
+    pos = code - '0';
   else if (code == '=')
-    code = ic->cursor_pos;
-  else if (code == '-' || code == '[')
-    code = ic->cursor_pos - 1;
-  else if (code == '+' || code == ']')
-    code = ic->cursor_pos + 1;
+    pos = ic->cursor_pos;
+  else if (code == '[')
+    pos = ic->cursor_pos - 1;
+  else if (code == ']')
+    pos = ic->cursor_pos + 1;
   else if (code == '<')
-    code = 0;
+    pos = 0;
   else if (code == '>')
-    code = len;
-  return (code >= 0 && code < len ? mtext_ref_char (preedit, code) : -1);
+    pos = len - 1;
+  return (pos >= 0 && pos < len ? mtext_ref_char (preedit, pos) : -1);
 }
 
 static int
@@ -682,7 +718,7 @@ resolve_expression (MInputContext *ic, MPlist *plist)
   if (MPLIST_INTEGER_P (plist))
     return MPLIST_INTEGER (plist);
   if (MPLIST_SYMBOL_P (plist))
-    return integer_value (ic, plist, NULL, 1);
+    return integer_value (ic, plist, 1);
   if (! MPLIST_PLIST_P (plist))
     return 0;
   plist = MPLIST_PLIST (plist);
@@ -780,6 +816,11 @@ parse_action_list (MPlist *plist, MPlist *macros)
 
          pl = MPLIST_NEXT (pl);
 
+         if (action_name == M_candidates)
+           {
+             /* This is an already regularised action.  */
+             continue;
+           }
          if (action_name == Minsert)
            {
              if (MPLIST_MTEXT_P (pl))
@@ -787,9 +828,16 @@ parse_action_list (MPlist *plist, MPlist *macros)
                  if (mtext_nchars (MPLIST_MTEXT (pl)) == 0)
                    MERROR (MERROR_IM, -1);
                }
+             else if (MPLIST_INTEGER_P (pl))
+               {
+                 int c = MPLIST_INTEGER (pl);
+
+                 if (c < 0 || c > MCHAR_MAX)
+                   MERROR (MERROR_IM, -1);
+               }
              else if (MPLIST_PLIST_P (pl))
                {
-                 MPLIST_DO (pl, pl)
+                 MPLIST_DO (pl, MPLIST_PLIST (pl))
                    {
                      if (MPLIST_PLIST_P (pl))
                        {
@@ -830,8 +878,7 @@ parse_action_list (MPlist *plist, MPlist *macros)
              if (! MPLIST_TAIL_P (pl))
                {
                  if (! MPLIST_SYMBOL_P (pl)
-                     && (! MPLIST_INTEGER_P (pl)
-                         || MPLIST_INTEGER (pl) == 0))
+                     && ! MPLIST_INTEGER_P (pl))
                    MERROR (MERROR_IM, -1);                 
                }
            }
@@ -882,7 +929,8 @@ parse_action_list (MPlist *plist, MPlist *macros)
                MERROR (MERROR_IM, -1);
            }
          else if (action_name == Mshow || action_name == Mhide
-                  || action_name == Mcommit || action_name == Munhandle)
+                  || action_name == Mcommit || action_name == Munhandle
+                  || action_name == Mpop)
            ;
          else if (action_name == Mcond)
            {
@@ -1035,34 +1083,48 @@ load_branch (MInputMethodInfo *im_info, MPlist *plist, MIMMap *map)
       if (branch_actions)
        M17N_OBJECT_REF (branch_actions);
     }
-  else if (im_info->maps
-          && (plist = (MPlist *) mplist_get (im_info->maps, map_name)))
+  else if (im_info->maps) 
     {
-      MPLIST_DO (plist, plist)
+      plist = (MPlist *) mplist_get (im_info->maps, map_name);
+      if (! plist && im_info->configured_vars)
        {
-         MPlist *keylist, *map_actions;
+         MPlist *p = mplist__assq (im_info->configured_vars, map_name);
 
-         if (! MPLIST_PLIST_P (plist))
-           MERROR (MERROR_IM, -1);
-         keylist = MPLIST_PLIST (plist);
-         map_actions = MPLIST_NEXT (keylist);
-         if (MPLIST_SYMBOL_P (keylist))
+         if (p && MPLIST_PLIST_P (p))
+           {
+             p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p))));
+             if (MPLIST_SYMBOL_P (p))
+               plist = mplist_get (im_info->maps, MPLIST_SYMBOL (p));
+           }
+       }
+      if (plist)
+       {
+         MPLIST_DO (plist, plist)
            {
-             MSymbol command = MPLIST_SYMBOL (keylist);
-             MPlist *pl;
+             MPlist *keylist, *map_actions;
 
-             if (MFAILP (command != Mat_reload))
-               continue;
-             pl = resolve_command (im_info->configured_cmds, command);
-             if (MFAILP (pl))
-               continue;
-             MPLIST_DO (pl, pl)
-               load_translation (map, pl, map_actions, branch_actions,
+             if (! MPLIST_PLIST_P (plist))
+               MERROR (MERROR_IM, -1);
+             keylist = MPLIST_PLIST (plist);
+             map_actions = MPLIST_NEXT (keylist);
+             if (MPLIST_SYMBOL_P (keylist))
+               {
+                 MSymbol command = MPLIST_SYMBOL (keylist);
+                 MPlist *pl;
+
+                 if (MFAILP (command != Mat_reload))
+                   continue;
+                 pl = resolve_command (im_info->configured_cmds, command);
+                 if (MFAILP (pl))
+                   continue;
+                 MPLIST_DO (pl, pl)
+                   load_translation (map, pl, map_actions, branch_actions,
+                                     im_info->macros);
+               }
+             else
+               load_translation (map, keylist, map_actions, branch_actions,
                                  im_info->macros);
            }
-         else
-           load_translation (map, keylist, map_actions, branch_actions,
-                             im_info->macros);
        }
     }
 
@@ -1413,14 +1475,12 @@ update_custom_info (void)
       if (! MPLIST_SYMBOL_P (p))
        continue;
       name = MPLIST_SYMBOL (p);
-      if (language == Mnil || name == Mnil)
-       continue;
       p = MPLIST_NEXT (p);
       if (MPLIST_TAIL_P (p))
        extra = Mnil;
       else if (MPLIST_SYMBOL_P (p))
        extra = MPLIST_SYMBOL (p);
-      else
+      if (language == Mnil || (name == Mnil && extra == Mnil))
        continue;
       im_info = new_im_info (NULL, language, name, extra, im_custom_list);
       load_im_info (im_data, im_info);
@@ -1446,6 +1506,8 @@ update_global_info (void)
     {
       MDatabase *mdb = mdatabase_find (Minput_method, Mt, Mnil, Mglobal);
 
+      if (! mdb)
+       return -1;
       global_info = new_im_info (mdb, Mt, Mnil, Mglobal, im_info_list);
     }
   if (! global_info->mdb
@@ -1515,6 +1577,8 @@ get_im_info (MSymbol language, MSymbol name, MSymbol extra, MSymbol key)
        im_info->cmds = mplist ();
       if (! im_info->vars)
        im_info->vars = mplist ();
+      if (! im_info->states)
+       im_info->states = mplist ();
     }
   if (! im_info->title
       && (key == Mnil || key == Mtitle))
@@ -1535,9 +1599,9 @@ reload_im_info (MInputMethodInfo *im_info)
   int check;
   MPlist *plist;
 
+  update_custom_info ();
+  update_global_info ();
   check = mdatabase__check (im_info->mdb);
-  if (check > 0)
-    return 0;
   if (check < 0)
     return -1;
   plist = mdatabase_load (im_info->mdb);
@@ -1546,6 +1610,19 @@ reload_im_info (MInputMethodInfo *im_info)
   fini_im_info (im_info);
   load_im_info (plist, im_info);
   M17N_OBJECT_UNREF (plist);
+  if (! im_info->cmds)
+    im_info->cmds = mplist ();
+  if (! im_info->vars)
+    im_info->vars = mplist ();
+  if (! im_info->title)
+    {
+      MSymbol name = im_info->name;
+
+      im_info->title = (name == Mnil ? mtext ()
+                       : mtext_from_data (MSYMBOL_NAME (name),
+                                          MSYMBOL_NAMELEN (name),
+                                          MTEXT_FORMAT_US_ASCII));
+    }
   return 1;
 }
 
@@ -1565,6 +1642,49 @@ get_im_info_by_tags (MPlist *plist)
   return get_im_info (tag[0], tag[1], tag[2], Mnil);
 }
 
+
+static int
+check_description (MPlist *plist)
+{
+  MText *mt;
+
+  if (MPLIST_MTEXT_P (plist))
+    return 1;
+  if (MPLIST_PLIST_P (plist))
+    {
+      MPlist *pl = MPLIST_PLIST (plist);
+
+      if (MFAILP (MPLIST_SYMBOL_P (pl) && MPLIST_SYMBOL (pl) == M_gettext))
+       return 0;
+      pl =MPLIST_NEXT (pl);
+      if (MFAILP (MPLIST_MTEXT_P (pl)))
+       return 0;
+      mt = MPLIST_MTEXT (pl);
+      M17N_OBJECT_REF (mt);
+#if ENABLE_NLS
+      {
+       char *translated = dgettext ("m17n-db", (char *) MTEXT_DATA (mt));
+
+       if (translated == (char *) MTEXT_DATA (mt))
+         translated = dgettext ("m17n-contrib", (char *) MTEXT_DATA (mt));
+       if (translated != (char *) MTEXT_DATA (mt))
+         {
+           M17N_OBJECT_UNREF (mt);
+           mt = mtext__from_data (translated, strlen (translated),
+                                  MTEXT_FORMAT_UTF_8, 1);
+         }
+      }
+#endif
+      mplist_set (plist, Mtext, mt);
+      M17N_OBJECT_UNREF (mt);
+      return 1;
+    }
+  if (MFAILP (MPLIST_SYMBOL_P (plist) && MPLIST_SYMBOL (plist) == Mnil))
+    return 0;
+  return 1;
+}
+
+
 /* Check KEYSEQ, and return 1 if it is valid as a key sequence, return
    0 if not.  */
 
@@ -1633,8 +1753,7 @@ load_commands (MInputMethodInfo *im_info, MPlist *plist)
        }
       else
        {
-         if (! MPLIST_MTEXT_P (p)
-             && (! MPLIST_SYMBOL_P (p) || MPLIST_SYMBOL (p) != Mnil))
+         if (! check_description (p))
            mplist_set (p, Msymbol, Mnil);
          p = MPLIST_NEXT (p);
          while (! MPLIST_TAIL_P (p))
@@ -1654,65 +1773,60 @@ config_command (MPlist *plist, MPlist *global_cmds, MPlist *custom_cmds,
                MPlist *config_cmds)
 {
   MPlist *global = NULL, *custom = NULL, *config = NULL;
-  MSymbol name;
-  MText *description = NULL;
+  MSymbol name = MPLIST_SYMBOL (plist);
   MSymbol status;
-  MPlist *keyseq;
+  MPlist *description, *keyseq;
+
+  if (global_cmds && (global = mplist__assq (global_cmds, name)))
+    global = MPLIST_NEXT (MPLIST_PLIST (global));  
 
-  name = MPLIST_SYMBOL (plist);
   plist = MPLIST_NEXT (plist);
-  if (MPLIST_MTEXT_P (plist))
-    description = MPLIST_MTEXT (plist);
-  else if (global_cmds && ((global = mplist__assq (global_cmds, name))))
+  if (MPLIST_MTEXT_P (plist) || MPLIST_PLIST_P (plist))
     {
-      global = MPLIST_NEXT (MPLIST_PLIST (global));
-      description = MPLIST_MTEXT_P (global) ? MPLIST_MTEXT (global) : NULL;
+      description = plist;
+      plist = MPLIST_NEXT (plist);
     }
-  if (MPLIST_TAIL_P (plist))
+  else
     {
-      if (! global
-         && global_cmds && ((global = mplist__assq (global_cmds, name))))
-       global = MPLIST_NEXT (MPLIST_PLIST (global));
-      if (global)
-       {
-         keyseq = MPLIST_NEXT (global);
-         status = Minherited;
-       }
-      else
-       {
-         keyseq = plist;
-         status = Mnil;
-       }
+      description = global;
+      if (! MPLIST_TAIL_P (plist))
+       plist = MPLIST_NEXT (plist);
+    }
+  if (MPLIST_TAIL_P (plist) && global)
+    {
+      keyseq = MPLIST_NEXT (global);
+      status = Minherited;
     }
   else
     {
-      keyseq = MPLIST_NEXT (plist);
+      keyseq = plist;
       status = Mnil;
     }
 
   if (config_cmds && (config = mplist__assq (config_cmds, name)))
     {
+      status = Mconfigured;
       config = MPLIST_NEXT (MPLIST_PLIST (config));
       if (! MPLIST_TAIL_P (config))
-       {
-         keyseq = MPLIST_NEXT (config);
-         status = Mconfigured;
-       }
+       keyseq = config;
     }
   else if (custom_cmds && (custom = mplist__assq (custom_cmds, name)))
     {
-      custom = MPLIST_NEXT (MPLIST_PLIST (custom));
-      if (! MPLIST_TAIL_P (custom))
+      MPlist *this_keyseq = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (custom)));
+
+      if (MPLIST_TAIL_P (this_keyseq))
+       mplist__pop_unref (custom);
+      else
        {
-         keyseq = MPLIST_NEXT (custom);
          status = Mcustomized;
+         keyseq = this_keyseq;
        }
     }
   
   plist = mplist ();
   mplist_add (plist, Msymbol, name);
   if (description)
-    mplist_add (plist, Mtext, description);
+    mplist_add (plist, MPLIST_KEY (description), MPLIST_VAL (description));
   else
     mplist_add (plist, Msymbol, Mnil);
   mplist_add (plist, Msymbol, status);
@@ -1743,7 +1857,10 @@ config_all_commands (MInputMethodInfo *im_info)
       MPlist *pl = config_command (MPLIST_PLIST (plist),
                                   global_cmds, custom_cmds, config_cmds);
       if (pl)
-       tail = mplist_add (tail, Mplist, pl);
+       {
+         tail = mplist_add (tail, Mplist, pl);
+         M17N_OBJECT_UNREF (pl);
+       }
     }
 }
 
@@ -1822,7 +1939,7 @@ check_variable_value (MPlist *val, MPlist *global)
        }
     }
 
-  return (MPLIST_TAIL_P (valids));
+  return (! MPLIST_TAIL_P (valids));
 }
 
 /* Load variable defitions from PLIST into IM_INFO->vars.
@@ -1865,7 +1982,7 @@ load_variables (MInputMethodInfo *im_info, MPlist *plist)
            mplist_add (p, Msymbol, Mnil);
          else
            {
-             if (MFAILP (MPLIST_MTEXT_P (p)))
+             if (! check_description (p))
                mplist_set (p, Msymbol, Mnil);
              p = MPLIST_NEXT (p);
              if (MFAILP (! MPLIST_TAIL_P (p)
@@ -1885,15 +2002,13 @@ load_variables (MInputMethodInfo *im_info, MPlist *plist)
              /* P ::= ((NAME DESC ...) ...) */
              p = MPLIST_PLIST (p); /* P ::= (NAME DESC ...) */
              global = MPLIST_NEXT (p); /* P ::= (DESC VALUE ...) */
-             global = MPLIST_NEXT (p); /* P ::= (VALUE ...) */
+             global = MPLIST_NEXT (global); /* P ::= (VALUE ...) */
            }
 
          p = MPLIST_NEXT (pl); /* P ::= (DESC VALUE VALID ...) */
          if (! MPLIST_TAIL_P (p))
            {
-             if (MFAILP (MPLIST_MTEXT_P (p)
-                         || (MPLIST_SYMBOL_P (p)
-                             && MPLIST_SYMBOL (p) == Mnil)))
+             if (! check_description (p))
                mplist_set (p, Msymbol, Mnil);
              p = MPLIST_NEXT (p); /* P ::= (VALUE VALID ...) */
              if (MFAILP (! MPLIST_TAIL_P (p)))
@@ -1930,9 +2045,8 @@ config_variable (MPlist *plist, MPlist *global_vars, MPlist *custom_vars,
 {
   MPlist *global = NULL, *custom = NULL, *config = NULL;
   MSymbol name = MPLIST_SYMBOL (plist);
-  MText *description = NULL;
   MSymbol status;
-  MPlist *value, *valids;
+  MPlist *description = NULL, *value, *valids;
 
   if (global_vars)
     {
@@ -1942,10 +2056,10 @@ config_variable (MPlist *plist, MPlist *global_vars, MPlist *custom_vars,
     }
 
   plist = MPLIST_NEXT (plist);
-  if (MPLIST_MTEXT_P (plist))
-    description = MPLIST_MTEXT (plist);
-  else if (global && MPLIST_MTEXT (global))
-    description = MPLIST_MTEXT (global);
+  if (MPLIST_MTEXT_P (plist) || MPLIST_PLIST_P (plist))
+    description = plist;
+  else if (global)
+    description = global;
   if (global)
     global = MPLIST_NEXT (global); /* (VALUE VALIDS ...) */
 
@@ -1983,21 +2097,24 @@ config_variable (MPlist *plist, MPlist *global_vars, MPlist *custom_vars,
 
   if (config_vars && (config = mplist__assq (config_vars, name)))
     {
+      status = Mconfigured;
       config = MPLIST_NEXT (MPLIST_PLIST (config));
       if (! MPLIST_TAIL_P (config))
        {
-         value = MPLIST_NEXT (config);
+         value = config;
          if (MFAILP (check_variable_value (value, global ? global : plist)))
            value = NULL;
-         status = Mconfigured;
        }
     }
   else if (custom_vars && (custom = mplist__assq (custom_vars, name)))
     {
-      custom = MPLIST_NEXT (MPLIST_PLIST (custom));
-      if (! MPLIST_TAIL_P (custom))
+      MPlist *this_value = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (custom)));
+
+      if (MPLIST_TAIL_P (this_value))
+       mplist__pop_unref (custom);
+      else
        {
-         value = MPLIST_NEXT (custom);
+         value = this_value;
          if (MFAILP (check_variable_value (value, global ? global : plist)))
            value = NULL;
          status = Mcustomized;
@@ -2007,7 +2124,7 @@ config_variable (MPlist *plist, MPlist *global_vars, MPlist *custom_vars,
   plist = mplist ();
   mplist_add (plist, Msymbol, name);
   if (description)
-    mplist_add (plist, Mtext, description);
+    mplist_add (plist, MPLIST_KEY (description), MPLIST_VAL (description));
   else
     mplist_add (plist, Msymbol, Mnil);
   mplist_add (plist, Msymbol, status);
@@ -2047,7 +2164,10 @@ config_all_variables (MInputMethodInfo *im_info)
       MPlist *pl = config_variable (MPLIST_PLIST (plist),
                                    global_vars, custom_vars, config_vars);
       if (pl)
-      tail = mplist_add (tail, Mplist, pl);
+       {
+         tail = mplist_add (tail, Mplist, pl);
+         M17N_OBJECT_UNREF (pl);
+       }
     }
 }
 
@@ -2209,11 +2329,10 @@ load_im_info (MPlist *plist, MInputMethodInfo *im_info)
            if (im_info->description)
              continue;
            elt = MPLIST_NEXT (elt);
-           if (MFAILP (MPLIST_MTEXT_P (elt)))
+           if (! check_description (elt))
              continue;
            im_info->description = MPLIST_MTEXT (elt);
            M17N_OBJECT_REF (im_info->description);
-
          }
       }
   im_info->tick = time (NULL);
@@ -2222,7 +2341,7 @@ load_im_info (MPlist *plist, MInputMethodInfo *im_info)
 \f
 
 static int take_action_list (MInputContext *ic, MPlist *action_list);
-static void preedit_commit (MInputContext *ic);
+static void preedit_commit (MInputContext *ic, int need_prefix);
 
 static void
 shift_state (MInputContext *ic, MSymbol state_name)
@@ -2250,7 +2369,15 @@ shift_state (MInputContext *ic, MSymbol state_name)
        state = (MIMState *) MPLIST_VAL (im_info->states);
     }
 
-  MDEBUG_PRINT1 ("\n  [IM] (shift %s)", MSYMBOL_NAME (state->name));
+  if (MDEBUG_FLAG ())
+    {
+      if (orig_state)
+       MDEBUG_PRINT2 ("\n  [IM] [%s] (shift %s)\n",
+                      MSYMBOL_NAME (orig_state->name),
+                      MSYMBOL_NAME (state->name));
+      else
+       MDEBUG_PRINT1 (" (shift %s)\n", MSYMBOL_NAME (state->name));
+    }
 
   /* Enter the new state.  */
   ic_info->state = state;
@@ -2259,13 +2386,18 @@ shift_state (MInputContext *ic, MSymbol state_name)
   if (state == (MIMState *) MPLIST_VAL (im_info->states)
       && orig_state)
     /* We have shifted to the initial state.  */
-    preedit_commit (ic);
+    preedit_commit (ic, 0);
   mtext_cpy (ic_info->preedit_saved, ic->preedit);
   ic_info->state_pos = ic->cursor_pos;
   if (state != orig_state)
     {
       if (state == (MIMState *) MPLIST_VAL (im_info->states))
-       ic_info->prev_state = NULL;
+       {
+         /* Shifted to the initial state.  */
+         ic_info->prev_state = NULL;
+         M17N_OBJECT_UNREF (ic_info->vars_saved);
+         ic_info->vars_saved = mplist_copy (ic_info->vars);
+       }
       else
        ic_info->prev_state = orig_state;
 
@@ -2277,7 +2409,8 @@ shift_state (MInputContext *ic, MSymbol state_name)
       if (ic_info->map == ic_info->state->map
          && ic_info->map->map_actions)
        {
-         MDEBUG_PRINT (" init-actions:");
+         MDEBUG_PRINT1 ("  [IM] [%s] init-actions:",
+                        MSYMBOL_NAME (state->name));
          take_action_list (ic, ic_info->map->map_actions);
        }
     }
@@ -2318,22 +2451,62 @@ find_candidates_group (MPlist *plist, int index,
   return NULL;
 }
 
+/* Adjust markers for the change of preedit text.
+   If FROM == TO, the change is insertion of INS chars.
+   If FROM < TO and INS == 0, the change is deletion of the range.
+   If FROM < TO and INS > 0, the change is replacement.  */
+
 static void
-preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
+adjust_markers (MInputContext *ic, int from, int to, int ins)
 {
   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
   MPlist *markers;
+
+  if (from == to)
+    {
+      MPLIST_DO (markers, ic_info->markers)
+       if (MPLIST_INTEGER (markers) > from)
+         MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + ins);
+      if (ic->cursor_pos >= from)
+       ic->cursor_pos += ins;
+    }
+  else
+    {
+      MPLIST_DO (markers, ic_info->markers)
+       {
+         if (MPLIST_INTEGER (markers) >= to)
+           MPLIST_VAL (markers)
+             = (void *) (MPLIST_INTEGER (markers) + ins - (to - from));
+         else if (MPLIST_INTEGER (markers) > from)
+           MPLIST_VAL (markers) = (void *) from;
+       }
+      if (ic->cursor_pos >= to)
+       ic->cursor_pos += ins - (to - from);
+      else if (ic->cursor_pos > from)
+       ic->cursor_pos = from;
+    }
+}
+
+
+static void
+preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
+{
   int nchars = mt ? mtext_nchars (mt) : 1;
 
   if (mt)
-    mtext_ins (ic->preedit, pos, mt);
+    {
+      mtext_ins (ic->preedit, pos, mt);
+      MDEBUG_PRINT1 ("(\"%s\")", MTEXT_DATA (mt));
+    }
   else
-    mtext_ins_char (ic->preedit, pos, c, 1);
-  MPLIST_DO (markers, ic_info->markers)
-    if (MPLIST_INTEGER (markers) > pos)
-      MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars);
-  if (ic->cursor_pos >= pos)
-    ic->cursor_pos += nchars;
+    {
+      mtext_ins_char (ic->preedit, pos, c, 1);
+      if (c < 0x7F)
+       MDEBUG_PRINT1 ("('%c')", c);
+      else
+       MDEBUG_PRINT1 ("(U+%04X)", c);
+    }
+  adjust_markers (ic, pos, pos, nchars);
   ic->preedit_changed = 1;
 }
 
@@ -2341,27 +2514,34 @@ preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
 static void
 preedit_delete (MInputContext *ic, int from, int to)
 {
-  MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
-  MPlist *markers;
+  mtext_del (ic->preedit, from, to);
+  adjust_markers (ic, from, to, 0);
+  ic->preedit_changed = 1;
+}
+
+static void
+preedit_replace (MInputContext *ic, int from, int to, MText *mt, int c)
+{
+  int ins;
 
   mtext_del (ic->preedit, from, to);
-  MPLIST_DO (markers, ic_info->markers)
-    {
-      if (MPLIST_INTEGER (markers) > to)
-       MPLIST_VAL (markers)
-         = (void *) (MPLIST_INTEGER (markers) - (to - from));
-      else if (MPLIST_INTEGER (markers) > from);
-       MPLIST_VAL (markers) = (void *) from;
-    }
-  if (ic->cursor_pos >= to)
-    ic->cursor_pos -= to - from;
-  else if (ic->cursor_pos > from)
-    ic->cursor_pos = from;
+  if (mt)
+    {
+      mtext_ins (ic->preedit, from, mt);
+      ins = mtext_nchars (mt);
+    }
+  else
+    {
+      mtext_ins_char (ic->preedit, from, c, 1);
+      ins = 1;
+    }
+  adjust_markers (ic, from, to, ins);
   ic->preedit_changed = 1;
 }
 
+
 static void
-preedit_commit (MInputContext *ic)
+preedit_commit (MInputContext *ic, int need_prefix)
 {
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
   int preedit_len = mtext_nchars (ic->preedit);
@@ -2375,27 +2555,33 @@ preedit_commit (MInputContext *ic)
       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
                             Mcandidate_index, NULL, 0);
       mtext_cat (ic->produced, ic->preedit);
-      if ((mdebug__flag & mdebug_mask)
-         && mtext_nchars (ic->preedit) > 0)
+      if (MDEBUG_FLAG ())
        {
          int i;
 
-         MDEBUG_PRINT (" (produced");
+         if (need_prefix)
+           MDEBUG_PRINT1 ("\n  [IM] [%s]",
+                          MSYMBOL_NAME (ic_info->state->name));
+         MDEBUG_PRINT (" (commit");
          for (i = 0; i < mtext_nchars (ic->preedit); i++)
            MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->preedit, i));
          MDEBUG_PRINT (")");
        }
+
       mtext_reset (ic->preedit);
       mtext_reset (ic_info->preedit_saved);
       MPLIST_DO (p, ic_info->markers)
        MPLIST_VAL (p) = 0;
       ic->cursor_pos = ic_info->state_pos = 0;
       ic->preedit_changed = 1;
+      ic_info->commit_key_head = ic_info->key_head;
     }
   if (ic->candidate_list)
     {
       M17N_OBJECT_UNREF (ic->candidate_list);
       ic->candidate_list = NULL;
+      ic->candidate_index = 0;
+      ic->candidate_from = ic->candidate_to = 0;
       ic->candidates_changed = MINPUT_CANDIDATES_LIST_CHANGED;
       if (ic->candidate_show)
        {
@@ -2403,16 +2589,12 @@ preedit_commit (MInputContext *ic)
          ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
        }
     }
-  memmove (ic_info->keys, ic_info->keys + ic_info->key_head,
-          sizeof (int) * (ic_info->used - ic_info->key_head));
-  ic_info->used -= ic_info->key_head;
-  ic_info->state_key_head = ic_info->key_head = 0;
 }
 
 static int
 new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
 {
-  int code = marker_code (sym);
+  int code = marker_code (sym, 0);
 
   if (mt && (code == '[' || code == ']'))
     {
@@ -2456,11 +2638,11 @@ update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
   int ingroup_index = idx - start;
   MText *mt;
 
-  preedit_delete (ic, from, to);
+  candidate_list = mplist_copy (candidate_list);
   if (MPLIST_MTEXT_P (group))
     {
       mt = MPLIST_MTEXT (group);
-      preedit_insert (ic, from, NULL, mtext_ref_char (mt, ingroup_index));
+      preedit_replace (ic, from, to, NULL, mtext_ref_char (mt, ingroup_index));
       to = from + 1;
     }
   else
@@ -2471,10 +2653,11 @@ update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
           i++, plist = MPLIST_NEXT (plist));
       mt = MPLIST_MTEXT (plist);
-      preedit_insert (ic, from, mt, 0);
+      preedit_replace (ic, from, to, mt, 0);
       to = from + mtext_nchars (mt);
     }
   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
+  M17N_OBJECT_UNREF (candidate_list);
   mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
   ic->cursor_pos = to;
 }
@@ -2608,14 +2791,9 @@ get_candidate_list (MInputContextInfo *ic_info, MPlist *args)
 
   plist = MPLIST_PLIST (args);
   if (charset)
-    {
-      if (! (plist = adjust_candidates (plist, charset)))
-       return NULL;
-    }
-  else
-    M17N_OBJECT_REF (plist);
+    plist = adjust_candidates (plist, charset);
 
-  if (column > 0)
+  if (plist && column > 0)
     {
       if (MPLIST_MTEXT_P (plist))
        {
@@ -2633,7 +2811,8 @@ get_candidate_list (MInputContextInfo *ic_info, MPlist *args)
                  next = MPLIST_NEXT (next);
                }
            }
-         M17N_OBJECT_UNREF (plist);
+         if (charset)
+           M17N_OBJECT_UNREF (plist);
          plist = mplist ();
          len = mtext_nchars (mt);
          if (len <= column)
@@ -2651,47 +2830,42 @@ get_candidate_list (MInputContextInfo *ic_info, MPlist *args)
            }
          M17N_OBJECT_UNREF (mt);
        }
-      else             /* MPLIST_PLIST_P (plist) */
+      else if (! MPLIST_TAIL_P (plist))
        {
-         MPlist *pl = MPLIST_PLIST (plist), *p;
-         MPlist *next = MPLIST_NEXT (plist);
-         int j;
+         MPlist *tail = plist;
+         MPlist *new = mplist ();
+         MPlist *this = mplist ();
+         int count = 0;
 
-         if (MPLIST_TAIL_P (next))
-           M17N_OBJECT_REF (pl);
-         else
+         MPLIST_DO (tail, tail)
            {
-             pl = mplist_copy (pl);
-             while (! MPLIST_TAIL_P (next))
-               {
-                 p = mplist_copy (MPLIST_PLIST (next));
-                 pl = mplist__conc (pl, p);
-                 M17N_OBJECT_UNREF (p);
-                 next = MPLIST_NEXT (next);
-               }
-           }
-         M17N_OBJECT_UNREF (plist);
-         plist = mplist ();
-         len = mplist_length (pl);
-         if (len <= column)
-           mplist_add (plist, Mplist, pl);
-         else
-           {
-             MPlist *p0 = pl;
+             MPlist *p = MPLIST_PLIST (tail);
 
-             for (i = 0; i < len; i += column)
+             MPLIST_DO (p, p)
                {
-                 p = mplist ();
-                 mplist_add (plist, Mplist, p);
-                 M17N_OBJECT_UNREF (p);
-                 for (j = 0; j < column && i + j < len; j++)
+                 MText *mt = MPLIST_MTEXT (p);
+
+                 if (count == column)
                    {
-                     p = mplist_add (p, Mtext, MPLIST_VAL (p0));
-                     p0 = MPLIST_NEXT (p0);
+                     mplist_add (new, Mplist, this);
+                     M17N_OBJECT_UNREF (this);
+                     this = mplist ();
+                     count = 0;
                    }
+                 mplist_add (this, Mtext, mt);
+                 count++;
                }
            }
-         M17N_OBJECT_UNREF (pl);
+         mplist_add (new, Mplist, this);
+         M17N_OBJECT_UNREF (this);
+         mplist_set (plist, Mnil, NULL);
+         MPLIST_DO (tail, new)
+           {
+             MPlist *elt = MPLIST_PLIST (tail);
+
+             mplist_add (plist, Mplist, elt);
+           }
+         M17N_OBJECT_UNREF (new);
        }
     }
 
@@ -2752,7 +2926,7 @@ regularize_action (MPlist *action_list, MInputContextInfo *ic_info)
 }
 
 /* Perform list of actions in ACTION_LIST for the current input
-   context IC.  If all actions are performed without error, return 0.
+   context IC.  If unhandle action was not performed, return 0.
    Otherwise, return -1.  */
 
 static int
@@ -2794,7 +2968,7 @@ take_action_list (MInputContext *ic, MPlist *action_list)
          MPlist *plist = get_candidate_list (ic_info, args);
          int len;
 
-         if (! plist)
+         if (! plist || (MPLIST_PLIST_P (plist) && MPLIST_TAIL_P (plist)))
            continue;
          if (MPLIST_MTEXT_P (plist))
            {
@@ -2802,6 +2976,8 @@ take_action_list (MInputContext *ic, MPlist *action_list)
                              mtext_ref_char (MPLIST_MTEXT (plist), 0));
              len = 1;
            }
+         else if (MPLIST_TAIL_P (MPLIST_PLIST (plist)))
+           continue;
          else
            {
              MText * mt = MPLIST_MTEXT (MPLIST_PLIST (plist));
@@ -2809,13 +2985,14 @@ take_action_list (MInputContext *ic, MPlist *action_list)
              preedit_insert (ic, ic->cursor_pos, mt, 0);
              len = mtext_nchars (mt);
            }
+         plist = mplist_copy (plist);
          mtext_put_prop (ic->preedit,
                          ic->cursor_pos - len, ic->cursor_pos,
                          Mcandidate_list, plist);
+         M17N_OBJECT_UNREF (plist);
          mtext_put_prop (ic->preedit,
                          ic->cursor_pos - len, ic->cursor_pos,
                          Mcandidate_index, (void *) 0);
-         M17N_OBJECT_UNREF (plist);
        }
       else if (name == Mselect)
        {
@@ -2823,31 +3000,41 @@ take_action_list (MInputContext *ic, MPlist *action_list)
          int code, idx, gindex;
          int pos = ic->cursor_pos;
          MPlist *group;
+         int idx_decided = 0;
 
          if (pos == 0
              || ! (prop = mtext_get_property (ic->preedit, pos - 1,
                                               Mcandidate_list)))
            continue;
+         idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
+         group = find_candidates_group (mtext_property_value (prop), idx,
+                                        &start, &end, &gindex);
          if (MPLIST_SYMBOL_P (args))
            {
-             code = marker_code (MPLIST_SYMBOL (args));
+             code = marker_code (MPLIST_SYMBOL (args), 0);
              if (code < 0)
-               continue;
+               {
+                 args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
+                 if (! MPLIST_INTEGER_P (args))
+                   continue;
+                 idx = start + MPLIST_INTEGER (args);
+                 if (idx < start || idx >= end)
+                   continue;
+                 idx_decided = 1;
+               }                 
            }
          else
            code = -1;
-         idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
-         group = find_candidates_group (mtext_property_value (prop), idx,
-                                        &start, &end, &gindex);
 
          if (code != '[' && code != ']')
            {
-             idx = (start
-                    + (code >= 0
-                       ? new_index (NULL, ic->candidate_index - start,
-                                    end - start - 1, MPLIST_SYMBOL (args),
-                                    NULL)
-                       : MPLIST_INTEGER (args)));
+             if (! idx_decided)
+               idx = (start
+                      + (code >= 0
+                         ? new_index (NULL, ic->candidate_index - start,
+                                      end - start - 1, MPLIST_SYMBOL (args),
+                                      NULL)
+                         : MPLIST_INTEGER (args)));
              if (idx < 0)
                {
                  find_candidates_group (mtext_property_value (prop), -1,
@@ -2889,6 +3076,7 @@ take_action_list (MInputContext *ic, MPlist *action_list)
              idx += ingroup_index;
            }
          update_candidate (ic, prop, idx);
+         MDEBUG_PRINT1 ("(%d)", idx);
        }
       else if (name == Mshow)
        ic->candidate_show = 1;
@@ -2903,7 +3091,17 @@ take_action_list (MInputContext *ic, MPlist *action_list)
          if (MPLIST_SYMBOL_P (args)
              && (pos = surrounding_pos (MPLIST_SYMBOL (args))) != 0)
            {
-             delete_surrounding_text (ic, pos);
+             to = ic->cursor_pos + pos;
+             if (to < 0)
+               {
+                 delete_surrounding_text (ic, to);
+                 to = 0;
+               }
+             else if (to > len)
+               {
+                 delete_surrounding_text (ic, to - len);
+                 to = len;
+               }
            }
          else
            {
@@ -2915,12 +3113,12 @@ take_action_list (MInputContext *ic, MPlist *action_list)
                to = 0;
              else if (to > len)
                to = len;
-             MDEBUG_PRINT1 ("(%d)", to - ic->cursor_pos);
-             if (to < ic->cursor_pos)
-               preedit_delete (ic, to, ic->cursor_pos);
-             else if (to > ic->cursor_pos)
-               preedit_delete (ic, ic->cursor_pos, to);
            }
+         MDEBUG_PRINT1 ("(%d)", to - ic->cursor_pos);
+         if (to < ic->cursor_pos)
+           preedit_delete (ic, to, ic->cursor_pos);
+         else if (to > ic->cursor_pos)
+           preedit_delete (ic, ic->cursor_pos, to);
        }
       else if (name == Mmove)
        {
@@ -2940,25 +3138,42 @@ take_action_list (MInputContext *ic, MPlist *action_list)
              ic->cursor_pos = pos;
              ic->preedit_changed = 1;
            }
+         MDEBUG_PRINT1 ("(%d)", ic->cursor_pos);
        }
       else if (name == Mmark)
        {
-         int code = marker_code (MPLIST_SYMBOL (args));
+         int code = marker_code (MPLIST_SYMBOL (args), 0);
 
          if (code < 0)
-           mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
-                       (void *) ic->cursor_pos);
+           {
+             mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
+                         (void *) ic->cursor_pos);
+             MDEBUG_PRINT1 ("(%d)", ic->cursor_pos);
+           }
        }
       else if (name == Mpushback)
        {
-         if (MPLIST_INTEGER_P (args))
+         if (MPLIST_INTEGER_P (args) || MPLIST_SYMBOL_P (args))
            {
-             int num = MPLIST_INTEGER (args);
+             int num;
+
+             if (MPLIST_SYMBOL_P (args))
+               {
+                 args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
+                 if (MPLIST_INTEGER_P (args))
+                   num = MPLIST_INTEGER (args);
+                 else
+                   num = 0;
+               }
+             else
+               num = MPLIST_INTEGER (args);
 
              if (num > 0)
                ic_info->key_head -= num;
+             else if (num == 0)
+               ic_info->key_head = 0;
              else
-               ic_info->key_head = num;
+               ic_info->key_head = - num;
              if (ic_info->key_head > ic_info->used)
                ic_info->key_head = ic_info->used;
            }
@@ -2997,6 +3212,11 @@ take_action_list (MInputContext *ic, MPlist *action_list)
                }
            }
        }
+      else if (name == Mpop)
+       {
+         if (ic_info->key_head < ic_info->used)
+           MLIST_DELETE1 (ic_info, keys, ic_info->key_head, 1);
+       }
       else if (name == Mcall)
        {
          MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
@@ -3015,8 +3235,8 @@ take_action_list (MInputContext *ic, MPlist *action_list)
                = (MIMExternalModule *) mplist_get (im_info->externals,
                                                    module);
              if (external)
-               func = (MIMExternalFunc) mplist_get (external->func_list,
-                                                    func_name);
+               func = ((MIMExternalFunc)
+                       mplist_get_func (external->func_list, func_name));
            }
          if (! func)
            continue;
@@ -3028,7 +3248,7 @@ take_action_list (MInputContext *ic, MPlist *action_list)
 
              if (MPLIST_KEY (args) == Msymbol
                  && MPLIST_KEY (args) != Mnil
-                 && (code = marker_code (MPLIST_SYMBOL (args))) >= 0)
+                 && (code = marker_code (MPLIST_SYMBOL (args), 0)) >= 0)
                {
                  code = new_index (ic, ic->cursor_pos, 
                                    mtext_nchars (ic->preedit),
@@ -3054,29 +3274,40 @@ take_action_list (MInputContext *ic, MPlist *action_list)
        {
          int intarg = (MPLIST_TAIL_P (args)
                        ? ic_info->used - 2
-                       : integer_value (ic, args, NULL, 0));
+                       : integer_value (ic, args, 0));
 
          mtext_reset (ic->preedit);
          mtext_reset (ic_info->preedit_saved);
+         mtext_reset (ic->produced);
+         M17N_OBJECT_UNREF (ic_info->vars);
+         ic_info->vars = mplist_copy (ic_info->vars_saved);
          ic->cursor_pos = ic_info->state_pos = 0;
-         ic_info->state_key_head = ic_info->key_head = 0;
+         ic_info->state_key_head = ic_info->key_head
+           = ic_info->commit_key_head = 0;
 
+         shift_state (ic, Mnil);
          if (intarg < 0)
-           ic_info->used += intarg;
+           {
+             if (MPLIST_TAIL_P (args))
+               {
+                 ic_info->used = 0;
+                 return -1;
+               }
+             ic_info->used += intarg;
+           }
          else
            ic_info->used = intarg;
-         shift_state (ic, Mnil);
          break;
        }
       else if (name == Mset || name == Madd || name == Msub
               || name == Mmul || name == Mdiv)
        {
          MSymbol sym = MPLIST_SYMBOL (args);
+         MPlist *value = resolve_variable (ic_info, sym);
          int val1, val2;
-         MPlist *value;
          char *op;
 
-         val1 = integer_value (ic, args, &value, 0);
+         val1 = MPLIST_INTEGER (value);
          args = MPLIST_NEXT (args);
          val2 = resolve_expression (ic, args);
          if (name == Mset)
@@ -3091,8 +3322,7 @@ take_action_list (MInputContext *ic, MPlist *action_list)
            val1 /= val2, op = "/=";
          MDEBUG_PRINT4 ("(%s %s 0x%X(%d))",
                         MSYMBOL_NAME (sym), op, val1, val1);
-         if (value)
-           mplist_set (value, Minteger, (void *) val1);
+         mplist_set (value, Minteger, (void *) val1);
        }
       else if (name == Mequal || name == Mless || name == Mgreater
               || name == Mless_equal || name == Mgreater_equal)
@@ -3153,11 +3383,11 @@ take_action_list (MInputContext *ic, MPlist *action_list)
        }
       else if (name == Mcommit)
        {
-         preedit_commit (ic);
+         preedit_commit (ic, 0);
        }
       else if (name == Munhandle)
        {
-         preedit_commit (ic);
+         preedit_commit (ic, 0);
          return -1;
        }
       else
@@ -3174,7 +3404,11 @@ take_action_list (MInputContext *ic, MPlist *action_list)
        }
     }
 
-  M17N_OBJECT_UNREF (ic->candidate_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)))
@@ -3213,8 +3447,8 @@ handle_key (MInputContext *ic)
   MSymbol alias = Mnil;
   int i;
 
-  MDEBUG_PRINT2 ("  [IM] handle `%s' in state %s", 
-                msymbol_name (key), MSYMBOL_NAME (ic_info->state->name));
+  MDEBUG_PRINT2 ("  [IM] [%s] handle `%s'", 
+                MSYMBOL_NAME (ic_info->state->name), msymbol_name (key));
 
   if (map->submaps)
     {
@@ -3281,47 +3515,43 @@ handle_key (MInputContext *ic)
     {
       /* MAP can not handle KEY.  */
 
-      /* If MAP is the root map of the initial state, it means that
-        the current input method can not handle KEY.  */
-      if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
+      /* Perform branch actions if any.  */
+      if (map->branch_actions)
        {
-         MDEBUG_PRINT (" unhandled\n");
-         return -1;
+         MDEBUG_PRINT (" branch-actions:");
+         if (take_action_list (ic, map->branch_actions) < 0)
+           {
+             MDEBUG_PRINT ("\n");
+             return -1;
+           }
        }
 
-      if (map != ic_info->state->map)
+      if (map == ic_info->map)
        {
-         /* If MAP is not the root map... */
-         /* If MAP has branch actions, perform them.  */
-         if (map->branch_actions)
+         /* The above branch actions didn't change the state.  */
+
+         /* If MAP is the root map of the initial state, and there
+            still exist an unhandled key, it means that the current
+            input method can not handle it.  */
+         if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map
+             && ic_info->key_head < ic_info->used)
            {
-             MDEBUG_PRINT (" branch-actions:");
-             if (take_action_list (ic, map->branch_actions) < 0)
-               {
-                 MDEBUG_PRINT ("\n");
-                 return -1;
-               }
+             MDEBUG_PRINT (" unhandled\n");
+             return -1;
            }
-         /* If MAP is still not the root map, shift to the current
-            state. */
-         if (ic_info->map != ic_info->state->map)
-           shift_state (ic, ic_info->state->name);
-       }
-      else
-       {
-         /* MAP is the root map, perform branch actions (if any) or
-            shift to the initial state.  */
-         if (map->branch_actions)
+
+         if (map != ic_info->state->map)
            {
-             MDEBUG_PRINT (" branch-actions:");
-             if (take_action_list (ic, map->branch_actions) < 0)
-               {
-                 MDEBUG_PRINT ("\n");
-                 return -1;
-               }
+             /* MAP is not the root map.  Shift to the root map of the
+                current state. */
+             shift_state (ic, ic_info->state->name);
+           }
+         else if (! map->branch_actions)
+           {
+             /* MAP is the root map without any default branch
+                actions.  Shift to the initial state.  */
+             shift_state (ic, Mnil);
            }
-         else
-           shift_state (ic, Mnil);
        }
     }
   MDEBUG_PRINT ("\n");
@@ -3348,7 +3578,7 @@ init_ic_info (MInputContext *ic)
        MPlist *pl = MPLIST_PLIST (plist);
        MSymbol name = MPLIST_SYMBOL (pl);
 
-       pl = MPLIST_NEXT (MPLIST_NEXT (pl));
+       pl = MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (pl)));
        if (MPLIST_KEY (pl) != Mt)
          {
            MPlist *p = mplist ();
@@ -3359,6 +3589,7 @@ init_ic_info (MInputContext *ic)
            mplist_add (p, MPLIST_KEY (pl), MPLIST_VAL (pl));
          }
       }
+  ic_info->vars_saved = mplist_copy (ic_info->vars);
 
   if (im_info->externals)
     {
@@ -3369,7 +3600,7 @@ init_ic_info (MInputContext *ic)
        {
          MIMExternalModule *external = MPLIST_VAL (plist);
          MIMExternalFunc func
-           = (MIMExternalFunc) mplist_get (external->func_list, Minit);
+           = (MIMExternalFunc) mplist_get_func (external->func_list, Minit);
 
          if (func)
            (func) (func_args);
@@ -3398,7 +3629,7 @@ fini_ic_info (MInputContext *ic)
        {
          MIMExternalModule *external = MPLIST_VAL (plist);
          MIMExternalFunc func
-           = (MIMExternalFunc) mplist_get (external->func_list, Mfini);
+           = (MIMExternalFunc) mplist_get_func (external->func_list, Mfini);
 
          if (func)
            (func) (func_args);
@@ -3410,6 +3641,7 @@ fini_ic_info (MInputContext *ic)
   M17N_OBJECT_UNREF (ic_info->preedit_saved);
   M17N_OBJECT_UNREF (ic_info->markers);
   M17N_OBJECT_UNREF (ic_info->vars);
+  M17N_OBJECT_UNREF (ic_info->vars_saved);
   M17N_OBJECT_UNREF (ic_info->preceding_text);
   M17N_OBJECT_UNREF (ic_info->following_text);
 
@@ -3431,6 +3663,7 @@ re_init_ic (MInputContext *ic, int reload)
     {
       candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
       M17N_OBJECT_UNREF (ic->candidate_list);
+      ic->candidate_list = NULL;
     }
   if (ic->candidate_show)
     {
@@ -3454,8 +3687,20 @@ re_init_ic (MInputContext *ic, int reload)
   fini_ic_info (ic);
   if (reload)
     reload_im_info (im_info);
+  if (! im_info->states)
+    {
+      struct MIMState *state;
+
+      M17N_OBJECT (state, free_state, MERROR_IM);
+      state->name = msymbol ("init");
+      state->title = mtext__from_data ("ERROR!", 6, MTEXT_FORMAT_US_ASCII, 0);
+      MSTRUCT_CALLOC (state->map, MERROR_IM);
+      im_info->states = mplist ();
+      mplist_add (im_info->states, state->name, state);
+    }
   init_ic_info (ic);
   shift_state (ic, Mnil);
+
   ic->status_changed = status_changed;
   ic->preedit_changed = preedit_changed;
   ic->cursor_pos_changed = cursor_pos_changed;
@@ -3474,7 +3719,7 @@ open_im (MInputMethod *im)
 {
   MInputMethodInfo *im_info = get_im_info (im->language, im->name, Mnil, Mnil);
 
-  if (! im_info)
+  if (! im_info || ! im_info->states)
     MERROR (MERROR_IM, -1);
   im->info = im_info;
 
@@ -3578,6 +3823,7 @@ filter (MInputContext *ic, MSymbol key, void *arg)
   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
   M17N_OBJECT_UNREF (ic_info->preceding_text);
   M17N_OBJECT_UNREF (ic_info->following_text);
+  ic_info->preceding_text = ic_info->following_text = NULL;
   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
   ic_info->key_unhandled = 0;
 
@@ -3590,6 +3836,10 @@ filter (MInputContext *ic, MSymbol key, void *arg)
            memmove (ic_info->keys, ic_info->keys + 1,
                     sizeof (int) * (ic_info->used - 1));
            ic_info->used--;
+           if (ic_info->state_key_head > 0)
+             ic_info->state_key_head--;
+           if (ic_info->commit_key_head > 0)
+             ic_info->commit_key_head--;             
          }
        /* This forces returning 1.  */
        ic_info->key_unhandled = 1;
@@ -3607,17 +3857,37 @@ filter (MInputContext *ic, MSymbol key, void *arg)
 
   /* If the current map is the root of the initial state, we should
      produce any preedit text in ic->produced.  */
-  if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map
-      && mtext_nchars (ic->preedit) > 0)
-    shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
+  if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
+    preedit_commit (ic, 1);
 
   if (mtext_nchars (ic->produced) > 0)
     {
-      MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
+      if (MDEBUG_FLAG ())
+       {
+         MDEBUG_PRINT1 ("\n  [IM] [%s] (produced",
+                        MSYMBOL_NAME (ic_info->state->name));
+         for (i = 0; i < mtext_nchars (ic->produced); i++)
+           MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->produced, i));
+         MDEBUG_PRINT (")");
+       }
 
-      if (lang != Mnil)
-       mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
-                       Mlanguage, ic->im->language);
+      mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
+                     Mlanguage, ic->im->language);
+    }
+  if (ic_info->commit_key_head > 0)
+    {
+      memmove (ic_info->keys, ic_info->keys + ic_info->commit_key_head,
+              sizeof (int) * (ic_info->used - ic_info->commit_key_head));
+      ic_info->used -= ic_info->commit_key_head;
+      ic_info->key_head -= ic_info->commit_key_head;
+      ic_info->state_key_head -= ic_info->commit_key_head;
+      ic_info->commit_key_head = 0;
+    }
+  if (ic_info->key_unhandled)
+    {
+      ic_info->used = 0;
+      ic_info->key_head = ic_info->state_key_head
+       = ic_info->commit_key_head = 0;
     }
 
   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
@@ -3743,8 +4013,8 @@ minput__init ()
   minput_default_driver.filter = filter;
   minput_default_driver.lookup = lookup;
   minput_default_driver.callback_list = mplist ();
-  mplist_put (minput_default_driver.callback_list, Minput_reset,
-             (void *) reset_ic);
+  mplist_put_func (minput_default_driver.callback_list, Minput_reset,
+                  M17N_FUNC (reset_ic));
   minput_driver = &minput_default_driver;
 
   fully_initialized = 0;
@@ -3769,21 +4039,6 @@ minput__fini ()
 
 }
 
-int
-minput__callback (MInputContext *ic, MSymbol command)
-{
-  MInputCallbackFunc func;
-
-  if (! ic->im->driver.callback_list)
-    return -1;
-  func = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
-                                         command);
-  if (! func)
-    return -1;
-  (func) (ic, command);
-  return 0;
-}
-
 MSymbol
 minput__char_to_key (int c)
 {
@@ -3820,6 +4075,8 @@ minput__char_to_key (int c)
     it specifies the number of characters following the current cursor
     position.  If the value is negative, the absolute value specifies
     the number of characters preceding the current cursor position.
+    If the value is zero, it means that the caller just wants to know
+    if the surrounding text is currently supported or not.
 
     If the surrounding text is currently supported, the callback
     function must set the key of this element to #Mtext and the value
@@ -3853,7 +4110,8 @@ minput__char_to_key (int c)
     ¤Æ#Minteger ¤ò¤È¤ê¡¢¤½¤ÎÃͤϥµ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤Î¤¦¤Á¤É¤ÎÉôʬ
     ¤ò¼è¤Ã¤ÆÍè¤ë¤«¤ò»ØÄꤹ¤ë¡£Ãͤ¬Àµ¤Ç¤¢¤ì¤Ð¡¢¸½ºß¤Î¥«¡¼¥½¥ë°ÌÃ֤˳¤¯
     ÃͤθĿôʬ¤Îʸ»ú¤ò¼è¤ë¡£Éé¤Ç¤¢¤ì¤Ð¡¢¥«¡¼¥½¥ë°ÌÃÖ¤ËÀè¹Ô¤¹¤ëÃͤÎÀäÂÐ
-    ÃÍʬ¤Îʸ»ú¤ò¼è¤ë¡£
+    ÃÍʬ¤Îʸ»ú¤ò¼è¤ë¡£¸½ºß¥µ¥é¥¦¥ó¥É¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ë¤«¤É¤¦
+    ¤«¤òÃΤꤿ¤¤¤À¤±¤Ç¤¢¤ì¤Ð¡¢¤³¤ÎÃͤϥ¼¥í¤Ç¤âÎɤ¤¡£
 
     ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ï
     ¤³¤ÎÍ×ÁǤΥ­¡¼¤ò #Mtext ¤Ë¡¢Ãͤò¼è¤ê¹þ¤ó¤ÀM-text ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê
@@ -3862,8 +4120,7 @@ minput__char_to_key (int c)
     ¥·¥ç¥ó¦¤ÇɬÍפǸúΨŪ¤À¤È»×¤¨¤ÐŤ¯¤Æ¤âÎɤ¤¡£
 
     ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø
-    ¿ô¤Ï #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤòÊѲ½¤µ¤»¤ë¤³¤È¤Ê¤¯ÊÖ¤µ¤Ê¤¯¤Æ
-    ¤Ï¤Ê¤é¤Ê¤¤¡£
+    ¿ô¤Ï #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤòÊѹ¹¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
 
     Minput_delete_surrounding_text: ¤³¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿¥³¡¼¥ë
     ¥Ð¥Ã¥¯´Ø¿ô¤¬¸Æ¤Ð¤ì¤¿ºÝ¤Ë¤Ï¡¢#MInputContext::plist ¤ÎÂè°ìÍ×ÁǤϡ¢¥­¡¼
@@ -3998,6 +4255,16 @@ MSymbol Minput_driver;
 /*=*/
 
 /***en
+    @name Functions
+*/
+/***ja
+    @name ´Ø¿ô
+*/
+/*** @{ */
+
+/*=*/
+
+/***en
     @brief Open an input method.
 
     The minput_open_im () function opens an input method whose
@@ -4155,9 +4422,9 @@ minput_create_ic (MInputMethod *im, void *arg)
 
   if (im->driver.callback_list)
     {
-      minput__callback (ic, Minput_preedit_start);
-      minput__callback (ic, Minput_status_start);
-      minput__callback (ic, Minput_status_draw);
+      minput_callback (ic, Minput_preedit_start);
+      minput_callback (ic, Minput_status_start);
+      minput_callback (ic, Minput_status_draw);
     }
 
   MDEBUG_PRINT (" ok\n");
@@ -4191,9 +4458,9 @@ minput_destroy_ic (MInputContext *ic)
                 msymbol_name (ic->im->name), msymbol_name (ic->im->language));
   if (ic->im->driver.callback_list)
     {
-      minput__callback (ic, Minput_preedit_done);
-      minput__callback (ic, Minput_status_done);
-      minput__callback (ic, Minput_candidates_done);
+      minput_callback (ic, Minput_preedit_done);
+      minput_callback (ic, Minput_status_done);
+      minput_callback (ic, Minput_candidates_done);
     }
   (*ic->im->driver.destroy_ic) (ic);
   M17N_OBJECT_UNREF (ic->preedit);
@@ -4259,16 +4526,20 @@ minput_filter (MInputContext *ic, MSymbol key, void *arg)
   if (! ic
       || ! ic->active)
     return 0;
+  if (ic->im->driver.callback_list
+      && mtext_nchars (ic->preedit) > 0)
+    minput_callback (ic, Minput_preedit_draw);
+
   ret = (*ic->im->driver.filter) (ic, key, arg);
 
   if (ic->im->driver.callback_list)
     {
       if (ic->preedit_changed)
-       minput__callback (ic, Minput_preedit_draw);
+       minput_callback (ic, Minput_preedit_draw);
       if (ic->status_changed)
-       minput__callback (ic, Minput_status_draw);
+       minput_callback (ic, Minput_status_draw);
       if (ic->candidates_changed)
-       minput__callback (ic, Minput_candidates_draw);
+       minput_callback (ic, Minput_candidates_draw);
     }
 
   return ret;
@@ -4371,7 +4642,7 @@ minput_set_spot (MInputContext *ic, int x, int y,
   ic->spot.mt = mt;
   ic->spot.pos = pos;
   if (ic->im->driver.callback_list)
-    minput__callback (ic, Minput_set_spot);
+    minput_callback (ic, Minput_set_spot);
 }
 /*=*/
 
@@ -4391,7 +4662,7 @@ void
 minput_toggle (MInputContext *ic)
 {
   if (ic->im->driver.callback_list)
-    minput__callback (ic, Minput_toggle);
+    minput_callback (ic, Minput_toggle);
   ic->active = ! ic->active;
 }
 
@@ -4421,7 +4692,7 @@ void
 minput_reset_ic (MInputContext *ic)
 {
   if (ic->im->driver.callback_list)
-    minput__callback (ic, Minput_reset);
+    minput_callback (ic, Minput_reset);
 }
 
 /*=*/
@@ -4451,7 +4722,7 @@ minput_reset_ic (MInputContext *ic)
 
     plist ¤ÎÂè°ìÍ×ÁǤϡ¢#Mtext ¤ò¥­¡¼¤Ë»ý¤Á¡¢ÃͤÏÆþÎϥ᥽¥Ã¥É¤ò¼±Ê̤¹¤ë
     ¥¿¥¤¥È¥ë¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£ÂèÆóÍ×ÁǤ¬¤¢¤ì¤Ð¡¢¥­¡¼¤Ï #Mtext ¤Ç¤¢
-    ¤ê¡¢Ãͤϼ±ÊÌÍÑ¥¢¥¤¥³¥ó²èÁü¤ÎÀäÂÐ¥Õ¥¡¥¤¥ë¥Í¡¼¥à¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£
+    ¤ê¡¢Ãͤϼ±ÊÌÍÑ¥¢¥¤¥³¥ó²èÁü¥Õ¥¡¥¤¥ë¤ÎÀäÂХѥ¹¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£
 
     @return
     »ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¡¢¥¿¥¤¥È¥ë¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ì¤Ð
@@ -4520,7 +4791,8 @@ minput_get_title_icon (MSymbol language, MSymbol name)
     ´Ø¿ô minput_get_description () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄê
     ¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤òÀâÌÀ¤¹¤ë M-text ¤òÊÖ¤¹¡£
 
-    @return »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤¬ÀâÌÀ¤¹¤ë¥Æ¥­¥¹¥È¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢
+    @return
+    »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤¬ÀâÌÀ¤¹¤ë¥Æ¥­¥¹¥È¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢
     #MText ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤½¤ì¤ò m17n_object_unref
     () ¤òÍѤ¤¤Æ²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ÆþÎϥ᥽¥Ã¥É¤ËÀâÌÀ¥Æ¥­¥¹¥È¤¬Ìµ¤±
     ¤ì¤Ð@c NULL ¤òÊÖ¤¹¡£ */
@@ -4529,10 +4801,16 @@ MText *
 minput_get_description (MSymbol language, MSymbol name)
 {
   MInputMethodInfo *im_info;
+  MSymbol extra;
 
   MINPUT__INIT ();
 
-  im_info = get_im_info (language, name, Mnil, Mdescription);
+  if (name != Mnil)
+    extra = Mnil;
+  else
+    extra = language, language = Mt;
+
+  im_info = get_im_info (language, name, extra, Mdescription);
   if (! im_info || ! im_info->description)
     return NULL;
   M17N_OBJECT_REF (im_info->description);
@@ -4562,7 +4840,7 @@ minput_get_description (MSymbol language, MSymbol name)
 
     If $COMMAND is #Mnil, information about all commands is returned.
 
-    The return value is a @e well-formed plist (#m17nPlist) of this
+    The return value is a @e well-formed plist (@ref m17nPlist) of this
     format:
 @verbatim
   ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
@@ -4574,7 +4852,7 @@ minput_get_description (MSymbol language, MSymbol name)
 
     @c STATUS is a symbol representing how the key assignment is decided.
     The value is #Mnil (the default key assignment), #Mcustomized (the
-    key assignment is customized by per-user configuration file), or
+    key assignment is customized by per-user customization file), or
     #Mconfigured (the key assignment is set by the call of
     minput_config_command ()).  For a local command only, it may also
     be #Minherited (the key assignment is inherited from the
@@ -4616,7 +4894,7 @@ minput_get_description (MSymbol language, MSymbol name)
 
     $COMMAND ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£
 
-    Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (#m17nPlist) ¤Ç¤¢¤ë¡£
+    Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (@ref m17nPlist) ¤Ç¤¢¤ë¡£
 
 @verbatim
   ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
@@ -4626,12 +4904,13 @@ minput_get_description (MSymbol language, MSymbol name)
     @c DESCRIPTION ¤Ï¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë
     ¤Ï #Mnil ¤Ç¤¢¤ë¡£
 
-    @c STATUS ¤Ï¥­¡¼³ä¤êÅö¤Æ¤¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë¤Ç¤¢
-    ¤ê¡¢¤½¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤Î³ä¤êÅö¤Æ¡Ë, #Mcustomized ¡Ê¥æ¡¼¥¶
-    Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿³ä¤êÅö¤Æ¡Ë, #Mconfigured
-    ¡Êminput_config_command ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ë³ä¤êÅö¤Æ¡Ë¤Î
-    ¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Î¾ì¹ç¤Ë¤Ï¡¢#Minherited ¡ÊÂбþ¤¹¤ë
-    ¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤«¤é¤Î·Ñ¾µ¤Ë¤è¤ë³ä¤êÅö¤Æ¡Ë¤Ç¤â¤è¤¤¡£
+    @c STATUS ¤Ï¥­¡¼³ä¤êÅö¤Æ¤¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë
+    ¤Ç¤¢¤ê¡¢¤½¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤Î³ä¤êÅö¤Æ¡Ë, #Mcustomized ¡Ê¥æ¡¼
+    ¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿³ä¤êÅö¤Æ¡Ë,
+    #Mconfigured ¡Êminput_config_command ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ë
+    ³ä¤êÅö¤Æ¡Ë¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Î¾ì¹ç¤Ë¤Ï¡¢
+    #Minherited ¡ÊÂбþ¤¹¤ë¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤«¤é¤Î·Ñ¾µ¤Ë¤è¤ë³ä¤êÅö¤Æ¡Ë
+    ¤Ç¤â¤è¤¤¡£
 
     @c KEYSEQ ¤Ï£±¤Ä°Ê¾å¤Î¥·¥ó¥Ü¥ë¤«¤é¤Ê¤ë plist ¤Ç¤¢¤ê¡¢³Æ¥·¥ó¥Ü¥ë¤Ï¥³¥Þ
     ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òɽ¤¹¡£KEYSEQ ¤¬Ìµ¤¤¾ì¹ç¤Ï¡¢
@@ -4654,15 +4933,15 @@ minput_get_description (MSymbol language, MSymbol name)
 MText *
 get_im_command_description (MSymbol language, MSymbol name, MSymbol command)
 {
-  /* Return a description of the command COMMAND of the input method */
-  /* specified by LANGUAGE and NAME.  */
+  /* Return a description of the command COMMAND of the input method
+     specified by LANGUAGE and NAME.  */
   MPlist *cmd = minput_get_command (langauge, name, command);
   MPlist *plist;
 
   if (! cmds)
     return NULL;
-  plist = mplist_value (cmds); /* (NAME DESCRIPTION KEY-SEQ ...) */
-  plist = mplist_next (plist); /* (DESCRIPTION KEY-SEQ ...) */
+  plist = mplist_value (cmds); /* (NAME DESCRIPTION STATUS KEY-SEQ ...) */
+  plist = mplist_next (plist); /* (DESCRIPTION STATUS KEY-SEQ ...) */
   return  (mplist_key (plist) == Mtext
           ? (MText *) mplist_value (plist)
           : NULL);
@@ -4698,12 +4977,16 @@ minput_get_command (MSymbol language, MSymbol name, MSymbol command)
     If $KEYSEQLIST is a non-empty plist, it must be a list of key
     sequences, and each key sequence must be a plist of symbols.
 
-    If $KEYSEQLIST is an empty plist, the command becomes unusable.
+    If $KEYSEQLIST is an empty plist, any configuration and
+    customization of the command are cancelled, and default key
+    sequences become effective.
+
+    If $KEYSEQLIST is NULL, the configuration of the command is
+    canceled, and the original key sequences (what saved in per-user
+    customization file, or the default one) become effective.
 
-    If $KEYSEQLIST is NULL, the configuration of the command for the
-    input method is canceled, and the default key sequences become
-    effective.  In such case, if $COMMAND is #Mnil, configurations for
-    all commands of the input method are canceled.
+    In the latter two cases, $COMMAND can be #Mnil to make all the
+    commands of the input method the target of the operation.
 
     If $NAME is #Mnil, this function configures the key assignment of a
     global command, not that of a specific input method.
@@ -4711,11 +4994,10 @@ minput_get_command (MSymbol language, MSymbol name, MSymbol command)
     The configuration takes effect for input methods opened or
     re-opened later in the current session.  In order to make the
     configuration take effect for the future session, it must be saved
-    in a per-user configuration file by the function
+    in a per-user customization file by the function
     minput_save_config ().
 
     @return
-
     If the operation was successful, this function returns 0,
     otherwise returns -1.  The operation fails in these cases:
     <ul>
@@ -4737,20 +5019,23 @@ minput_get_command (MSymbol language, MSymbol name, MSymbol command)
     $KEYSEQLIST ¤¬¶õ¥ê¥¹¥È¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È¤Ç¤¢¤ê¡¢
     ³Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥·¥ó¥Ü¥ë¤Î plist ¤Ç¤¢¤ë¡£
 
-    $KEYSEQLIST ¤¬¶õ¤Î plist ¤Ê¤é¤Ð¡¢¥³¥Þ¥ó¥É¤Ï»ÈÍѤǤ­¤Ê¤¯¤Ê¤ë¡£
+    $KEYSEQLIST ¤¬¶õ¤Î plist ¤Ê¤é¤Ð¡¢¤½¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤ä¥«¥¹¥¿¥Þ¥¤¥º¤Ï
+    ¤¹¤Ù¤Æ¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¥Ç¥Õ¥©¥ë¥È¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Í­¸ú¤Ë¤Ê¤ë¡£
 
-    $KEYSEQLIST ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤Ï
-    ¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¥Ç¥Õ¥©¥ë¥È¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Í­¸ú¤Ë¤Ê¤ë¡£¤³¤Î¾ì¹ç¡¢
-    $COMMAND ¤¬ #Mnil ¤Ê¤é¤Ð»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤Î¥³¥Þ¥ó¥É¤ÎÀßÄ꤬
-    ¥­¥ã¥ó¥»¥ë¤µ¤ì¤ë¡£
+    $KEYSEQLIST ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢¤½¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢
+    ¸µ¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¡Ê¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤µ¤ì¤Æ¤¤
+    ¤ë¤â¤Î¡¢¤¢¤ë¤¤¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¤â¤Î¡Ë¤¬Í­¸ú¤Ë¤Ê¤ë¡£
+
+    ¸å¤Î¤Õ¤¿¤Ä¤Î¾ì¹ç¤Ë¤Ï¡¢$COMMAND ¤Ï #Mnil ¤ò¤È¤ë¤³¤È¤¬¤Ç¤­¡¢»ØÄê¤ÎÆþ
+    Îϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤Î¥³¥Þ¥ó¥ÉÀßÄê¤Î¥­¥ã¥ó¥»¥ë¤ò°ÕÌ£¤¹¤ë¡£
 
     $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð
     ¥ë¤Ê¥³¥Þ¥ó¥É¤Î¥­¡¼³ä¤êÅö¤Æ¤òÀßÄꤹ¤ë¡£
 
     ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï
     ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹
-    ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤
-    ¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+    ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤
+    ¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
 
     @return
 
@@ -4773,22 +5058,21 @@ minput_get_command (MSymbol language, MSymbol name, MSymbol command)
   MPlist *cmd, *plist, *key_seq_list, *key_seq;
 
   /* At first get the current key-sequence assignment.  */
-  cmd = mplist_get_command (Mt, unicode, start_command);
+  cmd = minput_get_command (Mt, unicode, start_command);
   if (! cmd)
     {
-      /* The input method does not have the command "start".  Here */
-      /* should come some error handling code.  */
+      /* The input method does not have the command "start".  Here
+        should come some error handling code.  */
     }
-  /* Now CMD == ((start DESCRIPTION KEY-SEQUENCE ...) ...).  Extract */
-  /* the part (KEY-SEQUENCE ...).  */
-  plist = mplist_next (mplist_next (mplist_value (cmd)));
+  /* Now CMD == ((start DESCRIPTION STATUS KEY-SEQUENCE ...) ...).
+     Extract the part (KEY-SEQUENCE ...).  */
+  plist = mplist_next (mplist_next (mplist_next (mplist_value (cmd))));
   /* Copy it because we should not modify it directly.  */
   key_seq_list = mplist_copy (plist);
-  m17n_object_unref (cmds);
   
   key_seq = mplist ();
   mplist_add (key_seq, Msymbol, msymbol ("C-x"));
-  mplist_add (key_seq, Msymbo, msymbol ("u"));
+  mplist_add (key_seq, Msymbol, msymbol ("u"));
   mplist_add (key_seq_list, Mplist, key_seq);
   m17n_object_unref (key_seq);
 
@@ -4806,23 +5090,19 @@ minput_config_command (MSymbol language, MSymbol name, MSymbol command,
 
   MINPUT__INIT ();
 
-  if (keyseqlist)
-    {
-      if (command == Mnil)
-       MERROR (MERROR_IM, -1);
-      MPLIST_DO (plist, keyseqlist)
-       if (! MPLIST_PLIST_P (plist)
-           || ! check_command_keyseq (plist))
-         MERROR (MERROR_IM, -1);
-    }
-
   im_info = get_im_info (language, name, Mnil, Mcommand);
   if (! im_info)
     MERROR (MERROR_IM, -1);
-  if (command != Mnil
-      && (! im_info->cmds
-         || ! mplist__assq (im_info->cmds, command)))
+  if (command == Mnil ? (keyseqlist && ! MPLIST_TAIL_P (keyseqlist))
+      : (! im_info->cmds
+        || ! mplist__assq (im_info->configured_cmds, command)))
     MERROR (MERROR_IM, -1);
+  if (keyseqlist && ! MPLIST_TAIL_P (keyseqlist))
+    {
+      MPLIST_DO (plist, keyseqlist)
+       if (! check_command_keyseq (plist))
+         MERROR (MERROR_IM, -1);
+    }
 
   config = get_config_info (im_info);
   if (! config)
@@ -4834,13 +5114,29 @@ minput_config_command (MSymbol language, MSymbol name, MSymbol command,
       config->vars = mplist ();
     }
 
+  if (! keyseqlist && MPLIST_TAIL_P (config->cmds))
+    /* Nothing to do.  */
+    return 0;
+
   if (command == Mnil)
     {
-      MInputMethodInfo *custom = get_custom_info (im_info);
-
-      mplist_set (config->cmds, Mnil, NULL);
-      if (custom && custom->cmds)
+      if (! keyseqlist)
        {
+         /* Cancal the configuration. */
+         if (MPLIST_TAIL_P (config->cmds))
+           return 0;
+         mplist_set (config->cmds, Mnil, NULL);
+       }
+      else
+       {
+         /* Cancal the customization. */
+         MInputMethodInfo *custom = get_custom_info (im_info);
+
+         if (MPLIST_TAIL_P (config->cmds)
+             && (! custom || ! custom->cmds || MPLIST_TAIL_P (custom->cmds)))
+           /* Nothing to do.  */
+           return 0;
+         mplist_set (config->cmds, Mnil, NULL);
          MPLIST_DO (plist, custom->cmds)
            {
              command = MPLIST_SYMBOL (MPLIST_PLIST (plist));
@@ -4854,26 +5150,58 @@ minput_config_command (MSymbol language, MSymbol name, MSymbol command,
   else
     {
       plist = mplist__assq (config->cmds, command);
-      if (plist)
+      if (! keyseqlist)
        {
-         plist = MPLIST_PLIST (plist); /* (NAME [nil KEY-SEQUENCE ...])  */
-         plist = MPLIST_NEXT (plist);  /* ([nil ...]) */
-         if (! MPLIST_TAIL_P (plist))
-           mplist_set (plist, Mnil, NULL); /* () */
+         /* Cancel the configuration.  */
+         if (! plist)
+           return 0;
+         mplist__pop_unref (plist);
        }
-      else
+      else if (MPLIST_TAIL_P (keyseqlist))
        {
-         plist = mplist ();
-         mplist_add (config->cmds, Mplist, plist);
-         M17N_OBJECT_UNREF (plist);
-         plist = mplist_add (plist, Msymbol, command);
-         plist = MPLIST_NEXT (plist);
+         /* Cancel the customization.  */
+         MInputMethodInfo *custom = get_custom_info (im_info);
+         int no_custom = (! custom || ! custom->cmds
+                          || ! mplist__assq (custom->cmds, command));
+         if (! plist)
+           {
+             if (no_custom)
+               return 0;
+             plist = mplist ();
+             mplist_add (config->cmds, Mplist, plist);
+             M17N_OBJECT_UNREF (plist);
+             plist = mplist_add (plist, Msymbol, command);
+           }
+         else
+           {
+             if (no_custom)
+               mplist__pop_unref (plist);
+             else
+               {
+                 plist = MPLIST_PLIST (plist); /* (NAME nil KEYSEQ ...) */
+                 plist = MPLIST_NEXT (plist);
+                 mplist_set (plist, Mnil, NULL);
+               }
+           }
        }
-      if (keyseqlist)
+      else
        {
          MPlist *pl;
 
-         plist = mplist_add (plist, Msymbol, Mnil);
+         if (plist)
+           {
+             plist = MPLIST_NEXT (MPLIST_PLIST (plist));
+             if (! MPLIST_TAIL_P (plist))
+               mplist_set (plist, Mnil, NULL);
+           }
+         else
+           {
+             plist = mplist ();
+             mplist_add (config->cmds, Mplist, plist);
+             M17N_OBJECT_UNREF (plist);
+             plist = mplist_add (plist, Msymbol, command);
+             plist = MPLIST_NEXT (plist);
+           }
          MPLIST_DO (keyseqlist, keyseqlist)
            {
              pl = mplist_copy (MPLIST_VAL (keyseqlist));
@@ -4893,7 +5221,7 @@ minput_config_command (MSymbol language, MSymbol name, MSymbol command,
     @brief Get information about input method variable(s).
 
     The minput_get_variable () function returns information about
-    the variable $VARIABLE of the input method specified by $LANGUAGE and $NAME.
+    variable $VARIABLE of the input method specified by $LANGUAGE and $NAME.
     An input method variable controls behavior of an input method.
 
     There are two kinds of variables, global and local.  A global
@@ -4910,7 +5238,7 @@ minput_config_command (MSymbol language, MSymbol name, MSymbol command,
     If $VARIABLE is #Mnil, information about all variables is
     returned.
 
-    The return value is a @e well-formed plist (#m17nPlist) of this
+    The return value is a @e well-formed plist (@ref m17nPlist) of this
     format:
 @verbatim
   ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...)
@@ -4922,7 +5250,7 @@ minput_config_command (MSymbol language, MSymbol name, MSymbol command,
 
     @c STATUS is a symbol representing how the value is decided.  The
     value is #Mnil (the default value), #Mcustomized (the value is
-    customized by per-user configuration file), or #Mconfigured (the
+    customized by per-user customization file), or #Mconfigured (the
     value is set by the call of minput_config_variable ()).  For a
     local variable only, it may also be #Minherited (the value is
     inherited from the corresponding global variable).
@@ -4970,7 +5298,7 @@ minput_config_command (MSymbol language, MSymbol name, MSymbol command,
 
     $VARIABLE ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£
 
-    Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (#m17nPlist) ¤Ç¤¢¤ë¡£
+    Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (@ref m17nPlist) ¤Ç¤¢¤ë¡£
 @verbatim
   ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...)
 @endverbatim
@@ -4981,8 +5309,8 @@ minput_config_command (MSymbol language, MSymbol name, MSymbol command,
     #Mnil ¤Ç¤¢¤ë¡£
 
     @c STATUS ¤ÏÃͤ¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢
-    @c STATUS ¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¡Ë, #Mcustomized ¡Ê¥æ¡¼¥¶Ëè¤ÎÀß
-    Äê¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿ÃÍ¡Ë, #Mconfigured
+    @c STATUS ¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¡Ë, #Mcustomized ¡Ê¥æ¡¼¥¶Ëè¤Î
+    ¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿ÃÍ¡Ë, #Mconfigured
     ¡Êminput_config_variable ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ëÃ͡ˤΤ¤¤º¤ì
     ¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ëÊÑ¿ô¤Î¾ì¹ç¤Ë¤Ï¡¢#Minherited ¡ÊÂбþ¤¹¤ë¥°¥í¡¼¥Ð¥ë
     ÊÑ¿ô¤«¤é·Ñ¾µ¤·¤¿Ã͡ˤǤâ¤è¤¤¡£
@@ -5035,22 +5363,28 @@ minput_get_variable (MSymbol language, MSymbol name, MSymbol variable)
     variable $VARIABLE of the input method specified by $LANGUAGE and
     $NAME.
 
-    If $VALUE is not NULL, it must be a plist of one element whose key
-    is #Minteger, #Msymbol, or #Mtext, and the value is of the
-    corresponding type.
+    If $VALUE is a non-empty plist, it must be a plist of one element
+    whose key is #Minteger, #Msymbol, or #Mtext, and the value is of
+    the corresponding type.  That value is assigned to the variable.
+
+    If $VALUE is an empty plist, any configuration and customization
+    of the variable are canceled, and the default value is assigned to
+    the variable.
 
-    If $VALUE is NULL, a configuration for the variable for the input
-    method is canceled, and the variable is initialized to the default
-    value.  In that case, if $VARIABLE is #Mnil, configurations for
-    all variables of the input method are canceled.
+    If $VALUE is NULL, the configuration of the variable is canceled,
+    and the original value (what saved in per-user customization file,
+    or the default value) is assigned to the variable.
 
-    If $NAME is #Mnil, this function configure the value of global
+    In the latter two cases, $VARIABLE can be #Mnil to make all the
+    variables of the input method the target of the operation.
+
+    If $NAME is #Mnil, this function configures the value of global
     variable, not that of a specific input method.
 
     The configuration takes effect for input methods opened or
     re-opened later in the current session.  To make the configuration
     take effect for the future session, it must be saved in a per-user
-    configuration file by the function minput_save_config ().
+    customization file by the function minput_save_config ().
 
     @return
 
@@ -5071,20 +5405,26 @@ minput_get_variable (MSymbol language, MSymbol name, MSymbol variable)
     ´Ø¿ô minput_config_variable () ¤ÏÃÍ $VALUE ¤ò¡¢$LANGUAGE ¤È $NAME
     ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤ë¡£
 
-    $VALUE ¤¬ NULL¤Ç¤Ê¤±¤ì¤Ð¡¢£±Í×ÁǤΠplist ¤Ç¤¢¤ê¡¢¤½¤Î¥­¡¼¤Ï
+    $VALUE ¤¬ ¶õ¥ê¥¹¥È¤Ç¤Ê¤±¤ì¤Ð¡¢£±Í×ÁǤΠplist ¤Ç¤¢¤ê¡¢¤½¤Î¥­¡¼¤Ï
     #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì¤«¡¢ÃͤÏÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£
+    ¤³¤ÎÃͤ¬ÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤é¤ì¤ë¡£
+
+    $VALUE ¤¬ ¶õ¥ê¥¹¥È¤Ç¤¢¤ì¤Ð¡¢ÊÑ¿ô¤ÎÀßÄê¤È¥«¥¹¥¿¥Þ¥¤¥º¤¬¥­¥ã¥ó¥»¥ë¤µ
+    ¤ì¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤ¬ÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤é¤ì¤ë¡£
 
-    $VALUE ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë
-    ¤µ¤ì¡¢ÊÑ¿ô¤Ï¥Ç¥Õ¥©¥ë¥ÈÃͤ˽é´ü²½¤µ¤ì¤ë¡£¤³¤Î¾ì¹ç¡¢$VARIABLE ¤¬
-    #Mnil ¤Ê¤é¤Ð»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤ÎÊÑ¿ô¤ÎÀßÄ꤬¥­¥ã¥ó¥»¥ë¤µ¤ì¤ë¡£
+    $VALUE ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢ÊÑ¿ô¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¸µ¤ÎÃ͡ʥ桼¥¶
+    Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ëÃæ¤ÎÃÍ¡¢¤Þ¤¿¤Ï¥Ç¥Õ¥©¥ë¥È¤ÎÃ͡ˤ¬³ä¤êÅö¤Æ¤é¤ì¤ë¡£
+
+    ¸å¤Î¤Õ¤¿¤Ä¤Î¾ì¹ç¤Ë¤Ï¡¢$VARIABLE ¤Ï #Mnil ¤ò¤È¤ë¤³¤È¤¬¤Ç¤­¡¢»ØÄꤵ¤ì
+    ¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤ÎÊÑ¿ôÀßÄê¤Î¥­¥ã¥ó¥»¥ë¤ò°ÕÌ£¤¹¤ë¡£
 
     $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð
     ¥ë¤ÊÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë¡£
 
     ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï
     ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹
-    ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤
-    ¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+    ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤
+    ¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
 
     @return
 
@@ -5110,16 +5450,12 @@ minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
   im_info = get_im_info (language, name, Mnil, Mvariable);
   if (! im_info)
     MERROR (MERROR_IM, -1);
-  if (variable == Mnil)
-    {
-      if (value)
-       MERROR (MERROR_IM, -1);
-    }
-  else if (! im_info->vars
-          || ! (plist = mplist__assq (im_info->configured_vars, variable)))
+  if (variable == Mnil ? (value && ! MPLIST_TAIL_P (value))
+      : (! im_info->vars
+        || ! (plist = mplist__assq (im_info->configured_vars, variable))))
     MERROR (MERROR_IM, -1);
 
-  if (variable != Mnil && value)
+  if (value && ! MPLIST_TAIL_P (value))
     {
       plist = MPLIST_PLIST (plist);
       plist = MPLIST_NEXT (plist); /* (DESC STATUS VALUE VALIDS ...) */
@@ -5140,13 +5476,29 @@ minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
       config->vars = mplist ();
     }
 
+  if (! value && MPLIST_TAIL_P (config->vars))
+    /* Nothing to do.  */
+    return 0;
+
   if (variable == Mnil)
     {
-      MInputMethodInfo *custom = get_custom_info (im_info);
-
-      mplist_set (config->vars, Mnil, NULL);
-      if (custom && custom->cmds)
+      if (! value)
+       {
+         /* Cancel the configuration.  */
+         if (MPLIST_TAIL_P (config->vars))
+           return 0;
+         mplist_set (config->vars, Mnil, NULL);
+       }
+      else
        {
+         /* Cancel the customization.  */
+         MInputMethodInfo *custom = get_custom_info (im_info);
+
+         if (MPLIST_TAIL_P (config->vars)
+             && (! custom || ! custom->vars || MPLIST_TAIL_P (custom->vars)))
+           /* Nothing to do.  */
+           return 0;
+         mplist_set (config->vars, Mnil, NULL);
          MPLIST_DO (plist, custom->vars)
            {
              variable = MPLIST_SYMBOL (MPLIST_PLIST (plist));
@@ -5160,24 +5512,56 @@ minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
   else
     {
       plist = mplist__assq (config->vars, variable);
-      if (plist)
+      if (! value)
        {
-         plist = MPLIST_PLIST (plist); /* (NAME nil VALUE) */
-         plist = MPLIST_NEXT (plist);  /* ([nil VALUE]) */
-         if (! MPLIST_TAIL_P (plist))
-           mplist_set (plist, Mnil ,NULL); /* () */
+         /* Cancel the configuration.  */
+         if (! plist)
+           return 0;
+         mplist__pop_unref (plist);
        }
-      else
+      else if (MPLIST_TAIL_P (value))
        {
-         plist = mplist ();
-         mplist_add (config->vars, Mplist, plist);
-         M17N_OBJECT_UNREF (plist);
-         plist = mplist_add (plist, Msymbol, variable);
-         plist = MPLIST_NEXT (plist);
+         /* Cancel the customization.  */
+         MInputMethodInfo *custom = get_custom_info (im_info);
+         int no_custom = (! custom || ! custom->vars
+                          || ! mplist__assq (custom->vars, variable));
+         if (! plist)
+           {
+             if (no_custom)
+               return 0;
+             plist = mplist ();
+             mplist_add (config->vars, Mplist, plist);
+             M17N_OBJECT_UNREF (plist);
+             plist = mplist_add (plist, Msymbol, variable);
+           }
+         else
+           {
+             if (no_custom)
+               mplist__pop_unref (plist);
+             else
+               {
+                 plist = MPLIST_PLIST (plist); /* (NAME nil VALUE) */
+                 plist = MPLIST_NEXT (plist);  /* ([nil VALUE]) */
+                 mplist_set (plist, Mnil ,NULL);
+               }
+           }
        }
-      if (value)
+      else
        {
-         plist = mplist_add (plist, Msymbol, Mnil);
+         if (plist)
+           {
+             plist = MPLIST_NEXT (MPLIST_PLIST (plist));
+             if (! MPLIST_TAIL_P (plist))
+               mplist_set (plist, Mnil, NULL);
+           }
+         else
+           {
+             plist = mplist ();
+             mplist_add (config->vars, Mplist, plist);
+             M17N_OBJECT_UNREF (plist);
+             plist = mplist_add (plist, Msymbol, variable);
+             plist = MPLIST_NEXT (plist);
+           }
          mplist_add (plist, MPLIST_KEY (value), MPLIST_VAL (value));
        }
     }
@@ -5189,10 +5573,10 @@ minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
 /*=*/
 
 /***en
-    @brief Get the name of per-user configuration file.
+    @brief Get the name of per-user customization file.
     
     The minput_config_file () function returns the absolute path name
-    of per-user configuration file into which minput_save_config ()
+    of per-user customization file into which minput_save_config ()
     save configurations.  It is usually @c "config.mic" under the
     directory @c ".m17n.d" of user's home directory.  It is not assured
     that the file of the returned name exists nor is
@@ -5209,10 +5593,10 @@ minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
     minput_save_config ()
 */
 /***ja
-    @brief ¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤Î̾Á°¤òÆÀ¤ë.
+    @brief ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Î̾Á°¤òÆÀ¤ë.
     
     ´Ø¿ô minput_config_file () ¤Ï¡¢´Ø¿ô minput_save_config () ¤¬ÀßÄê¤ò
-    Êݸ¤¹¤ë¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤Ø¤ÎÀäÂХѥ¹Ì¾¤òÊÖ¤¹¡£Ä̾ï¤Ï¡¢¥æ¡¼¥¶
+    Êݸ¤¹¤ë¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ø¤ÎÀäÂХѥ¹Ì¾¤òÊÖ¤¹¡£Ä̾ï¤Ï¡¢¥æ¡¼¥¶
     ¤Î¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê¤Î²¼¤Î¥Ç¥£¥ì¥¯¥È¥ê @c ".m17n.d" ¤Ë¤¢¤ë@c
     "config.mic" ¤È¤Ê¤ë¡£ÊÖ¤µ¤ì¤¿Ì¾Á°¤Î¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤¹¤ë¤«¡¢Æɤ߽ñ¤­¤Ç
     ¤­¤ë¤«¤ÏÊݾڤµ¤ì¤Ê¤¤¡£´Ø¿ôminput_save_config () ¤¬¼ºÇÔ¤·¤Æ -1 ¤òÊÖ
@@ -5240,16 +5624,16 @@ minput_config_file ()
 /*=*/
 
 /***en
-    @brief Save configurations in per-user configuration file.
+    @brief Save configurations in per-user customization file.
 
     The minput_save_config () function saves the configurations done
-    so far in the current session into the per-user configuration
+    so far in the current session into the per-user customization
     file.
 
     @return
 
     If the operation was successful, 1 is returned.  If the per-user
-    configuration file is currently locked, 0 is returned.  In that
+    customization file is currently locked, 0 is returned.  In that
     case, the caller may wait for a while and try again.  If the
     configuration file is not writable, -1 is returned.  In that case,
     the caller may check the name of the file by calling
@@ -5259,18 +5643,18 @@ minput_config_file ()
     @seealso
     minput_config_file ()  */
 /***ja
-    @brief ÀßÄê¤ò¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë.
+    @brief ÀßÄê¤ò¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë.
 
     ´Ø¿ô minput_save_config () ¤Ï¸½¹Ô¤Î¥»¥Ã¥·¥ç¥ó¤Ç¤³¤ì¤Þ¤Ç¤Ë¹Ô¤Ã¤¿ÀßÄê
-    ¤ò¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë¡£
+    ¤ò¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë¡£
 
     @return
 
-    À®¸ù¤¹¤ì¤Ð 1 ¤òÊÖ¤¹¡£¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤¬¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤ì¤Ð 0
-    ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢¸Æ½Ð¦¤Ï¤·¤Ð¤é¤¯ÂԤäƺƻî¹Ô¤Ç¤­¤ë¡£ÀßÄê¥Õ¥¡¥¤¥ë
-    ¤¬½ñ¤­¹þ¤ßÉԲĤξì¹ç¡¢-1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢minput_config_file () ¤ò
-    ¸Æ¤ó¤Ç¥Õ¥¡¥¤¥ë̾¤ò¥Á¥§¥Ã¥¯¤·¡¢¤Ç¤­¤ì¤Ð½ñ¤­¹þ¤ß²Äǽ¤Ë¤·¡¢ºÆ»î¹Ô¤Ç¤­
-    ¤ë¡£
+    À®¸ù¤¹¤ì¤Ð 1 ¤òÊÖ¤¹¡£¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤¬¥í¥Ã¥¯¤µ¤ì¤Æ¤¤
+    ¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢¸Æ½Ð¦¤Ï¤·¤Ð¤é¤¯ÂԤäƺƻî¹Ô¤Ç¤­¤ë¡£ÀßÄê¥Õ¥¡
+    ¥¤¥ë¤¬½ñ¤­¹þ¤ßÉԲĤξì¹ç¡¢-1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢minput_config_file
+    () ¤ò¸Æ¤ó¤Ç¥Õ¥¡¥¤¥ë̾¤ò¥Á¥§¥Ã¥¯¤·¡¢¤Ç¤­¤ì¤Ð½ñ¤­¹þ¤ß²Äǽ¤Ë¤·¡¢ºÆ»î¹Ô
+    ¤Ç¤­¤ë¡£
 
     @seealso
     minput_config_file ()  */
@@ -5290,8 +5674,8 @@ minput_save_config (void)
   update_custom_info ();
   if (! im_custom_list)
     im_custom_list = mplist ();
-  data = tail = mplist ();
 
+  /* At first, reflect configuration in customization.  */
   MPLIST_DO (plist, im_config_list)
     {
       MPlist *pl = MPLIST_PLIST (plist);
@@ -5318,26 +5702,21 @@ minput_save_config (void)
            else
              custom->cmds = mplist (), p = NULL;
            elt = MPLIST_NEXT (elt);
-           if (MPLIST_TAIL_P (elt))
+           if (p)
              {
-               if (p)
-                 mplist__pop_unref (p);
+               p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p)));
+               mplist_set (p, Mnil, NULL);
              }
            else
              {
-               elt = MPLIST_NEXT (elt);
-               if (p)
-                 {
-                   p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p)));
-                   mplist_set (p, Mnil, NULL);
-                   mplist__conc (p, elt);
-                 }
-               else
-                 {
-                   p = MPLIST_PLIST (pl);
-                   mplist_add (custom->cmds, Mplist, p);
-                 }
+               p = mplist ();
+               mplist_add (custom->cmds, Mplist, p);
+               M17N_OBJECT_UNREF (p);
+               mplist_add (p, Msymbol, command);
+               p = mplist_add (p, Msymbol, Mnil);
+               p = MPLIST_NEXT (p);
              }
+           mplist__conc (p, elt);
          }
       if (config->vars)
        MPLIST_DO (pl, config->vars)
@@ -5349,30 +5728,28 @@ minput_save_config (void)
            else
              custom->vars = mplist (), p = NULL;
            elt = MPLIST_NEXT (elt);
-           if (MPLIST_TAIL_P (elt))
+           if (p)
              {
-               if (p)
-                 mplist__pop_unref (p);
+               p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p)));
+               mplist_set (p, Mnil, NULL);
              }
            else
              {
-               elt = MPLIST_NEXT (elt);
-               if (p)
-                 {
-                   p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p)));
-                   mplist_set (p, Mnil, NULL);
-                   mplist__conc (p, elt);
-                 }
-               else
-                 {
-                   p = MPLIST_PLIST (pl);
-                   mplist_add (custom->vars, Mplist, p);
-                 }
+               p = mplist ();
+               mplist_add (custom->vars, Mplist, p);
+               M17N_OBJECT_UNREF (p);
+               mplist_add (p, Msymbol, variable);
+               p = mplist_add (p, Msymbol, Mnil);
+               p = MPLIST_NEXT (p);
              }
+           mplist__conc (p, elt);
          }
     }
-  M17N_OBJECT_UNREF (im_config_list);
+  free_im_list (im_config_list);
+  im_config_list = NULL;
 
+  /* Next, reflect customization to the actual plist to be written.  */
+  data = tail = mplist ();
   MPLIST_DO (plist, im_custom_list)
     {
       MPlist *pl = MPLIST_PLIST (plist);
@@ -5386,6 +5763,9 @@ minput_save_config (void)
       extra = MPLIST_SYMBOL (pl);
       pl = MPLIST_NEXT (pl);
       custom = MPLIST_VAL (pl);
+      if ((! custom->cmds || MPLIST_TAIL_P (custom->cmds))
+         && (! custom->vars || MPLIST_TAIL_P (custom->vars)))
+       continue;
       im_info = lookup_im_info (im_info_list, language, name, extra);
       if (im_info)
        {
@@ -5395,34 +5775,54 @@ minput_save_config (void)
            config_all_variables (im_info);
        }
       
-      elt = mplist ();
-      tail = mplist_add (tail, Mplist, elt);
-      M17N_OBJECT_UNREF (elt);
-      pl = mplist ();
-      elt = mplist_add (elt, Mplist, pl);
-      M17N_OBJECT_UNREF (pl);
-      pl = mplist_add (pl, Msymbol, Minput_method);
-      pl = mplist_add (pl, Msymbol, language);
-      pl = mplist_add (pl, Msymbol, name);
-      if (extra != Mnil)
-       pl = mplist_add (pl, Msymbol, extra);
+      elt = NULL;
       if (custom->cmds && ! MPLIST_TAIL_P (custom->cmds))
        {
-         pl = mplist ();
-         elt = mplist_add (elt, Mplist, pl);
-         M17N_OBJECT_UNREF (pl);
-         pl = mplist_add (pl, Msymbol, Mcommand);
          MPLIST_DO (p, custom->cmds)
-           pl = mplist_add (pl, Mplist, MPLIST_PLIST (p));
+           if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
+             break;
+         if (! MPLIST_TAIL_P (p))
+           {
+             elt = mplist ();
+             pl = mplist ();
+             mplist_add (elt, Mplist, pl);
+             M17N_OBJECT_UNREF (pl);
+             pl = mplist_add (pl, Msymbol, Mcommand);
+             MPLIST_DO (p, custom->cmds)
+               if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
+                 pl = mplist_add (pl, Mplist, MPLIST_PLIST (p));
+           }
        }
       if (custom->vars && ! MPLIST_TAIL_P (custom->vars))
        {
+         MPLIST_DO (p, custom->vars)
+           if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
+             break;
+         if (! MPLIST_TAIL_P (p))
+           {
+             if (! elt)
+               elt = mplist ();
+             pl = mplist ();
+             mplist_add (elt, Mplist, pl);
+             M17N_OBJECT_UNREF (pl);
+             pl = mplist_add (pl, Msymbol, Mvariable);
+             MPLIST_DO (p, custom->vars)
+               if (! MPLIST_TAIL_P (MPLIST_NEXT (MPLIST_PLIST (p))))
+                 pl = mplist_add (pl, Mplist, MPLIST_PLIST (p));
+           }
+       }
+      if (elt)
+       {
          pl = mplist ();
-         elt = mplist_add (elt, Mplist, pl);
+         mplist_push (elt, Mplist, pl);
          M17N_OBJECT_UNREF (pl);
-         pl = mplist_add (pl, Msymbol, Mvariable);
-         MPLIST_DO (p, custom->vars)
-           pl = mplist_add (pl, Mplist, MPLIST_PLIST (p));
+         pl = mplist_add (pl, Msymbol, Minput_method);
+         pl = mplist_add (pl, Msymbol, language);
+         pl = mplist_add (pl, Msymbol, name);
+         if (extra != Mnil)
+           pl = mplist_add (pl, Msymbol, extra);
+         tail = mplist_add (tail, Mplist, elt);
+         M17N_OBJECT_UNREF (elt);
        }
     }
 
@@ -5434,7 +5834,8 @@ minput_save_config (void)
 }
 
 /*=*/
-
+/*** @} */
+/*=*/
 /***en
     @name Obsolete functions
 */
@@ -5452,7 +5853,7 @@ minput_save_config (void)
     The minput_get_variables () function returns a plist (#MPlist) of
     variables used to control the behavior of the input method
     specified by $LANGUAGE and $NAME.  The plist is @e well-formed
-    (#m17nPlist) of the following format:
+    (@ref m17nPlist) of the following format:
 
 @verbatim
     (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
@@ -5501,7 +5902,7 @@ minput_save_config (void)
 
     ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
     ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È
-    (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(#m17nPlist) °Ê
+    (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(@ref m17nPlist) °Ê
     ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£
 
 @verbatim
@@ -5790,7 +6191,8 @@ minput_get_commands (MSymbol language, MSymbol name)
     ¤³¤Î³ä¤êÅö¤Æ¤Ï¡¢³ä¤êÅö¤Æ°Ê¹ß¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­
     ¸ú¤Ë¤Ê¤ë¡£
 
-    @return ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
+    @return 
+    ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
     #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
 
 int
@@ -5820,6 +6222,35 @@ minput_assign_command_keys (MSymbol language, MSymbol name,
   return ret;
 }
 
+/*=*/
+
+/***en
+    @brief Call a callback function
+
+    The minput_callback () functions calls a callback function
+    $COMMAND assigned for the input context $IC.  The caller must set
+    specific elements in $IC->plist if the callback function requires.
+
+    @return
+    If there exists a specified callback function, 0 is returned.
+    Otherwise -1 is returned.  By side effects, $IC->plist may be
+    modified.  */
+
+int
+minput_callback (MInputContext *ic, MSymbol command)
+{
+  MInputCallbackFunc func;
+
+  if (! ic->im->driver.callback_list)
+    return -1;
+  func = ((MInputCallbackFunc)
+         mplist_get_func (ic->im->driver.callback_list, command));
+  if (! func)
+    return -1;
+  (func) (ic, command);
+  return 0;
+}
+
 /*** @} */ 
 /*** @} */
 /*=*/