*** empty log message ***
[m17n/m17n-lib.git] / src / input.c
index b13eb4d..3cc1086 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
@@ -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,12 +199,14 @@ static MSymbol M_key_alias;
 
 static MSymbol Mdescription, Mcommand, Mvariable, Mglobal, Mconfig;
 
+static MSymbol M_gettext;
+
 /** Structure to hold a map.  */
 
 struct MIMMap
 {
   /** List of actions to take when we reach the map.  In a root map,
-      the actions are executed only when there's no more key.  */
+      the actions are executed only when there is no more key.  */
   MPlist *map_actions;
 
   /** List of deeper maps.  If NULL, this is a terminal map.  */
@@ -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,21 +470,22 @@ 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);
 }
 
 
@@ -509,7 +514,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 +527,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 +548,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 +565,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;
@@ -586,6 +599,8 @@ 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;
@@ -602,7 +617,8 @@ 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;
@@ -612,7 +628,7 @@ static int
 integer_value (MInputContext *ic, MPlist *arg, MPlist **value, int surrounding)
 {
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
-  int code;
+  int code, pos;
   MText *preedit = ic->preedit;
   int len = mtext_nchars (preedit);
 
@@ -620,12 +636,8 @@ integer_value (MInputContext *ic, MPlist *arg, MPlist **value, int surrounding)
     *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));
@@ -636,19 +648,42 @@ integer_value (MInputContext *ic, MPlist *arg, MPlist **value, int surrounding)
     }
   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);
+         pos = ic->cursor_pos + pos;
+         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);
+           }
+         if (pos >= len)
+           return get_following_char (ic, pos - len + 1);
+       }
+      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
@@ -789,7 +824,7 @@ parse_action_list (MPlist *plist, MPlist *macros)
                }
              else if (MPLIST_PLIST_P (pl))
                {
-                 MPLIST_DO (pl, pl)
+                 MPLIST_DO (pl, MPLIST_PLIST (pl))
                    {
                      if (MPLIST_PLIST_P (pl))
                        {
@@ -830,8 +865,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 +916,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)
            {
@@ -907,7 +942,8 @@ resolve_command (MPlist *cmds, MSymbol command)
 
   if (! cmds || ! (plist = mplist__assq (cmds, command)))
     return NULL;
-  plist = MPLIST_PLIST (plist);
+  plist = MPLIST_PLIST (plist);        /* (NAME DESC STATUS [KEYSEQ ...]) */
+  plist = MPLIST_NEXT (plist);
   plist = MPLIST_NEXT (plist);
   plist = MPLIST_NEXT (plist);
   return plist;
@@ -1412,14 +1448,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);
@@ -1534,9 +1568,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);
@@ -1545,6 +1579,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;
 }
 
@@ -1564,6 +1611,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.  */
 
@@ -1610,8 +1700,6 @@ check_command_keyseq (MPlist *keyseq)
 static void
 load_commands (MInputMethodInfo *im_info, MPlist *plist)
 {
-  MPlist *global_cmds = ((im_info->mdb && im_info != global_info)
-                        ? global_info->cmds : NULL);
   MPlist *tail;
 
   im_info->cmds = tail = mplist ();
@@ -1619,45 +1707,109 @@ load_commands (MInputMethodInfo *im_info, MPlist *plist)
   MPLIST_DO (plist, MPLIST_NEXT (plist))
     {
       /* PLIST ::= ((NAME DESC KEYSEQ ...) ...) */
-      MPlist *pl, *p, *global = NULL;
-      MSymbol name;
+      MPlist *pl, *p;
 
       if (MFAILP (MPLIST_PLIST_P (plist)))
        continue;
       pl = MPLIST_PLIST (plist); /* PL ::= (NAME DESC KEYSEQ ...) */
       if (MFAILP (MPLIST_SYMBOL_P (pl)))
        continue;
-      name = MPLIST_SYMBOL (pl);
       p = MPLIST_NEXT (pl);    /* P ::= (DESC KEYSEQ ...) */
-      if (global_cmds
-         && (global = mplist__assq (global_cmds, name)))
+      if (MPLIST_TAIL_P (p))   /* PL ::= (NAME) */
        {
-         /* GLOBAL ::= ((NAME DESC ...) ...) */
-         global = MPLIST_PLIST (global); /* (NAME DESC ...) */
-         global = MPLIST_NEXT (global);  /* (DESC ...) */
+         if (MFAILP (im_info != global_info))
+           mplist_add (p, Msymbol, Mnil); /* PL ::= (NAME nil) */
        }
-      if (! MPLIST_MTEXT_P (p))
+      else
        {
-         if (global && MPLIST_MTEXT (global))
-           mplist_set (p, Mtext, MPLIST_MTEXT (global));
-         else
+         if (! check_description (p))
            mplist_set (p, Msymbol, Mnil);
+         p = MPLIST_NEXT (p);
+         while (! MPLIST_TAIL_P (p))
+           {
+             if (MFAILP (check_command_keyseq (p)))
+               mplist__pop_unref (p);
+             else
+               p = MPLIST_NEXT (p);
+           }
        }
-      p = MPLIST_NEXT (p);
-      MPLIST_DO (p, p)
-       if (MFAILP (check_command_keyseq (p)))
-         break;
-      if (! MPLIST_TAIL_P (p))
-       continue;
       tail = mplist_add (tail, Mplist, pl);
     }
 }
 
+static MPlist *
+config_command (MPlist *plist, MPlist *global_cmds, MPlist *custom_cmds,
+               MPlist *config_cmds)
+{
+  MPlist *global = NULL, *custom = NULL, *config = NULL;
+  MSymbol name;
+  MSymbol status;
+  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) || MPLIST_PLIST_P (plist))
+    {
+      description = plist;
+      plist = MPLIST_NEXT (plist);
+    }
+  else
+    {
+      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 = 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 = config;
+    }
+  else if (custom_cmds && (custom = mplist__assq (custom_cmds, name)))
+    {
+      MPlist *this_keyseq = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (custom)));
+
+      if (MPLIST_TAIL_P (this_keyseq))
+       mplist__pop_unref (custom);
+      else
+       {
+         status = Mcustomized;
+         keyseq = this_keyseq;
+       }
+    }
+  
+  plist = mplist ();
+  mplist_add (plist, Msymbol, name);
+  if (description)
+    mplist_add (plist, MPLIST_KEY (description), MPLIST_VAL (description));
+  else
+    mplist_add (plist, Msymbol, Mnil);
+  mplist_add (plist, Msymbol, status);
+  mplist__conc (plist, keyseq);
+  return plist;
+}
+
 static void
-config_commands (MInputMethodInfo *im_info)
+config_all_commands (MInputMethodInfo *im_info)
 {
+  MPlist *global_cmds, *custom_cmds, *config_cmds;
+  MInputMethodInfo *temp;
   MPlist *tail, *plist;
-  MInputMethodInfo *custom = NULL, *config = NULL;
 
   M17N_OBJECT_UNREF (im_info->configured_cmds);
 
@@ -1665,40 +1817,19 @@ config_commands (MInputMethodInfo *im_info)
       || ! im_info->mdb)
     return;
 
+  global_cmds = im_info != global_info ? global_info->cmds : NULL;
+  custom_cmds = ((temp = get_custom_info (im_info)) ? temp->cmds : NULL);
+  config_cmds = ((temp = get_config_info (im_info)) ? temp->cmds : NULL);
+
   im_info->configured_cmds = tail = mplist ();
-  if ((custom = get_custom_info (im_info)) && ! custom->cmds)
-    custom = NULL;
-  if ((config = get_config_info (im_info)) && ! config->cmds)
-    config = NULL;
   MPLIST_DO (plist, im_info->cmds)
     {
-      MPlist *pl = MPLIST_PLIST (plist), *p = NULL;
-      MSymbol name = MPLIST_SYMBOL (pl);
-
-      if (config)
-       p = mplist__assq (config->cmds, name);
-      if (! p && custom)
-       p = mplist__assq (custom->cmds, name);
-      if (p)
-       {
-         p = MPLIST_PLIST (p);
-         p = MPLIST_NEXT (p);
-         if (MPLIST_TAIL_P (p))
-           p = NULL;
-         else
-           {
-             p = MPLIST_NEXT (p);
-             pl = mplist_copy (pl);
-           }
-       }
-      tail = mplist_add (tail, Mplist, pl);
-      if (p)
+      MPlist *pl = config_command (MPLIST_PLIST (plist),
+                                  global_cmds, custom_cmds, config_cmds);
+      if (pl)
        {
+         tail = mplist_add (tail, Mplist, pl);
          M17N_OBJECT_UNREF (pl);
-         pl = MPLIST_NEXT (pl);
-         pl = MPLIST_NEXT (pl);
-         mplist_set (pl, Mnil, NULL);
-         mplist__conc (pl, p);
        }
     }
 }
@@ -1707,29 +1838,38 @@ config_commands (MInputMethodInfo *im_info)
    valid, return 0 if not.  */
 
 static int
-check_variable_value (MPlist *val, MPlist *valid_values)
+check_variable_value (MPlist *val, MPlist *global)
 {
   MSymbol type = MPLIST_KEY (val);
+  MPlist *valids = MPLIST_NEXT (val);
 
   if (type != Minteger && type != Mtext && type != Msymbol)
     return 0;
-  if (MPLIST_TAIL_P (valid_values))
-    /* No restriction.  Any value is ok.  */
+  if (global)
+    {
+      if (MPLIST_KEY (global) != Mt
+         && MPLIST_KEY (global) != MPLIST_KEY (val))
+       return 0;
+      if (MPLIST_TAIL_P (valids))
+       valids = MPLIST_NEXT (global);
+    }
+  if (MPLIST_TAIL_P (valids))
     return 1;
+
   if (type == Minteger)
     {
       int n = MPLIST_INTEGER (val);
 
-      MPLIST_DO (valid_values, valid_values)
+      MPLIST_DO (valids, valids)
        {
-         if (MPLIST_INTEGER_P (valid_values))
+         if (MPLIST_INTEGER_P (valids))
            {
-             if (n == MPLIST_INTEGER (valid_values))
+             if (n == MPLIST_INTEGER (valids))
                break;
            }
-         else if (MPLIST_PLIST_P (valid_values))
+         else if (MPLIST_PLIST_P (valids))
            {
-             MPlist *p = MPLIST_PLIST (valid_values);
+             MPlist *p = MPLIST_PLIST (valids);
              int min_bound, max_bound;
 
              if (! MPLIST_INTEGER_P (p))
@@ -1748,11 +1888,11 @@ check_variable_value (MPlist *val, MPlist *valid_values)
     {
       MSymbol sym = MPLIST_SYMBOL (val);
 
-      MPLIST_DO (valid_values, valid_values)
+      MPLIST_DO (valids, valids)
        {
-         if (! MPLIST_SYMBOL_P (valid_values))
+         if (! MPLIST_SYMBOL_P (valids))
            MERROR (MERROR_IM, 0);
-         if (sym == MPLIST_SYMBOL (valid_values))
+         if (sym == MPLIST_SYMBOL (valids))
            break;
        }
     }
@@ -1760,16 +1900,16 @@ check_variable_value (MPlist *val, MPlist *valid_values)
     {
       MText *mt = MPLIST_MTEXT (val);
 
-      MPLIST_DO (valid_values, valid_values)
+      MPLIST_DO (valids, valids)
        {
-         if (! MPLIST_MTEXT_P (valid_values))
+         if (! MPLIST_MTEXT_P (valids))
            MERROR (MERROR_IM, 0);
-         if (mtext_cmp (mt, MPLIST_MTEXT (valid_values)) == 0)
+         if (mtext_cmp (mt, MPLIST_MTEXT (valids)) == 0)
            break;
        }
     }
 
-  return (MPLIST_TAIL_P (valid_values));
+  return (! MPLIST_TAIL_P (valids));
 }
 
 /* Load variable defitions from PLIST into IM_INFO->vars.
@@ -1795,74 +1935,188 @@ load_variables (MInputMethodInfo *im_info, MPlist *plist)
   MPlist *tail;
 
   im_info->vars = tail = mplist ();
-
   MPLIST_DO (plist, MPLIST_NEXT (plist))
     {
-      MPlist *pl, *p, *global = NULL;
-      MSymbol name;
-      MPlist *valid_values;
+      MPlist *pl, *p;
 
       if (MFAILP (MPLIST_PLIST_P (plist)))
        continue;
-      pl = MPLIST_PLIST (plist); /* PL ::= (NAME [DESC VALUE VALID ...]) */
+      pl = MPLIST_PLIST (plist); /* PL ::= (NAME DESC VALUE VALID ...) */
       if (MFAILP (MPLIST_SYMBOL_P (pl)))
        continue;
-      name = MPLIST_SYMBOL (pl);
-      p = MPLIST_NEXT (pl);    /* P ::= ([DESC VALUE VALID ...]) */
-      if (global_vars
-         && (global = mplist__assq (global_vars, name)))
+      if (im_info == global_info)
        {
-         /* GLOBAL ::= ((NAME DESC ...) ...) */
-         global = MPLIST_PLIST (global); /* GLOBAL ::= (NAME DESC ...) */
-         global = MPLIST_NEXT (global);  /* GLOBAL ::= (DESC VALUE ...) */
-       }
-      if (! MPLIST_MTEXT_P (p))
-       {
-         if (global && MPLIST_MTEXT_P (global))
-           mplist_set (p, Mtext, MPLIST_MTEXT (global));
+         /* Loading a global variable.  */
+         p = MPLIST_NEXT (pl);
+         if (MPLIST_TAIL_P (p))
+           mplist_add (p, Msymbol, Mnil);
          else
-           mplist_set (p, Msymbol, Mnil);
+           {
+             if (! check_description (p))
+               mplist_set (p, Msymbol, Mnil);
+             p = MPLIST_NEXT (p);
+             if (MFAILP (! MPLIST_TAIL_P (p)
+                         && check_variable_value (p, NULL)))
+               mplist_set (p, Mt, NULL);
+           }
        }
-      p = MPLIST_NEXT (p);     /* p ::= ([VALUE VALID ...]) */
-      if (MPLIST_TAIL_P (p))
+      else if (im_info->mdb)
        {
-         if (MFAILP (global))
-           continue;
-         global = MPLIST_NEXT (global);
-         mplist__conc (p, global);
+         /* Loading a local variable.  */
+         MSymbol name = MPLIST_SYMBOL (pl);
+         MPlist *global = NULL;
+
+         if (global_vars
+             && (p = mplist__assq (global_vars, name)))
+           {
+             /* P ::= ((NAME DESC ...) ...) */
+             p = MPLIST_PLIST (p); /* P ::= (NAME DESC ...) */
+             global = MPLIST_NEXT (p); /* P ::= (DESC VALUE ...) */
+             global = MPLIST_NEXT (global); /* P ::= (VALUE ...) */
+           }
+
+         p = MPLIST_NEXT (pl); /* P ::= (DESC VALUE VALID ...) */
+         if (! MPLIST_TAIL_P (p))
+           {
+             if (! check_description (p))
+               mplist_set (p, Msymbol, Mnil);
+             p = MPLIST_NEXT (p); /* P ::= (VALUE VALID ...) */
+             if (MFAILP (! MPLIST_TAIL_P (p)))
+               mplist_set (p, Mt, NULL);
+             else
+               {
+                 MPlist *valid_values = MPLIST_NEXT (p);
+
+                 if (! MPLIST_TAIL_P (valid_values)
+                     ? MFAILP (check_variable_value (p, NULL))
+                     : global && MFAILP (check_variable_value (p, global)))
+                   mplist_set (p, Mt, NULL);
+               }
+           }
        }
       else
        {
-         if (MFAILP (MPLIST_INTEGER_P (p) || MPLIST_MTEXT_P (p)
-                     || MPLIST_SYMBOL_P (p)))
+         /* Loading a variable customization.  */
+         p = MPLIST_NEXT (pl); /* P ::= (nil VALUE) */
+         if (MFAILP (! MPLIST_TAIL_P (p)))
            continue;
-         valid_values = MPLIST_NEXT (p);
-         if (MPLIST_TAIL_P (valid_values)
-             && global)
-           {
-             global = MPLIST_NEXT (global); /* GLOBAL ::= (VALUE VALID ...) */
-             if (MFAILP (MPLIST_KEY (p) == MPLIST_KEY (global)))
-               continue;
-             valid_values = MPLIST_NEXT (global);
-             if (! MPLIST_TAIL_P (valid_values))
-               mplist__conc (p, valid_values);
-           }
-         if (MFAILP (check_variable_value (p, valid_values)))
+         p = MPLIST_NEXT (p);  /* P ::= (VALUE) */
+         if (MFAILP (MPLIST_INTEGER_P (p) || MPLIST_SYMBOL_P (p)
+                     || MPLIST_MTEXT_P (p)))
            continue;
        }
       tail = mplist_add (tail, Mplist, pl);
     }
 }
 
+static MPlist *
+config_variable (MPlist *plist, MPlist *global_vars, MPlist *custom_vars,
+                MPlist *config_vars)
+{
+  MPlist *global = NULL, *custom = NULL, *config = NULL;
+  MSymbol name = MPLIST_SYMBOL (plist);
+  MSymbol status;
+  MPlist *description = NULL, *value, *valids;
+
+  if (global_vars)
+    {
+      global = mplist__assq (global_vars, name);
+      if (global)
+       global = MPLIST_NEXT (MPLIST_PLIST (global)); /* (DESC VALUE ...) */
+    }
+
+  plist = MPLIST_NEXT (plist);
+  if (MPLIST_MTEXT_P (plist) || MPLIST_PLIST_P (plist))
+    description = plist;
+  else if (global)
+    description = global;
+  if (global)
+    global = MPLIST_NEXT (global); /* (VALUE VALIDS ...) */
+
+  if (MPLIST_TAIL_P (plist))
+    {
+      /* Inherit from global (if any).  */
+      if (global)
+       {
+         value = global;
+         if (MPLIST_KEY (value) == Mt)
+           value = NULL;
+         valids = MPLIST_NEXT (global);
+         status = Minherited;
+       }
+      else
+       {
+         value = NULL;
+         valids = NULL;
+         status = Mnil;
+         plist = NULL;
+       }
+    }
+  else
+    {
+      value = plist = MPLIST_NEXT (plist);
+      valids = MPLIST_NEXT (value);
+      if (MPLIST_KEY (value) == Mt)
+       value = NULL;
+      if (! MPLIST_TAIL_P (valids))
+       global = NULL;
+      else if (global)
+       valids = MPLIST_NEXT (global);
+      status = Mnil;
+    }
+
+  if (config_vars && (config = mplist__assq (config_vars, name)))
+    {
+      status = Mconfigured;
+      config = MPLIST_NEXT (MPLIST_PLIST (config));
+      if (! MPLIST_TAIL_P (config))
+       {
+         value = config;
+         if (MFAILP (check_variable_value (value, global ? global : plist)))
+           value = NULL;
+       }
+    }
+  else if (custom_vars && (custom = mplist__assq (custom_vars, name)))
+    {
+      MPlist *this_value = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (custom)));
+
+      if (MPLIST_TAIL_P (this_value))
+       mplist__pop_unref (custom);
+      else
+       {
+         value = this_value;
+         if (MFAILP (check_variable_value (value, global ? global : plist)))
+           value = NULL;
+         status = Mcustomized;
+       }
+    }
+  
+  plist = mplist ();
+  mplist_add (plist, Msymbol, name);
+  if (description)
+    mplist_add (plist, MPLIST_KEY (description), MPLIST_VAL (description));
+  else
+    mplist_add (plist, Msymbol, Mnil);
+  mplist_add (plist, Msymbol, status);
+  if (value)
+    mplist_add (plist, MPLIST_KEY (value), MPLIST_VAL (value));
+  else
+    mplist_add (plist, Mt, NULL);
+  if (valids && ! MPLIST_TAIL_P (valids))
+    mplist__conc (plist, valids);
+  return plist;
+}
+
 /* Return a configured variable definition list based on
    IM_INFO->vars.  If a variable in it doesn't contain a value, try to
    get it from global_info->vars.  */
 
 static void
-config_variables (MInputMethodInfo *im_info)
+config_all_variables (MInputMethodInfo *im_info)
 {
+  MPlist *global_vars, *custom_vars, *config_vars;
+  MInputMethodInfo *temp;
   MPlist *tail, *plist;
-  MInputMethodInfo *custom = NULL, *config = NULL;
 
   M17N_OBJECT_UNREF (im_info->configured_vars);
 
@@ -1870,46 +2124,25 @@ config_variables (MInputMethodInfo *im_info)
       || ! im_info->mdb)
     return;
 
-  im_info->configured_vars = tail = mplist ();
-  if ((custom = get_custom_info (im_info)) && ! custom->vars)
-    custom = NULL;
-  if ((config = get_config_info (im_info)) && ! config->vars)
-    config = NULL;
+  global_vars = im_info != global_info ? global_info->vars : NULL;
+  custom_vars = ((temp = get_custom_info (im_info)) ? temp->vars : NULL);
+  config_vars = ((temp = get_config_info (im_info)) ? temp->vars : NULL);
 
+  im_info->configured_vars = tail = mplist ();
   MPLIST_DO (plist, im_info->vars)
     {
-      MPlist *pl = MPLIST_PLIST (plist), *p = NULL;
-      MSymbol name = MPLIST_SYMBOL (pl);
-
-      if (config)
-       p = mplist__assq (config->vars, name);
-      if (! p && custom)
-       p = mplist__assq (custom->vars, name);
-      if (p)
-       {
-         p = MPLIST_PLIST (p);
-         p = MPLIST_NEXT (p);
-         if (MPLIST_TAIL_P (p))
-           p = NULL;
-         else
-           {
-             p = MPLIST_NEXT (p);
-             pl = mplist_copy (pl);
-           }
-       }
-      tail = mplist_add (tail, Mplist, pl);
-      if (p)
+      MPlist *pl = config_variable (MPLIST_PLIST (plist),
+                                   global_vars, custom_vars, config_vars);
+      if (pl)
        {
+         tail = mplist_add (tail, Mplist, pl);
          M17N_OBJECT_UNREF (pl);
-         pl = MPLIST_NEXT (pl);
-         pl = MPLIST_NEXT (pl);
-         mplist_set (pl, MPLIST_KEY (p), MPLIST_VAL (p));
        }
     }
 }
 
 /* Load an input method (LANGUAGE NAME) from PLIST into IM_INFO.
-   CONFIG contains configulation information of the input method.  */
+   CONFIG contains configuration information of the input method.  */
 
 static void
 load_im_info (MPlist *plist, MInputMethodInfo *im_info)
@@ -1919,7 +2152,7 @@ load_im_info (MPlist *plist, MInputMethodInfo *im_info)
   if (! im_info->cmds && (pl = mplist__assq (plist, Mcommand)))
     {
       load_commands (im_info, MPLIST_PLIST (pl));
-      config_commands (im_info);
+      config_all_commands (im_info);
       pl = mplist_pop (pl);
       M17N_OBJECT_UNREF (pl);
     }
@@ -1927,7 +2160,7 @@ load_im_info (MPlist *plist, MInputMethodInfo *im_info)
   if (! im_info->vars && (pl = mplist__assq (plist, Mvariable)))
     {
       load_variables (im_info, MPLIST_PLIST (pl));
-      config_variables (im_info);
+      config_all_variables (im_info);
       pl = mplist_pop (pl);
       M17N_OBJECT_UNREF (pl);
     }
@@ -2066,11 +2299,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);
@@ -2122,7 +2354,12 @@ shift_state (MInputContext *ic, MSymbol state_name)
   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;
 
@@ -2175,22 +2412,53 @@ 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);
   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;
+  adjust_markers (ic, pos, pos, nchars);
   ic->preedit_changed = 1;
 }
 
@@ -2198,25 +2466,32 @@ 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)
 {
@@ -2232,27 +2507,30 @@ 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 & mdebug_mask)
        {
          int i;
 
-         MDEBUG_PRINT (" (produced");
+         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)
        {
@@ -2260,16 +2538,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 == ']'))
     {
@@ -2313,11 +2587,10 @@ update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
   int ingroup_index = idx - start;
   MText *mt;
 
-  preedit_delete (ic, from, to);
   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
@@ -2328,7 +2601,7 @@ 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);
@@ -2465,14 +2738,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))
        {
@@ -2490,7 +2758,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)
@@ -2508,50 +2777,45 @@ 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
-           {
-             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_DO (tail, tail)
            {
-             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);
+       }
+    }
+
   return plist;
 }
 
@@ -2609,7 +2873,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
@@ -2651,7 +2915,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))
            {
@@ -2659,6 +2923,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));
@@ -2672,7 +2938,6 @@ take_action_list (MInputContext *ic, MPlist *action_list)
          mtext_put_prop (ic->preedit,
                          ic->cursor_pos - len, ic->cursor_pos,
                          Mcandidate_index, (void *) 0);
-         M17N_OBJECT_UNREF (plist);
        }
       else if (name == Mselect)
        {
@@ -2680,31 +2945,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,
@@ -2746,6 +3021,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;
@@ -2760,7 +3036,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
            {
@@ -2772,12 +3058,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)
        {
@@ -2797,25 +3083,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;
            }
@@ -2854,6 +3157,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;
@@ -2872,8 +3180,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;
@@ -2885,7 +3193,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),
@@ -2915,14 +3223,25 @@ take_action_list (MInputContext *ic, MPlist *action_list)
 
          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
@@ -3031,7 +3350,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)))
@@ -3138,47 +3461,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");
@@ -3202,15 +3521,21 @@ init_ic_info (MInputContext *ic)
   if (im_info->configured_vars)
     MPLIST_DO (plist, im_info->configured_vars)
       {
-       MPlist *pl = MPLIST_PLIST (plist), *p = mplist ();
+       MPlist *pl = MPLIST_PLIST (plist);
        MSymbol name = MPLIST_SYMBOL (pl);
 
-       pl = MPLIST_NEXT (MPLIST_NEXT (pl));
-       mplist_push (ic_info->vars, Mplist, p);
-       M17N_OBJECT_UNREF (p);
-       mplist_add (p, Msymbol, name);
-       mplist_add (p, MPLIST_KEY (pl), MPLIST_VAL (pl));
+       pl = MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (pl)));
+       if (MPLIST_KEY (pl) != Mt)
+         {
+           MPlist *p = mplist ();
+
+           mplist_push (ic_info->vars, Mplist, p);
+           M17N_OBJECT_UNREF (p);
+           mplist_add (p, Msymbol, name);
+           mplist_add (p, MPLIST_KEY (pl), MPLIST_VAL (pl));
+         }
       }
+  ic_info->vars_saved = mplist_copy (ic_info->vars);
 
   if (im_info->externals)
     {
@@ -3221,7 +3546,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);
@@ -3250,7 +3575,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);
@@ -3262,6 +3587,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);
 
@@ -3283,6 +3609,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)
     {
@@ -3430,6 +3757,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;
 
@@ -3442,6 +3770,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;
@@ -3459,18 +3791,40 @@ 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);
 
   if (mtext_nchars (ic->produced) > 0)
     {
       MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
 
+      if (mdebug__flag & mdebug_mask)
+       {
+         MDEBUG_PRINT (" (produced");
+         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);
     }
+  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);
 }
@@ -3584,6 +3938,9 @@ minput__init ()
   Minput_reset = msymbol ("input-reset");
   Minput_get_surrounding_text = msymbol ("input-get-surrounding-text");
   Minput_delete_surrounding_text = msymbol ("input-delete-surrounding-text");
+  Mcustomized = msymbol ("customized");
+  Mconfigured = msymbol ("configured");
+  Minherited = msymbol ("inherited");
 
   minput_default_driver.open_im = open_im;
   minput_default_driver.close_im = close_im;
@@ -3592,8 +3949,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;
@@ -3618,21 +3975,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)
 {
@@ -3659,7 +4001,7 @@ minput__char_to_key (int c)
     argument of callback functions of an input method driver (see
     #MInputDriver::callback_list).  
 
-    Most of them don't require extra argument nor return any value;
+    Most of them do not require extra argument nor return any value;
     exceptions are these:
 
     Minput_get_surrounding_text: When a callback function assigned for
@@ -3669,14 +4011,16 @@ 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
     to the retrieved M-text.  The length of the M-text may be shorter
     than the requested number of characters, if the available text is
     not that long.  The length can be zero in the worst case.  Or, the
-    length may be longer if an application thinks it's more efficient
-    to return that length).
+    length may be longer if an application thinks it is more efficient
+    to return that length.
 
     If the surrounding text is not currently supported, the callback
     function should return without changing the first element of
@@ -3689,13 +4033,37 @@ minput__char_to_key (int c)
     same way as the case of Minput_get_surrounding_text.  The callback
     function must delete the specified text.  It should not alter
     #MInputContext::plist.  */ 
-
 /***ja
     @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
 
     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND 
     °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£
-      */ 
+
+    ¤Û¤È¤ó¤É¤ÏÄɲäΰú¿ô¤òɬÍפȤ·¤Ê¤¤¤·ÃͤòÊÖ¤µ¤Ê¤¤¤¬¡¢°Ê²¼¤ÏÎã³°¤Ç¤¢¤ë¡£
+
+    Minput_get_surrounding_text: ¤³¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿¥³¡¼¥ë¥Ð¥Ã
+    ¥¯´Ø¿ô¤¬¸Æ¤Ð¤ì¤¿ºÝ¤Ë¤Ï¡¢ #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤϥ­¡¼¤È¤·
+    ¤Æ#Minteger ¤ò¤È¤ê¡¢¤½¤ÎÃͤϥµ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤Î¤¦¤Á¤É¤ÎÉôʬ
+    ¤ò¼è¤Ã¤ÆÍè¤ë¤«¤ò»ØÄꤹ¤ë¡£Ãͤ¬Àµ¤Ç¤¢¤ì¤Ð¡¢¸½ºß¤Î¥«¡¼¥½¥ë°ÌÃ֤˳¤¯
+    ÃͤθĿôʬ¤Îʸ»ú¤ò¼è¤ë¡£Éé¤Ç¤¢¤ì¤Ð¡¢¥«¡¼¥½¥ë°ÌÃÖ¤ËÀè¹Ô¤¹¤ëÃͤÎÀäÂÐ
+    ÃÍʬ¤Îʸ»ú¤ò¼è¤ë¡£¸½ºß¥µ¥é¥¦¥ó¥É¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ë¤«¤É¤¦
+    ¤«¤òÃΤꤿ¤¤¤À¤±¤Ç¤¢¤ì¤Ð¡¢¤³¤ÎÃͤϥ¼¥í¤Ç¤âÎɤ¤¡£
+
+    ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ï
+    ¤³¤ÎÍ×ÁǤΥ­¡¼¤ò #Mtext ¤Ë¡¢Ãͤò¼è¤ê¹þ¤ó¤ÀM-text ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê
+    ¤é¤Ê¤¤¡£¤â¤·¥Æ¥­¥¹¥È¤ÎŤµ¤¬½¼Ê¬¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î M-text ¤ÎŤµ¤ÏÍ×
+    µá¤µ¤ì¤Æ¤¤¤ëʸ»ú¿ô¤è¤êû¤¯¤ÆÎɤ¤¡£ºÇ°­¤Î¾ì¹ç 0 ¤Ç¤â¤è¤¤¤·¡¢¥¢¥×¥ê¥±¡¼
+    ¥·¥ç¥ó¦¤ÇɬÍפǸúΨŪ¤À¤È»×¤¨¤ÐŤ¯¤Æ¤âÎɤ¤¡£
+
+    ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø
+    ¿ô¤Ï #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤòÊѹ¹¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+
+    Minput_delete_surrounding_text: ¤³¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿¥³¡¼¥ë
+    ¥Ð¥Ã¥¯´Ø¿ô¤¬¸Æ¤Ð¤ì¤¿ºÝ¤Ë¤Ï¡¢#MInputContext::plist ¤ÎÂè°ìÍ×ÁǤϡ¢¥­¡¼
+    ¤È¤·¤Æ#Minteger ¤ò¤È¤ê¡¢ÃͤϺï½ü¤¹¤ë¤Ù¤­¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥­¥¹¥È¤ò
+    Minput_get_surrounding_text ¤ÈƱÍͤΤä¤êÊý¤Ç»ØÄꤹ¤ë¡£¥³¡¼¥ë¥Ð¥Ã¥¯
+    ´Ø¿ô¤Ï»ØÄꤵ¤ì¤¿¥Æ¥­¥¹¥È¤òºï½ü¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤Þ¤¿
+    #MInputContext::plist ¤òÊѤ¨¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */ 
 /*** @{ */ 
 /*=*/
 
@@ -3722,6 +4090,10 @@ MSymbol Minput_delete_surrounding_text;
 
     These are the predefined symbols that are used as the @c KEY
     argument of minput_filter ().  */ 
+/***ja
+    @name ÊÑ¿ô: ÆÃÊ̤ÊÆþÎÏ¥¤¥Ù¥ó¥ÈÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
+
+    minput_filter () ¤Î @c KEY °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë¡£  */ 
 
 /*** @{ */ 
 /*=*/
@@ -3733,6 +4105,25 @@ MSymbol Minput_focus_move;
 /*** @} */
 
 /*=*/
+/***en
+    @name Variables: Predefined symbols used in input method information.
+
+    These are the predefined symbols describing status of input method
+    command and variable, and are used in a return value of
+    minput_get_command () and minput_get_variable ().  */
+/***ja
+    @name ÊÑ¿ô: ÆþÎϥ᥽¥Ã¥É¾ðÊóÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
+
+    ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤äÊÑ¿ô¤Î¾õÂÖ¤òɽ¤·¡¢minput_get_command () ¤È
+    minput_get_variable () ¤ÎÌá¤êÃͤȤ·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë¡£  */
+/*** @{ */ 
+/*=*/
+MSymbol Minherited;
+MSymbol Mcustomized;
+MSymbol Mconfigured;
+/*** @} */ 
+
+/*=*/
 
 /***en
     @brief The default driver for internal input methods.
@@ -3755,7 +4146,6 @@ MSymbol Minput_focus_move;
     Therefore, unless @c minput_driver is set differently, the driver
     dependent arguments $ARG of the functions whose name begins with
     "minput_" are all ignored.  */
-
 /***ja
     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
 
@@ -3801,6 +4191,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
@@ -3822,7 +4222,6 @@ MSymbol Minput_driver;
 
     $ARG is set in the member @c arg of the structure MInputMethod so
     that the driver can refer to it.  */
-
 /***ja
     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
 
@@ -3959,9 +4358,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");
@@ -3995,9 +4394,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);
@@ -4063,16 +4462,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;
@@ -4175,7 +4578,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);
 }
 /*=*/
 
@@ -4195,7 +4598,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;
 }
 
@@ -4225,7 +4628,7 @@ void
 minput_reset_ic (MInputContext *ic)
 {
   if (ic->im->driver.callback_list)
-    minput__callback (ic, Minput_reset);
+    minput_callback (ic, Minput_reset);
 }
 
 /*=*/
@@ -4246,6 +4649,21 @@ minput_reset_ic (MInputContext *ic)
     If there exists a specified input method and it defines an title,
     a plist is returned.  Otherwise, NULL is returned.  The caller
     must free the plist by m17n_object_unref ().  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¤Î¥¿¥¤¥È¥ë¤È¥¢¥¤¥³¥óÍÑ¥Õ¥¡¥¤¥ë̾¤òÆÀ¤ë.
+
+    ´Ø¿ô minput_get_title_icon () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ë
+    ÆþÎϥ᥽¥Ã¥É¤Î¥¿¥¤¥È¥ë¤È¡Ê¤¢¤ì¤Ð¡Ë¥¢¥¤¥³¥óÍÑ¥Õ¥¡¥¤¥ë¤ò´Þ¤à plist ¤ò
+    ÊÖ¤¹¡£
+
+    plist ¤ÎÂè°ìÍ×ÁǤϡ¢#Mtext ¤ò¥­¡¼¤Ë»ý¤Á¡¢ÃͤÏÆþÎϥ᥽¥Ã¥É¤ò¼±Ê̤¹¤ë
+    ¥¿¥¤¥È¥ë¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£ÂèÆóÍ×ÁǤ¬¤¢¤ì¤Ð¡¢¥­¡¼¤Ï #Mtext ¤Ç¤¢
+    ¤ê¡¢Ãͤϼ±ÊÌÍÑ¥¢¥¤¥³¥ó²èÁü¥Õ¥¡¥¤¥ë¤ÎÀäÂХѥ¹¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£
+
+    @return
+    »ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¡¢¥¿¥¤¥È¥ë¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ì¤Ð
+     plist ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð NULL ¤òÊÖ¤¹¡£¸Æ½Ð¦¤Ï
+     ´Ø¿ô m17n_object_unref () ¤òÍѤ¤¤Æ plist ¤ò²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */
 
 MPlist *
 minput_get_title_icon (MSymbol language, MSymbol name)
@@ -4318,294 +4736,308 @@ 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);
   return im_info->description;
 }
 
+/*=*/
+
 /***en
-    @brief Get information about input method commands.
+    @brief Get information about input method command(s).
 
-    The minput_get_commands () function returns information about
-    input method commands of the input method specified by $LANGUAGE
-    and $NAME.  An input method command is a pseudo key event to which
-    one or more actual input key sequences are assigned.
+    The minput_get_command () function returns information about
+    the command $COMMAND of the input method specified by $LANGUAGE and
+    $NAME.  An input method command is a pseudo key event to which one
+    or more actual input key sequences are assigned.
 
-    There are two kinds of commands, global and local.  Global
-    commands are used by multiple input methods for the same purpose,
-    and have global key assignments.  Local commands are used only by
-    a specific input method, and have only local key assignments.
+    There are two kinds of commands, global and local.  A global
+    command has a global definition, and the description and the key
+    assignment may be inherited by a local command.  Each input method
+    defines a local command which has a local key assignment.  It may
+    also declare a local command that inherits the definition of a
+    global command of the same name.
 
-    Each input method may locally change key assignments for global
-    commands.  The global key assignment for a global command is
-    effective only when the current input method does not have local
-    key assignments for that command.
+    If $LANGUAGE is #Mt and $NAME is #Mnil, this function returns
+    information about a global command.  Otherwise information about a
+    local command is returned.
 
-    If $NAME is #Mnil, information about global commands is returned.
-    In this case $LANGUAGE is ignored.
+    If $COMMAND is #Mnil, information about all commands is returned.
 
-    If $NAME is not #Mnil, information about those commands that have
-    local key assignments in the input method specified by $LANGUAGE
-    and $NAME is returned.
+    The return value is a @e well-formed plist (#m17nPlist) of this
+    format:
+@verbatim
+  ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
+@endverbatim
+    @c NAME is a symbol representing the command name.
 
-    @return
-    If no input method commands are found, this function returns @c NULL.
+    @c DESCRIPTION is an M-text describing the command, or #Mnil if the
+    command has no description.
 
-    Otherwise, a pointer to a plist is returned.  The key of each
-    element in the plist is a symbol representing a command, and the
-    value is a plist of the form COMMAND-INFO described below.
+    @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 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
+    corresponding global command).
 
-    The first element of COMMAND-INFO has the key #Mtext, and the
-    value is an M-text describing the command.
+    @c KEYSEQ is a plist of one or more symbols representing a key
+    sequence assigned to the command.  If there's no KEYSEQ, the
+    command is currently disabled (i.e. no key sequence can trigger
+    actions of the command).
 
-    If there are no more elements, that means no key sequences are
-    assigned to the command.  Otherwise, each of the remaining
-    elements has the key #Mplist, and the value is a plist whose keys are
-    #Msymbol and values are symbols representing input keys, which are
-    currently assigned to the command.
+    If $COMMAND is not #Mnil, the first element of the returned plist
+    contains the information about $COMMAND.
 
-    As the returned plist is kept in the library, the caller must not
-    modify nor free it.  */
+    @return
+
+    If the requested information was found, a pointer to a non-empty
+    plist is returned.  As the plist is kept in the library, the
+    caller must not modify nor free it.
+
+    Otherwise (the specified input method or the specified command
+    does not exist), @c NULL is returned.  */
 /***ja
     @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
 
-    ´Ø¿ô minput_get_commands () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
-    ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã
-    ¥É¥³¥Þ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢¤½¤ì¤¾¤ì¤Ë£±¤Ä°Ê¾å¤Î¼ÂºÝ¤Î
-    ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¤â¤Î¤ò»Ø¤¹¡£
+    ´Ø¿ô minput_get_command () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎÏ
+    ¥á¥½¥Ã¥É¤Î¥³¥Þ¥ó¥É $COMMAND ¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ
+    ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢£±¤Ä°Ê¾å¤Î¼ÂºÝ¤ÎÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨
+    ¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤ë¡£
 
-    ¥³¥Þ¥ó¥É¤Ë¤Ï¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É
-    ¤ÏÊ£¿ô¤ÎÆþÎϥ᥽¥Ã¥É¤Ë¤ª¤¤¤Æ¡¢Æ±¤¸ÌÜŪ¤Ç¡¢¥°¥í¡¼¥Ð¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ
-    ¤ÇÍѤ¤¤é¤ì¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤ÏÆÃÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Î¤ß¡¢¥í¡¼¥«¥ë
-    ¤Ê¥­¡¼³äÅö¤Ç»ÈÍѤµ¤ì¤ë¡£
+    ¥³¥Þ¥ó¥É¤Ë¤Ï¡¢¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¤Ê¥³¥Þ¥ó¥É
+    ¤Ï¥°¥í¡¼¥Ð¥ë¤ËÄêµÁ¤µ¤ì¡¢¥í¡¼¥«¥ë¤Ê¥³¥Þ¥ó¥É¤Ï¤½¤ÎÀâÌÀ¤È¥­¡¼³ä¤êÅö¤Æ
+    ¤ò·Ñ¾µ¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£³ÆÆþÎϥ᥽¥Ã¥É¤Ï¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤ò»ý¤Ä¥í¡¼
+    ¥«¥ë¤Ê¥³¥Þ¥ó¥É¤òÄêµÁ¤¹¤ë¡£¤Þ¤¿Æ±Ì¾¤Î¥°¥í¡¼¥Ð¥ë¤Ê¥³¥Þ¥ó¥É¤ÎÄêµÁ¤ò·Ñ
+    ¾µ¤¹¤ë¥í¡¼¥«¥ë¤Ê¥³¥Þ¥ó¥É¤òÀë¸À¤¹¤ë¤³¤È¤â¤Ç¤­¤ë¡£
 
-    ¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ï¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Î¥­¡¼³äÅö¤òÊѹ¹¤¹¤ë¤³¤È¤â¤Ç
-    ¤­¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥ÉÍѤΥ°¥í¡¼¥Ð¥ë¥­¡¼³ä¤êÅö¤Æ¤Ï¡¢»ÈÍѤ¹¤ëÆþÎÏ
-    ¥á¥½¥Ã¥É¤Ë¤ª¤¤¤Æ¤½¤Î¥³¥Þ¥ó¥ÉÍÑ¤Î¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤¬Â¸ºß¤·¤Ê¤¤¾ì¹ç
-    ¤Ë¤Î¤ßÍ­¸ú¤Ç¤¢¤ë¡£
+    $LANGUAGE ¤¬ #Mt ¤Ç $NAME ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤³¤Î´Ø¿ô¤Ï¥°¥í¡¼¥Ð¥ë¥³
+    ¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¤â
+    ¤Î¤òÊÖ¤¹¡£
 
-    $NAME ¤¬ #Mnil ¤Ç¤¢¤ì¤Ð¡¢¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤³¤Î
-    ¾ì¹ç¡¢$LANGUAGE ¤Ï̵»ë¤µ¤ì¤ë¡£
+    $COMMAND ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£
 
-    $NAME ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþ
-    Îϥ᥽¥Ã¥É¤ËÃÖ¤±¤ë¥í¡¼¥«¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ¤ò»ý¤Ä¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó
-    ¤òÊÖ¤¹¡£
+    Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (#m17nPlist) ¤Ç¤¢¤ë¡£
+
+@verbatim
+  ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
+@endverbatim
+    @c NAME ¤Ï¥³¥Þ¥ó¥É̾¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
+
+    @c DESCRIPTION ¤Ï¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë
+    ¤Ï #Mnil ¤Ç¤¢¤ë¡£
+
+    @c STATUS ¤Ï¥­¡¼³ä¤êÅö¤Æ¤¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë
+    ¤Ç¤¢¤ê¡¢¤½¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤Î³ä¤êÅö¤Æ¡Ë, #Mcustomized ¡Ê¥æ¡¼
+    ¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿³ä¤êÅö¤Æ¡Ë,
+    #Mconfigured ¡Êminput_config_command ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ë
+    ³ä¤êÅö¤Æ¡Ë¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Î¾ì¹ç¤Ë¤Ï¡¢
+    #Minherited ¡ÊÂбþ¤¹¤ë¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤«¤é¤Î·Ñ¾µ¤Ë¤è¤ë³ä¤êÅö¤Æ¡Ë
+    ¤Ç¤â¤è¤¤¡£
+
+    @c KEYSEQ ¤Ï£±¤Ä°Ê¾å¤Î¥·¥ó¥Ü¥ë¤«¤é¤Ê¤ë plist ¤Ç¤¢¤ê¡¢³Æ¥·¥ó¥Ü¥ë¤Ï¥³¥Þ
+    ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òɽ¤¹¡£KEYSEQ ¤¬Ìµ¤¤¾ì¹ç¤Ï¡¢
+    ¤½¤Î¥³¥Þ¥ó¥É¤Ï¸½¾õ¤Ç»ÈÍÑÉÔǽ¤Ç¤¢¤ë¡£¡Ê¤¹¤Ê¤ï¤Á¥³¥Þ¥ó¥É¤ÎÆ°ºî¤òµ¯
+    Æ°¤Ç¤­¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Ìµ¤¤¡£¡Ë
+
+    $COMMAND ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÖ¤µ¤ì¤ë plist ¤ÎºÇ½é¤ÎÍ×ÁǤϡ¢
+    $COMMAND ¤Ë´Ø¤¹¤ë¾ðÊó¤ò´Þ¤à¡£
 
     @return
-    ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï @c NULL ¤òÊÖ¤¹¡£
 
-    ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹¥È¤Î³ÆÍ×ÁǤÎ
-    ¥­¡¼¤Ï¸Ä¡¹¤Î¥³¥Þ¥ó¥É¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢Ãͤϲ¼µ­¤Î COMMAND-INFO
-    ¤Î·Á¼°¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ë¡£
+    µá¤á¤é¤ì¤¿¾ðÊ󤬸«¤Ä¤«¤ì¤Ð¡¢¶õ¤Ç¤Ê¤¤ plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹
+    ¥È¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð¦¤¬Êѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë
+    ¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
 
-    COMMAND-INFO ¤ÎÂè°ìÍ×ÁǤΥ­¡¼¤Ï #Mtext ¤Þ¤¿¤Ï #Msymbol ¤Ç¤¢¤ë¡£¥­¡¼
-    ¤¬ #Mtext ¤Ê¤é¡¢ÃͤϤ½¤Î¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£¥­¡¼¤¬
-    #Msymbol ¤Ê¤éÃͤϠ#Mnil ¤Ç¤¢¤ê¡¢¤³¤Î¥³¥Þ¥ó¥É¤ÏÀâÌÀ¥Æ¥­¥¹¥È¤ò»ý¤¿¤Ê
-    ¤¤¤³¤È¤Ë¤Ê¤ë¡£
+    ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤¹¤Ê¤ï¤Á»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ä¥³¥Þ¥ó¥É¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð
+    @c NULL ¤òÊÖ¤¹¡£  */
 
-    ¤½¤ì°Ê³°¤ÎÍ×ÁǤ¬Ìµ¤±¤ì¤Ð¡¢¤³¤Î¥³¥Þ¥ó¥É¤ËÂФ·¤Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä
-    ¤êÅö¤Æ¤é¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢»Ä¤ê¤Î³ÆÍ×ÁǤϥ­
-    ¡¼¤È¤·¤Æ#Mplist ¤ò¡¢ÃͤȤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò»ý¤Ä¡£¤³¤Î¥×¥í¥Ñ¥Æ¥£
-    ¥ê¥¹¥È¤Î¥­¡¼¤Ï #Msymbol ¤Ç¤¢¤ê¡¢Ãͤϸ½ºß¤½¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì
-    ¤Æ¤¤¤ëÆþÎÏ¥­¡¼¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
+#if EXAMPLE_CODE
+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.  */
+  MPlist *cmd = minput_get_command (langauge, name, command);
+  MPlist *plist;
 
-    ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð
-    ¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£*/
+  if (! cmds)
+    return NULL;
+  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);
+}
+#endif
 
 MPlist *
-minput_get_commands (MSymbol language, MSymbol name)
+minput_get_command (MSymbol language, MSymbol name, MSymbol command)
 {
   MInputMethodInfo *im_info;
-  MPlist *cmds;
 
   MINPUT__INIT ();
 
   im_info = get_im_info (language, name, Mnil, Mcommand);
-  if (! im_info || ! im_info->configured_vars)
+  if (! im_info
+      || ! im_info->configured_cmds
+      || MPLIST_TAIL_P (im_info->configured_cmds))
     return NULL;
-  M17N_OBJECT_UNREF (im_info->bc_cmds);
-  im_info->bc_cmds = mplist ();
-  MPLIST_DO (cmds, im_info->configured_cmds)
-    {
-      MPlist *plist = MPLIST_PLIST (cmds);
-      MPlist *elt = mplist ();
-
-      mplist_push (im_info->bc_cmds, Mplist, elt);
-      mplist_add (elt, MPLIST_SYMBOL (plist),
-                 mplist_copy (MPLIST_NEXT (plist)));
-      M17N_OBJECT_UNREF (elt);
-    }
-  return im_info->bc_cmds;
+  if (command == Mnil)
+    return im_info->configured_cmds;
+  return mplist__assq (im_info->configured_cmds, command);
 }
 
+/*=*/
+
 /***en
-    @brief Assign a key sequence to an input method command (obsolete).
+    @brief Configure the key sequence of an input method command.
 
-    This function is obsolete.  Use minput_config_command () instead.
+    The minput_config_command () function assigns a list of key
+    sequences $KEYSEQLIST to the command $COMMAND of the input method
+    specified by $LANGUAGE and $NAME.
 
-    The minput_assign_command_keys () function assigns input key
-    sequence $KEYSEQ to input method command $COMMAND for the input
-    method specified by $LANGUAGE and $NAME.  If $NAME is #Mnil, the
-    key sequence is assigned globally no matter what $LANGUAGE is.
-    Otherwise the key sequence is assigned locally.
+    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.
 
-    Each element of $KEYSEQ must have the key $Msymbol and the value
-    must be a symbol representing an input key.
+    If $KEYSEQLIST is an empty plist, any configuration and
+    customization of the command are cancelled, and default key
+    sequences become effective.
 
-    $KEYSEQ may be @c NULL, in which case, all assignments are deleted
-    globally or locally.
+    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.
 
-    This assignment gets effective in a newly opened input method.
+    In the latter two cases, $COMMAND can be #Mnil to make all the
+    commands of the input method the target of the operation.
 
-    @return
-    If the operation was successful, 0 is returned.  Otherwise -1 is
-    returned, and #merror_code is set to #MERROR_IM.  */
-/***ja
-    @brief ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤ò³ä¤êÅö¤Æ¤ë.
+    If $NAME is #Mnil, this function configures the key assignment of a
+    global command, not that of a specific input method.
 
-    ´Ø¿ô minput_assign_command_keys () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ
-    »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥ÉÍѤÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É $COMMAND ¤ËÂФ·¤Æ¡¢
-    ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹ $KEYSEQ ¤ò³ä¤êÅö¤Æ¤ë¡£ $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢
-    $LANGUAGE ¤Ë´Ø·¸¤Ê¤¯¡¢ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥°¥í¡¼¥Ð¥ë¤Ë³ä¤êÅö¤Æ¤é
-    ¤ì¤ë¡£¤½¤¦¤Ç¤Ê¤ì¤Ð¡¢³ä¤êÅö¤Æ¤Ï¥í¡¼¥«¥ë¤Ç¤¢¤ë¡£
+    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 customization file by the function
+    minput_save_config ().
 
-    $KEYSEQ ¤Î³ÆÍ×ÁǤϥ­¡¼¤È¤·¤Æ $Msymbol ¤ò¡¢ÃͤȤ·¤ÆÆþÎÏ¥­¡¼¤òɽ¤¹¥·
-    ¥ó¥Ü¥ë¤ò»ý¤¿¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+    @return
+    If the operation was successful, this function returns 0,
+    otherwise returns -1.  The operation fails in these cases:
+    <ul>
+    <li>$KEYSEQLIST is not in a valid form.
+    <li>$COMMAND is not available for the input method.
+    <li>$LANGUAGE and $NAME do not specify an existing input method.
+    </ul>
 
-    $KEYSEQ ¤Ï @c NULL ¤Ç¤â¤è¤¤¡£¤³¤Î¾ì¹ç¡¢¥°¥í¡¼¥Ð¥ë¤â¤·¤¯¤Ï¥í¡¼¥«¥ë¤Ê
-    ¤¹¤Ù¤Æ¤Î³ä¤êÅö¤Æ¤¬¾Ãµî¤µ¤ì¤ë¡£
+    @seealso
+    minput_get_commands (), minput_save_config ().
+*/
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òÀßÄꤹ¤ë.
 
-    ¤³¤Î³ä¤êÅö¤Æ¤Ï¡¢³ä¤êÅö¤Æ°Ê¹ß¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­
-    ¸ú¤Ë¤Ê¤ë¡£
+    ´Ø¿ô minput_config_command () ¤Ï¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È
+    $KEYSEQLIST ¤ò¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤Î
+    ¥³¥Þ¥ó¥É $COMMAND ¤Ë³ä¤êÅö¤Æ¤ë¡£
 
-    @return ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
-    #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
+    $KEYSEQLIST ¤¬¶õ¥ê¥¹¥È¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È¤Ç¤¢¤ê¡¢
+    ³Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥·¥ó¥Ü¥ë¤Î plist ¤Ç¤¢¤ë¡£
 
-int
-minput_assign_command_keys (MSymbol language, MSymbol name,
-                           MSymbol command, MPlist *keyseq)
-{
-  int ret;
+    $KEYSEQLIST ¤¬¶õ¤Î plist ¤Ê¤é¤Ð¡¢¤½¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤ä¥«¥¹¥¿¥Þ¥¤¥º¤Ï
+    ¤¹¤Ù¤Æ¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¥Ç¥Õ¥©¥ë¥È¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Í­¸ú¤Ë¤Ê¤ë¡£
 
-  MINPUT__INIT ();
+    $KEYSEQLIST ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢¤½¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢
+    ¸µ¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¡Ê¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤µ¤ì¤Æ¤¤
+    ¤ë¤â¤Î¡¢¤¢¤ë¤¤¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¤â¤Î¡Ë¤¬Í­¸ú¤Ë¤Ê¤ë¡£
 
-  if (command == Mnil)
-    MERROR (MERROR_IM, -1);
-  if (keyseq)
-    {
-      MPlist *plist;
+    ¸å¤Î¤Õ¤¿¤Ä¤Î¾ì¹ç¤Ë¤Ï¡¢$COMMAND ¤Ï #Mnil ¤ò¤È¤ë¤³¤È¤¬¤Ç¤­¡¢»ØÄê¤ÎÆþ
+    Îϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤Î¥³¥Þ¥ó¥ÉÀßÄê¤Î¥­¥ã¥ó¥»¥ë¤ò°ÕÌ£¤¹¤ë¡£
 
-      if  (! check_command_keyseq (keyseq))
-       MERROR (MERROR_IM, -1);
-      plist = mplist ();
-      mplist_add (plist, Mplist, keyseq);
-      keyseq = plist;
-    }  
-  else
-    keyseq = mplist ();
-  ret = minput_config_command (language, name, command, keyseq);
-  M17N_OBJECT_UNREF (keyseq);
-  return ret;
-}
+    $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð
+    ¥ë¤Ê¥³¥Þ¥ó¥É¤Î¥­¡¼³ä¤êÅö¤Æ¤òÀßÄꤹ¤ë¡£
 
-MPlist *
-minput_get_command (MSymbol language, MSymbol name, MSymbol command)
-{
-  MInputMethodInfo *im_info;
+    ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï
+    ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹
+    ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤
+    ¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
 
-  MINPUT__INIT ();
+    @return
 
-  im_info = get_im_info (language, name, Mnil, Mcommand);
-  if (! im_info || ! im_info->configured_cmds)
-    return NULL;
-  if (command == Mnil)
-    return im_info->configured_cmds;
-  return mplist__assq (im_info->configured_cmds, command);
-}
+    ¤³¤Î´Ø¿ô¤Ï¡¢½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤ò¡¢¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ¤¹¡£¼ºÇԤȤϰʲ¼¤Î¾ì¹ç¤Ç¤¢¤ë¡£
+    <ul>
+    <li>$KEYSEQLIST ¤¬Í­¸ú¤Ê·Á¼°¤Ç¤Ê¤¤¡£
+    <li>$COMMAND ¤¬»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÇÍøÍѤǤ­¤Ê¤¤¡£
+    <li>$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¤Ê¤¤¡£
+    </ul>
+
+    @seealso
+    minput_get_commands (), minput_save_config ().
+*/
 
 #if EXAMPLE_CODE
-/* Return a description of the command COMMAND of the input method
-   specified by LANGUAGE and NAME.  */
-MText *
-get_im_command_help (MSymbol language, MSymbol name, MSymbol command)
+/* Add "C-x u" to the "start" command of Unicode input method.  */
 {
-  MPlist *cmd = minput_get_command (langauge, name, command);
-  MPlist *plist;
+  MSymbol start_command = msymbol ("start");
+  MSymbol unicode = msymbol ("unicode");
+  MPlist *cmd, *plist, *key_seq_list, *key_seq;
 
-  if (! cmds)
-    return NULL;
-  plist = mplist_value (cmds); /* (NAME DESCRIPTION KEY-SEQ ...) */
-  plist = mplist_next (plist); /* (DESCRIPTION KEY-SEQ ...) */
-  return (MText *) mplist_value (list);
+  /* At first get the current key-sequence assignment.  */
+  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.  */
+    }
+  /* 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);
+  
+  key_seq = mplist ();
+  mplist_add (key_seq, Msymbol, msymbol ("C-x"));
+  mplist_add (key_seq, Msymbol, msymbol ("u"));
+  mplist_add (key_seq_list, Mplist, key_seq);
+  m17n_object_unref (key_seq);
+
+  minput_config_command (Mt, unicode, start_command, key_seq_list);
+  m17n_object_unref (key_seq_list);
 }
 #endif
 
-/***en
-    @brief Configure the key sequence of an input method command.
-
-    The minput_config_command () function assigns list of key
-    sequences $KEYSEQ-LIST to the command $COMMAND for the input
-    method specified by $LANGUAGE and $NAME.
-
-    If $KEYSEQ-LIST is a non-empty plist, it must be a list of key
-    sequences, and each key sequence must be a plist of key symbols.
-
-    If $KEYSEQ is an empty plist, the command become unusable.
-
-    If $KEYSEQ is NULL, all configulations of the command for the
-    input method are canceled, and the default key sequences become
-    effective.  In that case, if $COMMAND is #Mnil, configurations for
-    all commands of the input method are canceled.
-
-    If $NAME is #Mnil, this function configure the global key sequence
-    assignments, not that of a specific input method.
-
-    The configulation (or the cancelling) takes effect instantly for
-    the current session even for already opened input methods.  To
-    make the configulation take effect for the future session, it must
-    be saved 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:
-
-    $KEYSEQ is not in a valid form.
-
-    $COMMAND is not available for the input method.
-
-    $LANGUAGE and $NAME don't specify an existing input method.
-
-    @seealso
-    minput_get_commands (), minput_save_config ().  */
-
 int
 minput_config_command (MSymbol language, MSymbol name, MSymbol command,
-                      MPlist *keyseq)
+                      MPlist *keyseqlist)
 {
   MInputMethodInfo *im_info, *config;
   MPlist *plist;
 
   MINPUT__INIT ();
 
-  if (keyseq && ! check_command_keyseq (keyseq))
-    MERROR (MERROR_IM, -1);
   im_info = get_im_info (language, name, Mnil, Mcommand);
   if (! im_info)
     MERROR (MERROR_IM, -1);
-  if (command == Mnil)
+  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))
     {
-      if (keyseq)
-       MERROR (MERROR_IM, -1);
+      MPLIST_DO (plist, keyseqlist)
+       if (! check_command_keyseq (plist))
+         MERROR (MERROR_IM, -1);
     }
-  else if (! im_info->cmds
-          || ! mplist__assq (im_info->cmds, command))
-    MERROR (MERROR_IM, -1);
 
   config = get_config_info (im_info);
   if (! config)
@@ -4617,13 +5049,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));
@@ -4637,309 +5085,294 @@ 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 DESC KEY-SEQUENCE ...)  */
-         plist = MPLIST_NEXT (plist);  /* (DESC ...) */
-         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_push (config->cmds, Mplist, plist);
-         M17N_OBJECT_UNREF (plist);
-         plist = mplist_add (plist, Msymbol, command);
+         /* 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 (keyseq)
+      else
        {
-         MPlist *pl, *p;
+         MPlist *pl;
 
-         keyseq = mplist_copy (keyseq);
-         MPLIST_DO (pl, keyseq)
+         if (plist)
            {
-             p = mplist_copy (MPLIST_VAL (pl));
-             mplist_set (pl, Mplist, p);
-             M17N_OBJECT_UNREF (p);
+             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));
+             plist = mplist_add (plist, Mplist, pl);
+             M17N_OBJECT_UNREF (pl);
            }
-         plist = mplist_add (plist, Msymbol, Mnil);
-         mplist__conc (plist, keyseq);
-         M17N_OBJECT_UNREF (keyseq);
        }
     }
-  config_commands (im_info);
+  config_all_commands (im_info);
   im_info->tick = time (NULL);
   return 0;
 }
 
-#if EXAMPLE_CODE
-/* Add "C-x u" to the "start" command of Unicode input method.  */
-{
-  MSymbol start_command = msymbol ("start");
-  MSymbol unicode = msymbol ("unicode");
-  MPlist *cmd, *plist, *key_seq_list, *key_seq;
+/*=*/
 
-  /* At first get the current key-sequence assignment.  */
-  cmd = mplist_get_command (Mt, unicode, start_command);
-  if (! cmd)
-    {
-      /* The input method doesn't have the command "start".  Here
-        comes some error handling code.  */
-    }
-  /* Now CMD == ((start DESCRIPTION KEY-SEQUENCE ...) ...).  Extract
-     the part (KEY-SEQUENCE ...).  */
-  plist = 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_list, Mplist, key_seq);
-  m17n_object_unref (key_seq);
+/***en
+    @brief Get information about input method variable(s).
 
-  minput_config_command (Mt, unicode, start_command, key_seq_list);
-  m17n_object_unref (key_seq_list);
-}
-#endif
+    The minput_get_variable () function returns information about
+    variable $VARIABLE of the input method specified by $LANGUAGE and $NAME.
+    An input method variable controls behavior of an input method.
 
-/***en
-    @brief Get a list of variables of an input method (obsolete).
+    There are two kinds of variables, global and local.  A global
+    variable has a global definition, and the description and the value
+    may be inherited by a local variable.  Each input method defines a
+    local variable which has local value.  It may also declare a
+    local variable that inherits definition of a global variable of
+    the same name.
 
-    This function is obsolete.  Use minput_get_variable () instead.
+    If $LANGUAGE is #Mt and $NAME is #Mnil, information about a global
+    variable is returned.  Otherwise information about a local variable
+    is returned.
 
-    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:
+    If $VARIABLE is #Mnil, information about all variables is
+    returned.
 
+    The return value is a @e well-formed plist (#m17nPlist) of this
+    format:
 @verbatim
-    (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
-     VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
-     ...)
+  ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...)
 @endverbatim
+    @c NAME is a symbol representing the variable name.
 
-    @c VARNAME is a symbol representing the variable name.
+    @c DESCRIPTION is an M-text describing the variable, or #Mnil if the
+    variable has no description.
 
-    @c DOC-MTEXT is an M-text describing the variable.
+    @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 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).
 
-    @c DEFAULT-VALUE is the default value of the variable.  It is a
-    symbol, integer, or M-text.
+    @c VALUE is the initial value of the variable.  If the key of this
+    element is #Mt, the variable has no initial value.  Otherwise, the
+    key is #Minteger, #Msymbol, or #Mtext and the value is of the
+    corresponding type.
 
-    @c VALUEs (if any) specifies the possible values of the variable.
-    If @c DEFAULT-VALUE is an integer, @c VALUE may be a plist (@c FROM
-    @c TO), where @c FROM and @c TO specifies a range of possible
+    @c VALID-VALUEs (if any) specify which values the variable can have.
+    They have the same type (i.e. having the same key) as @c VALUE except
+    for the case that VALUE is an integer.  In that case, @c VALID-VALUE
+    may be a plist of two integers specifying the range of possible
     values.
 
-    For instance, suppose an input method has the variables:
+    If there no @c VALID-VALUE, the variable can have any value as long
+    as the type is the same as @c VALUE.
 
-    @li name:intvar, description:"value is an integer",
-         initial value:0, value-range:0..3,10,20
+    If $VARIABLE is not #Mnil, the first element of the returned plist
+    contains the information about $VARIABLE.
 
-    @li name:symvar, description:"value is a symbol",
-         initial value:nil, value-range:a, b, c, nil
+    @return
 
-    @li name:txtvar, description:"value is an M-text",
-         initial value:empty text, no value-range (i.e. any text)
+    If the requested information was found, a pointer to a non-empty
+    plist is returned.  As the plist is kept in the library, the
+    caller must not modify nor free it.
 
-    Then, the returned plist is as follows.
+    Otherwise (the specified input method or the specified variable
+    does not exist), @c NULL is returned.  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
 
-@verbatim
-    (intvar ("value is an integer" 0 (0 3) 10 20)
-     symvar ("value is a symbol" nil a b c nil)
-     txtvar ("value is an M-text" ""))
-@endverbatim
+    ´Ø¿ô minput_get_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎÏ
+    ¥á¥½¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤È¤Ï¡¢
+    ÆþÎϥ᥽¥Ã¥É¤Î¿¶Éñ¤òÀ©¸æ¤¹¤ë¤â¤Î¤Ç¤¢¤ë¡£
 
-    @return
-    If the input method uses any variables, a pointer to #MPlist is
-    returned.  As the plist is kept in the library, the caller must not
-    modify nor free it.  If the input method does not use any
-    variable, @c NULL is returned.  */
-/***ja
-    @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¥ê¥¹¥È¤òÆÀ¤ë.
+    ÊÑ¿ô¤Ë¤Ï¡¢¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¤ÊÊÑ¿ô¤Ï¥°
+    ¥í¡¼¥Ð¥ë¤ËÄêµÁ¤µ¤ì¡¢¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤Ï¤½¤ÎÀâÌÀ¤ÈÃͤò·Ñ¾µ¤¹¤ë¤³¤È¤¬¤Ç
+    ¤­¤ë¡£³ÆÆþÎϥ᥽¥Ã¥É¤Ï¥í¡¼¥«¥ë¤ÊÃͤò»ý¤Ä¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤òÄêµÁ¤¹¤ë¡£
+    ¤Þ¤¿Æ±Ì¾¤Î¥°¥í¡¼¥Ð¥ë¤ÊÊÑ¿ô¤ÎÄêµÁ¤ò·Ñ¾µ¤¹¤ë¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤òÀë¸À¤¹¤ë
+    ¤³¤È¤â¤Ç¤­¤ë¡£
 
-    ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
-    ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È
-    (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(#m17nPlist) °Ê
-    ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£
+    $LANGUAGE ¤¬ #Mt ¤Ç $NAME ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤³¤Î´Ø¿ô¤Ï¥°¥í¡¼¥Ð¥ëÊÑ
+    ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥í¡¼¥«¥ëÊÑ¿ô¤Ë´Ø¤¹¤ë¤â¤Î¤òÊÖ¤¹¡£
+
+    $VARIABLE ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£
 
+    Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (#m17nPlist) ¤Ç¤¢¤ë¡£
 @verbatim
-    (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
-     VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
-     ...)
+  ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...)
 @endverbatim
 
-    @c VARNAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
-
-    @c DOC-MTEXT ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£
+    @c NAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
 
-    @c DEFAULT-VALUE ¤ÏÊÑ¿ô¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤǤ¢¤ê¡¢¥·¥ó¥Ü¥ë¡¢À°¿ô¤â¤·¤¯¤Ï
-    M-text ¤Ç¤¢¤ë¡£
+    @c DESCRIPTION ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë¤Ï
+    #Mnil ¤Ç¤¢¤ë¡£
 
-    @c VALUE ¤Ï¡¢¤â¤·»ØÄꤵ¤ì¤Æ¤¤¤ì¤ÐÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò¼¨¤¹¡£¤â¤·
-    @c DEFAULT-VALUE ¤¬À°¿ô¤Ê¤é¡¢ @c VALUE ¤Ï (@c FROM @c TO) ¤È¤¤¤¦·Á
-    ¤Î¥ê¥¹¥È¤Ç¤âÎɤ¤¡£¤³¤Î¾ì¹ç @c FROM ¤È @c TO ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹¡£
+    @c STATUS ¤ÏÃͤ¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢
+    @c STATUS ¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¡Ë, #Mcustomized ¡Ê¥æ¡¼¥¶Ëè¤Î
+    ¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿ÃÍ¡Ë, #Mconfigured
+    ¡Êminput_config_variable ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ëÃ͡ˤΤ¤¤º¤ì
+    ¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ëÊÑ¿ô¤Î¾ì¹ç¤Ë¤Ï¡¢#Minherited ¡ÊÂбþ¤¹¤ë¥°¥í¡¼¥Ð¥ë
+    ÊÑ¿ô¤«¤é·Ñ¾µ¤·¤¿Ã͡ˤǤâ¤è¤¤¡£
 
-    Îã¤È¤·¤Æ¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤¬¼¡¤Î¤è¤¦¤ÊÊÑ¿ô¤ò»ý¤Ä¾ì¹ç¤ò¹Í¤¨¤è¤¦¡£
+    @c VALUE ¤ÏÊÑ¿ô¤Î½é´üÃͤǤ¢¤ë¡£¤³¤ÎÍ×ÁǤΥ­¡¼¤¬#Mt ¤Ç¤¢¤ì¤Ð½é´üÃͤò»ý
+    ¤¿¤Ê¤¤¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¤Ï #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì
+    ¤«¤Ç¤¢¤ê¡¢ÃͤϤ½¤ì¤¾¤ìÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£
 
-    @li name:intvar, ÀâÌÀ:"value is an integer",
-        ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20
+    @c VALID-VALUE ¤Ï¤â¤·¤¢¤ì¤Ð¡¢ÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò»ØÄꤹ¤ë¡£¤³¤ì¤Ï @c VALUE
+    ¤ÈƱ¤¸·¿(¤¹¤Ê¤ï¤ÁƱ¤¸¥­¡¼¤ò»ý¤Ä) ¤Ç¤¢¤ë¤¬¡¢Îã³°¤È¤·¤Æ @c VALUE ¤¬
+    integer ¤Î¾ì¹ç¤Ï @c VALID-VALUE ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹Æó¤Ä¤ÎÀ°¿ô¤«¤é
+    ¤Ê¤ë plist ¤È¤Ê¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
 
-    @li name:symvar, ÀâÌÀ:"value is a symbol",
-         ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil
+    @c VALID-VALUE ¤¬¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô¤Ï @c VALUE ¤ÈƱ¤¸·¿¤Ç¤¢¤ë¸Â¤ê¤¤¤«¤Ê¤ëÃͤâ
+    ¤È¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
 
-    @li name:txtvar, ÀâÌÀ:"value is an M-text",
-        ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä)
+    $VARIABLE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÖ¤µ¤ì¤ë plist ¤ÎºÇ½é¤ÎÍ×ÁǤÏ
+    $VARIABLE ¤Ë´Ø¤¹¤ë¾ðÊó¤ò´Þ¤à¡£
 
-    ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
+    @return
 
-@verbatim
-    (intvar ("value is an integer" 0 (0 3) 10 20)
-     symvar ("value is a symbol" nil a b c nil)
-     txtvar ("value is an M-text" ""))
-@endverbatim
+    µá¤á¤é¤ì¤¿¾ðÊ󤬸«¤Ä¤«¤ì¤Ð¡¢¶õ¤Ç¤Ê¤¤ plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹
+    ¥È¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð¦¤¬Êѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë
+    ¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
 
-    @return 
-    ÆþÎϥ᥽¥Ã¥É¤¬²¿¤é¤«¤ÎÊÑ¿ô¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð #MPlist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
-    ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
-    ÆþÎϥ᥽¥Ã¥É¤¬ÊÑ¿ô¤ò°ìÀÚ»ÈÍѤ·¤Æ¤Ê¤±¤ì¤Ð¡¢@c NULL ¤òÊÖ¤¹¡£  */
+    ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤¹¤Ê¤ï¤Á»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤äÊÑ¿ô¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð
+    @c NULL ¤òÊÖ¤¹¡£ */
 
 MPlist *
-minput_get_variables (MSymbol language, MSymbol name)
+minput_get_variable (MSymbol language, MSymbol name, MSymbol variable)
 {
   MInputMethodInfo *im_info;
-  MPlist *vars;
 
   MINPUT__INIT ();
 
   im_info = get_im_info (language, name, Mnil, Mvariable);
   if (! im_info || ! im_info->configured_vars)
     return NULL;
+  if (variable == Mnil)
+    return im_info->configured_vars;
+  return mplist__assq (im_info->configured_vars, variable);
+}
 
-  M17N_OBJECT_UNREF (im_info->bc_vars);
-  im_info->bc_vars = mplist ();
-  MPLIST_DO (vars, im_info->configured_vars)
-    {
-      MPlist *plist = MPLIST_PLIST (vars);
-      MPlist *elt = mplist ();
-
-      mplist_push (im_info->bc_vars, Mplist, elt);
-      mplist_add (elt, Msymbol, MPLIST_SYMBOL (plist));
-      elt = MPLIST_NEXT (elt);
-      mplist_set (elt, Mplist, mplist_copy (MPLIST_NEXT (plist)));
-      M17N_OBJECT_UNREF (elt);
-    }
-  return im_info->bc_vars;
-}
+/*=*/
 
 /***en
-    @brief Set the initial value of an input method variable.
+    @brief Configure the value of an input method variable.
 
-    The minput_set_variable () function sets the initial value of
-    input method variable $VARIABLE to $VALUE for the input method
-    specified by $LANGUAGE and $NAME.
+    The minput_config_variable () function assigns $VALUE to the
+    variable $VARIABLE of the input method specified by $LANGUAGE and
+    $NAME.
 
-    By default, the initial value is 0.
+    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.
 
-    This setting gets effective in a newly opened input method.
+    If $VALUE is an empty plist, any configuration and customization
+    of the variable are canceled, and the default value is assigned to
+    the variable.
 
-    @return
-    If the operation was successful, 0 is returned.  Otherwise -1 is
-    returned, and #merror_code is set to #MERROR_IM.  */
-/***ja
-    @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë.
+    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.
 
-    ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME 
-    ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE
-    ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£
+    In the latter two cases, $VARIABLE can be #Mnil to make all the
+    variables of the input method the target of the operation.
 
-    ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃͤϠ0 ¤Ç¤¢¤ë¡£
+    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
+    customization file by the function minput_save_config ().
 
     @return
-    ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
-    #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
-
-int
-minput_set_variable (MSymbol language, MSymbol name,
-                    MSymbol variable, void *value)
-{
-  MPlist *plist, *pl;
-  MInputMethodInfo *im_info;
-  int ret;
-
-  MINPUT__INIT ();
-
-  if (variable == Mnil)
-    MERROR (MERROR_IM, -1);
-  plist = minput_get_variable (language, name, variable);
-  plist = MPLIST_PLIST (plist);
-  plist = MPLIST_NEXT (plist);
-  pl = mplist ();
-  mplist_add (pl, MPLIST_KEY (plist), value);
-  ret = minput_config_variable (language, name, variable, pl);
-  M17N_OBJECT_UNREF (pl);
-  if (ret == 0)
-    {
-      im_info = get_im_info (language, name, Mnil, Mvariable);
-      im_info->tick = 0;
-    }
-  return ret;
-}
-
-MPlist *
-minput_get_variable (MSymbol language, MSymbol name, MSymbol variable)
-{
-  MInputMethodInfo *im_info;
-
-  MINPUT__INIT ();
 
-  im_info = get_im_info (language, name, Mnil, Mvariable);
-  if (! im_info || ! im_info->configured_vars)
-    return NULL;
-  if (variable == Mnil)
-    return im_info->configured_vars;
-  return mplist__assq (im_info->configured_vars, variable);
-}
+    If the operation was successful, this function returns 0,
+    otherwise returns -1.  The operation fails in these cases:
+    <ul>
+    <li>$VALUE is not in a valid form, the type does not match the
+    definition, or the value is our of range.
+    <li>$VARIABLE is not available for the input method.
+    <li>$LANGUAGE and $NAME do not specify an existing input method.  
+    </ul>
 
-/***en
-    @brief Configure the value of an input method variable.
+    @seealso
+    minput_get_variable (), minput_save_config ().  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë.
 
-    The minput_config_variable () function assigns the value $VALUE to
-    the variable $VARIABLE of the input method specified by $LANGUAGE
-    and $NAME.
+    ´Ø¿ô minput_config_variable () ¤ÏÃÍ $VALUE ¤ò¡¢$LANGUAGE ¤È $NAME
+    ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤ë¡£
 
-    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.
+    $VALUE ¤¬ ¶õ¥ê¥¹¥È¤Ç¤Ê¤±¤ì¤Ð¡¢£±Í×ÁǤΠplist ¤Ç¤¢¤ê¡¢¤½¤Î¥­¡¼¤Ï
+    #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì¤«¡¢ÃͤÏÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£
+    ¤³¤ÎÃͤ¬ÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤é¤ì¤ë¡£
 
-    If $VALUE is NULL, configurations for the variable done in the
-    current session are canceled (except for what saved by
-    minput_save_config ()).  In that case, if $VARIABLE is #Mnil,
-    configurations for all variables are canceled.
+    $VALUE ¤¬ ¶õ¥ê¥¹¥È¤Ç¤¢¤ì¤Ð¡¢ÊÑ¿ô¤ÎÀßÄê¤È¥«¥¹¥¿¥Þ¥¤¥º¤¬¥­¥ã¥ó¥»¥ë¤µ
+    ¤ì¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤ¬ÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤é¤ì¤ë¡£
 
-    If $NAME is #Mnil, this function configure the global value, not
-    that of a specific input method.
+    $VALUE ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢ÊÑ¿ô¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¸µ¤ÎÃ͡ʥ桼¥¶
+    Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ëÃæ¤ÎÃÍ¡¢¤Þ¤¿¤Ï¥Ç¥Õ¥©¥ë¥È¤ÎÃ͡ˤ¬³ä¤êÅö¤Æ¤é¤ì¤ë¡£
 
-    The configulation takes effect instantly for the current session
-    even for already opened input methods.  To make the configulation
-    take effect for the future session, it must be saved in a per-user
-    customization file by the function minput_save_config ().
+    ¸å¤Î¤Õ¤¿¤Ä¤Î¾ì¹ç¤Ë¤Ï¡¢$VARIABLE ¤Ï #Mnil ¤ò¤È¤ë¤³¤È¤¬¤Ç¤­¡¢»ØÄꤵ¤ì
+    ¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤ÎÊÑ¿ôÀßÄê¤Î¥­¥ã¥ó¥»¥ë¤ò°ÕÌ£¤¹¤ë¡£
 
-    @return If the operation was successful, this function returns 0,
-    otherwise returns -1.  The operation fails in these cases:
+    $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð
+    ¥ë¤ÊÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë¡£
 
-    $VALUE is not in a valid form, or the type doesn't much the
-    definition.
+    ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï
+    ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹
+    ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤
+    ¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
 
-    $VARIABLE is not available for the input method.
+    @return
 
-    $LANGUAGE and $NAME don't specify an existing input method.  
+    ¤³¤Î´Ø¿ô¤Ï¡¢½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤ò¡¢¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ¤¹¡£¼ºÇԤȤϰʲ¼¤Î¾ì¹ç¤Ç¤¢¤ë¡£
+    <ul>
+    <li>$VALUE¤¬Í­¸ú¤Ê·Á¼°¤Ç¤Ê¤¤¡£·¿¤¬ÄêµÁ¤Ë¹ç¤ï¤Ê¤¤¡¢¤Þ¤¿¤ÏÃͤ¬Èϰϳ°¤Ç¤¢¤ë¡£
+    <li>$VARIABLE ¤¬»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÇÍøÍѤǤ­¤Ê¤¤¡£
+    <li>$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¤Ê¤¤¡£
+    </ul>
 
     @seealso
-    minput_get_variables (), minput_save_config ().  */
-
+    minput_get_commands (), minput_save_config ().
+*/
 int
 minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
                        MPlist *value)
@@ -4952,14 +5385,21 @@ 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 (variable == Mnil ? (value && ! MPLIST_TAIL_P (value))
+      : (! im_info->vars
+        || ! (plist = mplist__assq (im_info->configured_vars, variable))))
+    MERROR (MERROR_IM, -1);
+
+  if (value && ! MPLIST_TAIL_P (value))
     {
-      if (value)
+      plist = MPLIST_PLIST (plist);
+      plist = MPLIST_NEXT (plist); /* (DESC STATUS VALUE VALIDS ...) */
+      plist = MPLIST_NEXT (plist); /* (STATUS VALUE VALIDS ...) */
+      plist = MPLIST_NEXT (plist); /* (VALUE VALIDS ...) */
+      if (MPLIST_KEY (plist) != Mt
+         && ! check_variable_value (value, plist))
        MERROR (MERROR_IM, -1);
     }
-  else if (! im_info->vars
-          || ! mplist__assq (im_info->vars, variable))
-    MERROR (MERROR_IM, -1);
 
   config = get_config_info (im_info);
   if (! config)
@@ -4971,13 +5411,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));
@@ -4991,38 +5447,153 @@ 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 DESC VALUE) */
-         plist = MPLIST_NEXT (plist);  /* (DESC VALUE) */
-         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);
+         /* 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);
-         plist = MPLIST_NEXT (plist);
-         mplist_set (plist, MPLIST_KEY (value), MPLIST_VAL (value));
+         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));
        }
     }
-  config_variables (im_info);
+  config_all_variables (im_info);
   im_info->tick = time (NULL);
   return 0;
 }
 
+/*=*/
+
+/***en
+    @brief Get the name of per-user customization file.
+    
+    The minput_config_file () function returns the absolute path name
+    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
+    readable/writable.  If minput_save_config () fails and returns -1,
+    an application program might check the file, make it
+    writable (if possible), and try minput_save_config () again.
+
+    @return
+
+    This function returns a string.  As the string is kept in the
+    library, the caller must not modify nor free it.
+
+    @seealso
+    minput_save_config ()
+*/
+/***ja
+    @brief ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Î̾Á°¤òÆÀ¤ë.
+    
+    ´Ø¿ô minput_config_file () ¤Ï¡¢´Ø¿ô minput_save_config () ¤¬ÀßÄê¤ò
+    Êݸ¤¹¤ë¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ø¤ÎÀäÂХѥ¹Ì¾¤òÊÖ¤¹¡£Ä̾ï¤Ï¡¢¥æ¡¼¥¶
+    ¤Î¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê¤Î²¼¤Î¥Ç¥£¥ì¥¯¥È¥ê @c ".m17n.d" ¤Ë¤¢¤ë@c
+    "config.mic" ¤È¤Ê¤ë¡£ÊÖ¤µ¤ì¤¿Ì¾Á°¤Î¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤¹¤ë¤«¡¢Æɤ߽ñ¤­¤Ç
+    ¤­¤ë¤«¤ÏÊݾڤµ¤ì¤Ê¤¤¡£´Ø¿ôminput_save_config () ¤¬¼ºÇÔ¤·¤Æ -1 ¤òÊÖ
+    ¤·¤¿¾ì¹ç¤Ë¤Ï¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï¥Õ¥¡¥¤¥ë¤Î¸ºß¤ò³Îǧ¤·¡¢
+    ¡Ê¤Ç¤­¤ì¤Ð¡Ë½ñ¤­¹þ¤ß²Äǽ¤Ë¤·ºÆÅÙminput_save_config () ¤ò»î¤¹¤³¤È¤¬
+    ¤Ç¤­¤ë¡£
+
+    @return
+
+    ¤³¤Î´Ø¿ô¤Ïʸ»úÎó¤òÊÖ¤¹¡£Ê¸»úÎó¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð
+    Â¦¤¬½¤Àµ¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
+
+    @seealso
+    minput_save_config ()
+*/
+
 char *
 minput_config_file ()
 {
   MINPUT__INIT ();
+
   return mdatabase__file (im_custom_mdb);
 }
 
+/*=*/
+
+/***en
+    @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 customization
+    file.
+
+    @return
+
+    If the operation was successful, 1 is returned.  If the per-user
+    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
+    minput_config_file (), make it writable if possible, and try
+    again.
+
+    @seealso
+    minput_config_file ()  */
+/***ja
+    @brief ÀßÄê¤ò¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë.
+
+    ´Ø¿ô minput_save_config () ¤Ï¸½¹Ô¤Î¥»¥Ã¥·¥ç¥ó¤Ç¤³¤ì¤Þ¤Ç¤Ë¹Ô¤Ã¤¿ÀßÄê
+    ¤ò¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë¡£
+
+    @return
+
+    À®¸ù¤¹¤ì¤Ð 1 ¤òÊÖ¤¹¡£¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤¬¥í¥Ã¥¯¤µ¤ì¤Æ¤¤
+    ¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢¸Æ½Ð¦¤Ï¤·¤Ð¤é¤¯ÂԤäƺƻî¹Ô¤Ç¤­¤ë¡£ÀßÄê¥Õ¥¡
+    ¥¤¥ë¤¬½ñ¤­¹þ¤ßÉԲĤξì¹ç¡¢-1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢minput_config_file
+    () ¤ò¸Æ¤ó¤Ç¥Õ¥¡¥¤¥ë̾¤ò¥Á¥§¥Ã¥¯¤·¡¢¤Ç¤­¤ì¤Ð½ñ¤­¹þ¤ß²Äǽ¤Ë¤·¡¢ºÆ»î¹Ô
+    ¤Ç¤­¤ë¡£
+
+    @seealso
+    minput_config_file ()  */
+
 int
 minput_save_config (void)
 {
@@ -5038,8 +5609,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);
@@ -5066,26 +5637,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)
@@ -5097,35 +5663,33 @@ 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);
       MSymbol language, name, extra;
-      MInputMethodInfo *custom;
+      MInputMethodInfo *custom, *im_info;
 
       language = MPLIST_SYMBOL (pl);
       pl  = MPLIST_NEXT (pl);
@@ -5134,46 +5698,494 @@ 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)
+       {
+         if (im_info->cmds)
+           config_all_commands (im_info);
+         if (im_info->vars)
+           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);
        }
     }
 
-  mplist_push (data, Msymbol, msymbol (";;-*-lisp-*-"));
+  mplist_push (data, Mstring, ";; -*- mode:lisp; coding:utf-8 -*-");
   ret = mdatabase__save (im_custom_mdb, data);
-  M17N_OBJECT_UNREF (data);
   mdatabase__unlock (im_custom_mdb);
+  M17N_OBJECT_UNREF (data);
   return (ret < 0 ? -1 : 1);
 }
 
+/*=*/
+/*** @} */
+/*=*/
+/***en
+    @name Obsolete functions
+*/
+/***ja
+    @name Obsolete ¤Ê´Ø¿ô
+*/
+/*** @{ */
+
+/*=*/
+/***en
+    @brief Get a list of variables of an input method (obsolete).
+
+    This function is obsolete.  Use minput_get_variable () instead.
+
+    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:
+
+@verbatim
+    (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
+     VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
+     ...)
+@endverbatim
+
+    @c VARNAME is a symbol representing the variable name.
+
+    @c DOC-MTEXT is an M-text describing the variable.
+
+    @c DEFAULT-VALUE is the default value of the variable.  It is a
+    symbol, integer, or M-text.
+
+    @c VALUEs (if any) specifies the possible values of the variable.
+    If @c DEFAULT-VALUE is an integer, @c VALUE may be a plist (@c FROM
+    @c TO), where @c FROM and @c TO specifies a range of possible
+    values.
+
+    For instance, suppose an input method has the variables:
+
+    @li name:intvar, description:"value is an integer",
+         initial value:0, value-range:0..3,10,20
+
+    @li name:symvar, description:"value is a symbol",
+         initial value:nil, value-range:a, b, c, nil
+
+    @li name:txtvar, description:"value is an M-text",
+         initial value:empty text, no value-range (i.e. any text)
+
+    Then, the returned plist is as follows.
+
+@verbatim
+    (intvar ("value is an integer" 0 (0 3) 10 20)
+     symvar ("value is a symbol" nil a b c nil)
+     txtvar ("value is an M-text" ""))
+@endverbatim
+
+    @return
+    If the input method uses any variables, a pointer to #MPlist is
+    returned.  As the plist is kept in the library, the caller must not
+    modify nor free it.  If the input method does not use any
+    variable, @c NULL is returned.  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¥ê¥¹¥È¤òÆÀ¤ë.
 
+    ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
+    ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È
+    (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(#m17nPlist) °Ê
+    ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£
+
+@verbatim
+    (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
+     VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
+     ...)
+@endverbatim
+
+    @c VARNAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
+
+    @c DOC-MTEXT ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£
+
+    @c DEFAULT-VALUE ¤ÏÊÑ¿ô¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤǤ¢¤ê¡¢¥·¥ó¥Ü¥ë¡¢À°¿ô¤â¤·¤¯¤Ï
+    M-text ¤Ç¤¢¤ë¡£
+
+    @c VALUE ¤Ï¡¢¤â¤·»ØÄꤵ¤ì¤Æ¤¤¤ì¤ÐÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò¼¨¤¹¡£¤â¤·
+    @c DEFAULT-VALUE ¤¬À°¿ô¤Ê¤é¡¢ @c VALUE ¤Ï (@c FROM @c TO) ¤È¤¤¤¦·Á
+    ¤Î¥ê¥¹¥È¤Ç¤âÎɤ¤¡£¤³¤Î¾ì¹ç @c FROM ¤È @c TO ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹¡£
+
+    Îã¤È¤·¤Æ¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤¬¼¡¤Î¤è¤¦¤ÊÊÑ¿ô¤ò»ý¤Ä¾ì¹ç¤ò¹Í¤¨¤è¤¦¡£
+
+    @li name:intvar, ÀâÌÀ:"value is an integer",
+        ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20
+
+    @li name:symvar, ÀâÌÀ:"value is a symbol",
+         ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil
+
+    @li name:txtvar, ÀâÌÀ:"value is an M-text",
+        ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä)
+
+    ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
+
+@verbatim
+    (intvar ("value is an integer" 0 (0 3) 10 20)
+     symvar ("value is a symbol" nil a b c nil)
+     txtvar ("value is an M-text" ""))
+@endverbatim
+
+    @return 
+    ÆþÎϥ᥽¥Ã¥É¤¬²¿¤é¤«¤ÎÊÑ¿ô¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð #MPlist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
+    ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+    ÆþÎϥ᥽¥Ã¥É¤¬ÊÑ¿ô¤ò°ìÀÚ»ÈÍѤ·¤Æ¤Ê¤±¤ì¤Ð¡¢@c NULL ¤òÊÖ¤¹¡£  */
+
+MPlist *
+minput_get_variables (MSymbol language, MSymbol name)
+{
+  MInputMethodInfo *im_info;
+  MPlist *vars;
+
+  MINPUT__INIT ();
+
+  im_info = get_im_info (language, name, Mnil, Mvariable);
+  if (! im_info || ! im_info->configured_vars)
+    return NULL;
+
+  M17N_OBJECT_UNREF (im_info->bc_vars);
+  im_info->bc_vars = mplist ();
+  MPLIST_DO (vars, im_info->configured_vars)
+    {
+      MPlist *plist = MPLIST_PLIST (vars);
+      MPlist *elt = mplist ();
+
+      mplist_push (im_info->bc_vars, Mplist, elt);
+      mplist_add (elt, Msymbol, MPLIST_SYMBOL (plist));
+      elt = MPLIST_NEXT (elt);
+      mplist_set (elt, Mplist, mplist_copy (MPLIST_NEXT (plist)));
+      M17N_OBJECT_UNREF (elt);
+    }
+  return im_info->bc_vars;
+}
+
+/*=*/
+
+/***en
+    @brief Set the initial value of an input method variable.
+
+    The minput_set_variable () function sets the initial value of
+    input method variable $VARIABLE to $VALUE for the input method
+    specified by $LANGUAGE and $NAME.
+
+    By default, the initial value is 0.
+
+    This setting gets effective in a newly opened input method.
+
+    @return
+    If the operation was successful, 0 is returned.  Otherwise -1 is
+    returned, and #merror_code is set to #MERROR_IM.  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë.
+
+    ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME 
+    ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE
+    ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£
+
+    ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃͤϠ0 ¤Ç¤¢¤ë¡£
+
+    ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£
+
+    @return
+    ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
+    #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
+
+int
+minput_set_variable (MSymbol language, MSymbol name,
+                    MSymbol variable, void *value)
+{
+  MPlist *plist, *pl;
+  MInputMethodInfo *im_info;
+  int ret;
+
+  MINPUT__INIT ();
+
+  if (variable == Mnil)
+    MERROR (MERROR_IM, -1);
+  plist = minput_get_variable (language, name, variable);
+  plist = MPLIST_PLIST (plist);
+  plist = MPLIST_NEXT (plist);
+  pl = mplist ();
+  mplist_add (pl, MPLIST_KEY (plist), value);
+  ret = minput_config_variable (language, name, variable, pl);
+  M17N_OBJECT_UNREF (pl);
+  if (ret == 0)
+    {
+      im_info = get_im_info (language, name, Mnil, Mvariable);
+      im_info->tick = 0;
+    }
+  return ret;
+}
+
+/*=*/
+
+/***en
+    @brief Get information about input method commands.
+
+    The minput_get_commands () function returns information about
+    input method commands of the input method specified by $LANGUAGE
+    and $NAME.  An input method command is a pseudo key event to which
+    one or more actual input key sequences are assigned.
+
+    There are two kinds of commands, global and local.  Global
+    commands are used by multiple input methods for the same purpose,
+    and have global key assignments.  Local commands are used only by
+    a specific input method, and have only local key assignments.
+
+    Each input method may locally change key assignments for global
+    commands.  The global key assignment for a global command is
+    effective only when the current input method does not have local
+    key assignments for that command.
+
+    If $NAME is #Mnil, information about global commands is returned.
+    In this case $LANGUAGE is ignored.
+
+    If $NAME is not #Mnil, information about those commands that have
+    local key assignments in the input method specified by $LANGUAGE
+    and $NAME is returned.
+
+    @return
+    If no input method commands are found, this function returns @c NULL.
+
+    Otherwise, a pointer to a plist is returned.  The key of each
+    element in the plist is a symbol representing a command, and the
+    value is a plist of the form COMMAND-INFO described below.
+
+    The first element of COMMAND-INFO has the key #Mtext, and the
+    value is an M-text describing the command.
+
+    If there are no more elements, that means no key sequences are
+    assigned to the command.  Otherwise, each of the remaining
+    elements has the key #Mplist, and the value is a plist whose keys are
+    #Msymbol and values are symbols representing input keys, which are
+    currently assigned to the command.
+
+    As the returned plist is kept in the library, the caller must not
+    modify nor free it.  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
+
+    ´Ø¿ô minput_get_commands () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
+    ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã
+    ¥É¥³¥Þ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢¤½¤ì¤¾¤ì¤Ë£±¤Ä°Ê¾å¤Î¼ÂºÝ¤Î
+    ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¤â¤Î¤ò»Ø¤¹¡£
+
+    ¥³¥Þ¥ó¥É¤Ë¤Ï¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É
+    ¤ÏÊ£¿ô¤ÎÆþÎϥ᥽¥Ã¥É¤Ë¤ª¤¤¤Æ¡¢Æ±¤¸ÌÜŪ¤Ç¡¢¥°¥í¡¼¥Ð¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ
+    ¤ÇÍѤ¤¤é¤ì¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤ÏÆÃÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Î¤ß¡¢¥í¡¼¥«¥ë
+    ¤Ê¥­¡¼³äÅö¤Ç»ÈÍѤµ¤ì¤ë¡£
+
+    ¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ï¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Î¥­¡¼³äÅö¤òÊѹ¹¤¹¤ë¤³¤È¤â¤Ç
+    ¤­¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥ÉÍѤΥ°¥í¡¼¥Ð¥ë¥­¡¼³ä¤êÅö¤Æ¤Ï¡¢»ÈÍѤ¹¤ëÆþÎÏ
+    ¥á¥½¥Ã¥É¤Ë¤ª¤¤¤Æ¤½¤Î¥³¥Þ¥ó¥ÉÍÑ¤Î¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤¬Â¸ºß¤·¤Ê¤¤¾ì¹ç
+    ¤Ë¤Î¤ßÍ­¸ú¤Ç¤¢¤ë¡£
+
+    $NAME ¤¬ #Mnil ¤Ç¤¢¤ì¤Ð¡¢¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤³¤Î
+    ¾ì¹ç¡¢$LANGUAGE ¤Ï̵»ë¤µ¤ì¤ë¡£
+
+    $NAME ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþ
+    Îϥ᥽¥Ã¥É¤ËÃÖ¤±¤ë¥í¡¼¥«¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ¤ò»ý¤Ä¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó
+    ¤òÊÖ¤¹¡£
+
+    @return
+    ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï @c NULL ¤òÊÖ¤¹¡£
+
+    ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹¥È¤Î³ÆÍ×ÁǤÎ
+    ¥­¡¼¤Ï¸Ä¡¹¤Î¥³¥Þ¥ó¥É¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢Ãͤϲ¼µ­¤Î COMMAND-INFO
+    ¤Î·Á¼°¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ë¡£
+
+    COMMAND-INFO ¤ÎÂè°ìÍ×ÁǤΥ­¡¼¤Ï #Mtext ¤Þ¤¿¤Ï #Msymbol ¤Ç¤¢¤ë¡£¥­¡¼
+    ¤¬ #Mtext ¤Ê¤é¡¢ÃͤϤ½¤Î¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£¥­¡¼¤¬
+    #Msymbol ¤Ê¤éÃͤϠ#Mnil ¤Ç¤¢¤ê¡¢¤³¤Î¥³¥Þ¥ó¥É¤ÏÀâÌÀ¥Æ¥­¥¹¥È¤ò»ý¤¿¤Ê
+    ¤¤¤³¤È¤Ë¤Ê¤ë¡£
+
+    ¤½¤ì°Ê³°¤ÎÍ×ÁǤ¬Ìµ¤±¤ì¤Ð¡¢¤³¤Î¥³¥Þ¥ó¥É¤ËÂФ·¤Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä
+    ¤êÅö¤Æ¤é¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢»Ä¤ê¤Î³ÆÍ×ÁǤϥ­
+    ¡¼¤È¤·¤Æ#Mplist ¤ò¡¢ÃͤȤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò»ý¤Ä¡£¤³¤Î¥×¥í¥Ñ¥Æ¥£
+    ¥ê¥¹¥È¤Î¥­¡¼¤Ï #Msymbol ¤Ç¤¢¤ê¡¢Ãͤϸ½ºß¤½¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì
+    ¤Æ¤¤¤ëÆþÎÏ¥­¡¼¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
+
+    ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð
+    ¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£*/
+
+MPlist *
+minput_get_commands (MSymbol language, MSymbol name)
+{
+  MInputMethodInfo *im_info;
+  MPlist *cmds;
+
+  MINPUT__INIT ();
+
+  im_info = get_im_info (language, name, Mnil, Mcommand);
+  if (! im_info || ! im_info->configured_vars)
+    return NULL;
+  M17N_OBJECT_UNREF (im_info->bc_cmds);
+  im_info->bc_cmds = mplist ();
+  MPLIST_DO (cmds, im_info->configured_cmds)
+    {
+      MPlist *plist = MPLIST_PLIST (cmds);
+      MPlist *elt = mplist ();
+
+      mplist_push (im_info->bc_cmds, Mplist, elt);
+      mplist_add (elt, MPLIST_SYMBOL (plist),
+                 mplist_copy (MPLIST_NEXT (plist)));
+      M17N_OBJECT_UNREF (elt);
+    }
+  return im_info->bc_cmds;
+}
+
+/*=*/
+
+/***en
+    @brief Assign a key sequence to an input method command (obsolete).
+
+    This function is obsolete.  Use minput_config_command () instead.
+
+    The minput_assign_command_keys () function assigns input key
+    sequence $KEYSEQ to input method command $COMMAND for the input
+    method specified by $LANGUAGE and $NAME.  If $NAME is #Mnil, the
+    key sequence is assigned globally no matter what $LANGUAGE is.
+    Otherwise the key sequence is assigned locally.
+
+    Each element of $KEYSEQ must have the key $Msymbol and the value
+    must be a symbol representing an input key.
+
+    $KEYSEQ may be @c NULL, in which case, all assignments are deleted
+    globally or locally.
+
+    This assignment gets effective in a newly opened input method.
+
+    @return
+    If the operation was successful, 0 is returned.  Otherwise -1 is
+    returned, and #merror_code is set to #MERROR_IM.  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤ò³ä¤êÅö¤Æ¤ë.
+
+    ´Ø¿ô minput_assign_command_keys () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ
+    »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥ÉÍѤÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É $COMMAND ¤ËÂФ·¤Æ¡¢
+    ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹ $KEYSEQ ¤ò³ä¤êÅö¤Æ¤ë¡£ $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢
+    $LANGUAGE ¤Ë´Ø·¸¤Ê¤¯¡¢ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥°¥í¡¼¥Ð¥ë¤Ë³ä¤êÅö¤Æ¤é
+    ¤ì¤ë¡£¤½¤¦¤Ç¤Ê¤ì¤Ð¡¢³ä¤êÅö¤Æ¤Ï¥í¡¼¥«¥ë¤Ç¤¢¤ë¡£
+
+    $KEYSEQ ¤Î³ÆÍ×ÁǤϥ­¡¼¤È¤·¤Æ $Msymbol ¤ò¡¢ÃͤȤ·¤ÆÆþÎÏ¥­¡¼¤òɽ¤¹¥·
+    ¥ó¥Ü¥ë¤ò»ý¤¿¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+
+    $KEYSEQ ¤Ï @c NULL ¤Ç¤â¤è¤¤¡£¤³¤Î¾ì¹ç¡¢¥°¥í¡¼¥Ð¥ë¤â¤·¤¯¤Ï¥í¡¼¥«¥ë¤Ê
+    ¤¹¤Ù¤Æ¤Î³ä¤êÅö¤Æ¤¬¾Ãµî¤µ¤ì¤ë¡£
+
+    ¤³¤Î³ä¤êÅö¤Æ¤Ï¡¢³ä¤êÅö¤Æ°Ê¹ß¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­
+    ¸ú¤Ë¤Ê¤ë¡£
+
+    @return ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
+    #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
+
+int
+minput_assign_command_keys (MSymbol language, MSymbol name,
+                           MSymbol command, MPlist *keyseq)
+{
+  int ret;
+
+  MINPUT__INIT ();
+
+  if (command == Mnil)
+    MERROR (MERROR_IM, -1);
+  if (keyseq)
+    {
+      MPlist *plist;
+
+      if  (! check_command_keyseq (keyseq))
+       MERROR (MERROR_IM, -1);
+      plist = mplist ();
+      mplist_add (plist, Mplist, keyseq);
+      keyseq = plist;
+    }  
+  else
+    keyseq = mplist ();
+  ret = minput_config_command (language, name, command, keyseq);
+  M17N_OBJECT_UNREF (keyseq);
+  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;
+}
+
+/*** @} */ 
 /*** @} */
 /*=*/
 /*** @addtogroup m17nDebug */