(parse_otf_command): Fix previous change.
[m17n/m17n-lib.git] / src / input.c
index b13eb4d..61baa7a 100644 (file)
@@ -1,5 +1,5 @@
 /* input.c -- input method module.
-   Copyright (C) 2003, 2004, 2005, 2006
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
@@ -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
     input event to an input key by himself.  See the documentation of
     the function minput_event_to_key () for the detail.
 
-    <li> Foreign Input Method
+    <li> Foreign Input Method @anchor foreign-input-method
 
     A foreign input method has @c Mnil LANGUAGE, and its body is
     defined in an external resource (e.g. XIM of X Window System).
     For this kind of input methods, the symbol NAME must have a
-    property of key @c Minput_driver, and the value must be a pointer
+    property of key #Minput_driver, and the value must be a pointer
     to an input method driver.  Therefore, by preparing a proper
     driver, any kind of input method can be treated in the framework
     of the @c m17n @c library.
 
     For convenience, the m17n-X library provides an input method
     driver that enables the input style of OverTheSpot for XIM, and
-    stores @c Minput_driver property of the symbol @c Mxim with a
+    stores #Minput_driver property of the symbol @c Mxim with a
     pointer to the driver.  See the documentation of m17n GUI API for
     the detail.
 
     ¹Ô¤ï¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï´Ø¿ô minput_event_to_key () ¤Î
     ÀâÌÀ¤ò»²¾È¡£
 
-    <li> ³°ÉôÆþÎϥ᥽¥Ã¥É
+    <li> ³°ÉôÆþÎϥ᥽¥Ã¥É @anchor foreign-input-method
 
     ³°ÉôÆþÎϥ᥽¥Ã¥É¤È¤Ï LANGUAGE ¤¬ @c Mnil ¤Î¤â¤Î¤Ç¤¢¤ê¡¢¤½¤ÎËÜÂΤϳ°
     Éô¤Î¥ê¥½¡¼¥¹¤È¤·¤ÆÄêµÁ¤µ¤ì¤ë¡£¡Ê¤¿¤È¤¨¤ÐX Window System ¤ÎXIM ¤Ê
-    ¤É¡£) ¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢¥·¥ó¥Ü¥ë NAME ¤Ï@c Minput_driver ¤ò
+    ¤É¡£) ¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢¥·¥ó¥Ü¥ë NAME ¤Ï #Minput_driver ¤ò
     ¥­¡¼¤È¤¹¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Á¡¢¤½¤ÎÃͤÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó
     ¥¿¤Ç¤¢¤ë¡£¤³¤Î¤³¤È¤Ë¤è¤ê¡¢Å¬Àڤʥɥ饤¥Ð¤ò½àÈ÷¤¹¤ë¤³¤È¤Ë¤è¤Ã¤Æ¡¢¤¤
     ¤«¤Ê¤ë¼ïÎà¤ÎÆþÎϥ᥽¥Ã¥É¤â@c m17n @c ¥é¥¤¥Ö¥é¥ê ¤ÎÏÈÁȤÎÃæ¤Ç°·¤¦»ö
 
     ÍøÊØÀ­¤Î´ÑÅÀ¤«¤é¡¢m17n X ¥é¥¤¥Ö¥é¥ê¤Ï XIM ¤Î OverTheSpot ¤ÎÆþÎÏ¥¹¥¿
     ¥¤¥ë¤ò¼Â¸½¤¹¤ëÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤òÄ󶡤·¡¢¤Þ¤¿¥·¥ó¥Ü¥ë @c Mxim ¤Î
-    @c Minput_driver ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤȤ·¤Æ¤½¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÝ»ý
+    #Minput_driver ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤȤ·¤Æ¤½¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÝ»ý
     ¤·¤Æ¤¤¤ë¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï m17n GUI API ¤Î¥É¥­¥å¥á¥ó¥È¤ò»²¾È¤Î¤³¤È¡£
 
     </ul> 
 #include <dlfcn.h>
 #endif
 
-#include "m17n-gui.h"
+#include "m17n.h"
 #include "m17n-misc.h"
 #include "internal.h"
 #include "mtext.h"
 #include "database.h"
 #include "charset.h"
 
-static int mdebug_mask = MDEBUG_INPUT;
+static int mdebug_flag = MDEBUG_INPUT;
 
 static int fully_initialized;
 
-static MSymbol Minput_method;
-
 /** Symbols to load an input method data.  */
 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 +197,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.  */
@@ -269,7 +269,7 @@ static int update_custom_info (void);
 static MInputMethodInfo *get_im_info (MSymbol, MSymbol, MSymbol, MSymbol);
 
 \f
-void
+static void
 fully_initialize ()
 {
   char *key_names[32]
@@ -277,23 +277,28 @@ fully_initialize ()
        "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL,
        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
        NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL };
-  char buf[6], buf2[32];
+  char buf[6], buf2[32], buf3[2];
   int i, j;
-  /* Maximum case: C-M-a, C-M-A, M-Return, C-A-a, C-A-A, A-Return.  */
-  MSymbol alias[7];
+  /* Maximum case: '\215', C-M-m, C-M-M, M-Return, C-A-m, C-A-M, A-Return
+     plus one for cyclic alias.  */
+  MSymbol alias[8];
 
   M_key_alias = msymbol ("  key-alias");
 
+  buf3[1] = '\0';
+
+  /* Aliases for 0x00-0x1F */
   buf[0] = 'C';
   buf[1] = '-';
   buf[3] = '\0';
   for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++)
     {
-      one_char_symbol[i] = msymbol (buf);
+      j = 0;
+      buf3[0] = i;
+      alias[j++] = msymbol (buf3);
+      alias[j++] = one_char_symbol[i] = msymbol (buf);
       if (key_names[i] || (buf[2] >= 'A' && buf[2] <= 'Z'))
        {
-         j = 0;
-         alias[j++] = one_char_symbol[i];
          if (key_names[i])
            {
              /* Ex: `Escape' == `C-['  */
@@ -306,12 +311,14 @@ fully_initialize ()
              alias[j++] = msymbol (buf);
              buf[2] -= 32;
            }
-         /* Establish cyclic alias chain.  */
-         alias[j] = alias[0];
-         while (--j >= 0)
-           msymbol_put (alias[j], M_key_alias, alias[j + 1]);
        }
+      /* Establish cyclic alias chain.  */
+      alias[j] = alias[0];
+      while (--j >= 0)
+       msymbol_put (alias[j], M_key_alias, alias[j + 1]);
     }
+
+  /* Aliases for 0x20-0x7E */
   buf[0] = 'S';
   for (i = buf[2] = ' '; i < 127; i++, buf[2]++)
     {
@@ -328,19 +335,26 @@ fully_initialize ()
            msymbol_put (alias[j], M_key_alias, alias[j + 1]);
        }
     }
-  buf[0] = 'C';
 
-  alias[0] = alias[2] = one_char_symbol[127] = msymbol ("Delete");
-  alias[1] = msymbol ("C-?");
-  for (j = 0; j < 2; j++)
+  /* Aliases for 0x7F */
+  buf3[0] = 0x7F;
+  alias[0] = alias[3] = msymbol (buf3);
+  alias[1] = one_char_symbol[127] = msymbol ("Delete");
+  alias[2] = msymbol ("C-?");
+  for (j = 0; j < 3; j++)
     msymbol_put (alias[j], M_key_alias, alias[j + 1]);
 
+  /* Aliases for 0x80-0x9F */
+  buf[0] = 'C';
+  /* buf[1] = '-'; -- already done */
   buf[3] = '-';
   buf[5] = '\0';
   buf2[1] = '-';
   for (i = 128, buf[4] = '@'; i < 160; i++, buf[4]++)
     {
       j = 0;
+      buf3[0] = i;
+      alias[j++] = msymbol (buf3);
       /* `C-M-a' == `C-A-a' */
       buf[2] = 'M';
       alias[j++] = one_char_symbol[i] = msymbol (buf);
@@ -365,28 +379,59 @@ fully_initialize ()
          alias[j++] = msymbol (buf);
          buf[4] -= 32;
        }
+
       /* Establish cyclic alias chain.  */
       alias[j] = alias[0];
       while (--j >= 0)
        msymbol_put (alias[j], M_key_alias, alias[j + 1]);
     }
-  for (i = 160, buf[4] = ' '; i < 256; i++, buf[4]++)
+
+  /* Aliases for 0xA0-0xFF */
+  for (i = 160, buf[4] = ' '; i < 255; i++, buf[4]++)
     {
+      j = 0;
+      buf3[0] = i;
+      alias[j++] = msymbol (buf3);
       buf[2] = 'M';
-      alias[0] = alias[2] = one_char_symbol[i] = msymbol (buf + 2);
+      alias[j++] = one_char_symbol[i] = msymbol (buf + 2);
       buf[2] = 'A';
-      alias[1] = msymbol (buf + 2);
-      for (j = 0; j < 2; j++)
+      alias[j++] = msymbol (buf + 2);
+      alias[j]= alias[0];
+      while (--j >= 0)
        msymbol_put (alias[j], M_key_alias, alias[j + 1]);
     }
 
-  alias[0] = alias[4] = one_char_symbol[255] = msymbol ("M-Delete");
-  alias[1] = msymbol ("A-Delete");
-  alias[2] = msymbol ("C-M-?");
-  alias[3] = msymbol ("C-A-?");
-  for (j = 0; j < 4; j++)
+  buf3[0] = (char) 255;
+  alias[0] = alias[3] = msymbol (buf3);
+  alias[1] = one_char_symbol[255] = msymbol ("M-Delete");
+  alias[2] = msymbol ("A-Delete");
+  for (j = 0; j < 3; j++)
     msymbol_put (alias[j], M_key_alias, alias[j + 1]);
 
+  /* Aliases for keys that can't be mapped to one-char-symbol
+     (e.g. C-A-1) */
+  /* buf is already set to "C-?-".  */
+  for (i = ' '; i <= '~'; i++)
+    {
+      if (i == '@')
+       {
+         i = '_';
+         continue;
+       }
+      if (i == 'a')
+       {
+         i = 'z';
+         continue;
+       }
+      buf[2] = 'M';
+      buf[4] = i;
+      alias[0] = alias[2] = msymbol (buf);
+      buf[2] = 'A';
+      alias[1] = msymbol (buf);
+      for (j = 0; j < 2; j++)
+       msymbol_put (alias[j], M_key_alias, alias[j + 1]);
+    }
+
   Minput_method = msymbol ("input-method");
   Mtitle = msymbol ("title");
   Mmacro = msymbol ("macro");
@@ -400,6 +445,7 @@ fully_initialize ()
   Mmove = msymbol ("move");
   Mmark = msymbol ("mark");
   Mpushback = msymbol ("pushback");
+  Mpop = msymbol ("pop");
   Mundo = msymbol ("undo");
   Mcall = msymbol ("call");
   Mshift = msymbol ("shift");
@@ -427,7 +473,7 @@ fully_initialize ()
   Mor = msymbol ("|");
   Mnot = msymbol ("!");
 
-  Mat_reload = msymbol ("@reload");
+  Mat_reload = msymbol ("-reload");
 
   Mcandidates_group_size = msymbol ("candidates-group-size");
   Mcandidates_charset = msymbol ("candidates-charset");
@@ -443,6 +489,7 @@ fully_initialize ()
   Mvariable = msymbol ("variable");
   Mglobal = msymbol ("global");
   Mconfig = msymbol ("config");
+  M_gettext = msymbol ("_");
 
   load_im_info_keys = mplist ();
   mplist_add (load_im_info_keys, Mstate, Mnil);
@@ -466,24 +513,28 @@ fully_initialize ()
 
 \f
 static int
-marker_code (MSymbol sym)
+marker_code (MSymbol sym, int surrounding)
 {
   char *name;
 
   if (sym == Mnil)
     return -1;
   name = MSYMBOL_NAME (sym);
-  return ((name[0] == '@'
-          && ((name[1] >= '0' && name[1] <= '9')
-              || name[1] == '<' || name[1] == '>'
-              || name[1] == '=' || name[1] == '+' || name[1] == '-'
-              || name[1] == '[' || name[1] == ']'
-              || name[1] == '@')
-          && name[2] == '\0')
-         ? name[1] : -1);
+  return (name[0] != '@' ? -1
+         : (((name[1] >= '0' && name[1] <= '9')
+             || name[1] == '<' || name[1] == '>' || name[1] == '='
+             || name[1] == '[' || name[1] == ']'
+             || name[1] == '@')
+            && name[2] == '\0') ? name[1]
+         : (name[1] != '+' && name[1] != '-') ? -1
+         : (name[2] == '\0' || surrounding) ? name[1]
+         : -1);
 }
 
 
+/* Return a plist containing an integer value of VAR.  The plist must
+   not be UNREFed. */
+
 static MPlist *
 resolve_variable (MInputContextInfo *ic_info, MSymbol var)
 {
@@ -509,7 +560,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 +573,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 +594,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 +611,8 @@ get_preceding_char (MInputContext *ic, int pos)
          M17N_OBJECT_UNREF (ic_info->preceding_text);
          ic_info->preceding_text = mt;
        }
+      else
+       M17N_OBJECT_UNREF (mt);
     }
   else
     ic_info->preceding_text = mt;
@@ -572,10 +631,10 @@ get_following_char (MInputContext *ic, int pos)
   if (ic_info->following_text)
     {
       len = mtext_nchars (ic_info->following_text);
-      if (pos <= len)
-       return mtext_ref_char (ic_info->following_text, pos - 1);
+      if (pos < len)
+       return mtext_ref_char (ic_info->following_text, pos);
     }
-  mt = get_surrounding_text (ic, pos);
+  mt = get_surrounding_text (ic, pos + 1);
   if (! mt)
     return -2;
   len = mtext_nchars (mt);
@@ -586,69 +645,91 @@ get_following_char (MInputContext *ic, int pos)
          M17N_OBJECT_UNREF (ic_info->following_text);
          ic_info->following_text = mt;
        }
+      else
+       M17N_OBJECT_UNREF (mt);
     }
   else
     ic_info->following_text = mt;
-  if (pos > len)
+  if (pos >= len)
     return -1;
-  return mtext_ref_char (ic_info->following_text, pos - 1);
+  return mtext_ref_char (ic_info->following_text, pos);
 }
 
 static int
-surrounding_pos (MSymbol sym)
+surrounding_pos (MSymbol sym, int *pos)
 {
   char *name;
 
   if (sym == Mnil)
     return 0;
   name = MSYMBOL_NAME (sym);
-  if ((name[1] == '-' || name[1] == '+')
-      && name[2] >= '1' && name[2] <= '9')
-    return (name[1] == '-' ? - atoi (name + 2) : atoi (name + 2));
+  if (name[0] == '@'
+      && (name[1] == '-' ? (name[2] >= '1' && name[2] <= '9')
+         : name[1] == '+' ? (name[2] >= '0' && name[2] <= '9')
+         : 0))
+    {
+      *pos = name[1] == '-' ? - atoi (name + 2) : atoi (name + 2);
+      return 1;
+    }
   return 0;
 }
 
 static int
-integer_value (MInputContext *ic, MPlist *arg, MPlist **value, int surrounding)
+integer_value (MInputContext *ic, MPlist *arg, int surrounding)
 {
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
-  int code;
+  int code, pos;
   MText *preedit = ic->preedit;
   int len = mtext_nchars (preedit);
 
-  if (value)
-    *value = NULL;
   if (MPLIST_INTEGER_P (arg))
     return MPLIST_INTEGER (arg);
-  if (surrounding
-      && (surrounding = surrounding_pos (MPLIST_SYMBOL (arg))) != 0)
-    return (surrounding < 0
-           ? get_preceding_char (ic, - surrounding)
-           : get_following_char (ic, surrounding));
-  code = marker_code (MPLIST_SYMBOL (arg));
+
+  code = marker_code (MPLIST_SYMBOL (arg), surrounding);
   if (code < 0)
     {
       MPlist *val = resolve_variable (ic_info, MPLIST_SYMBOL (arg));
 
-      if (value)
-       *value = val;
       return (MPLIST_INTEGER_P (val) ? MPLIST_INTEGER (val) : 0);
     }
   if (code == '@')
     return ic_info->key_head;
-  if (code >= '0' && code <= '9')
-    code -= '0';
+  if ((code == '-' || code == '+'))
+    {
+      char *name = MSYMBOL_NAME (MPLIST_SYMBOL (arg));
+
+      if (name[2])
+       {
+         pos = atoi (name + 1);
+         if (pos == 0 && code == '-')
+           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);
+           }
+         else if (pos >= len)
+           return get_following_char (ic, pos - len);
+       }
+      else
+       pos = ic->cursor_pos + (code == '+' ? 1 : -1);
+    }
+  else if (code >= '0' && code <= '9')
+    pos = code - '0';
   else if (code == '=')
-    code = ic->cursor_pos;
-  else if (code == '-' || code == '[')
-    code = ic->cursor_pos - 1;
-  else if (code == '+' || code == ']')
-    code = ic->cursor_pos + 1;
+    pos = ic->cursor_pos;
+  else if (code == '[')
+    pos = ic->cursor_pos - 1;
+  else if (code == ']')
+    pos = ic->cursor_pos + 1;
   else if (code == '<')
-    code = 0;
+    pos = 0;
   else if (code == '>')
-    code = len;
-  return (code >= 0 && code < len ? mtext_ref_char (preedit, code) : -1);
+    pos = len - 1;
+  return (pos >= 0 && pos < len ? mtext_ref_char (preedit, pos) : -1);
 }
 
 static int
@@ -682,7 +763,7 @@ resolve_expression (MInputContext *ic, MPlist *plist)
   if (MPLIST_INTEGER_P (plist))
     return MPLIST_INTEGER (plist);
   if (MPLIST_SYMBOL_P (plist))
-    return integer_value (ic, plist, NULL, 1);
+    return integer_value (ic, plist, 1);
   if (! MPLIST_PLIST_P (plist))
     return 0;
   plist = MPLIST_PLIST (plist);
@@ -780,6 +861,11 @@ parse_action_list (MPlist *plist, MPlist *macros)
 
          pl = MPLIST_NEXT (pl);
 
+         if (action_name == M_candidates)
+           {
+             /* This is an already regularised action.  */
+             continue;
+           }
          if (action_name == Minsert)
            {
              if (MPLIST_MTEXT_P (pl))
@@ -787,9 +873,16 @@ parse_action_list (MPlist *plist, MPlist *macros)
                  if (mtext_nchars (MPLIST_MTEXT (pl)) == 0)
                    MERROR (MERROR_IM, -1);
                }
+             else if (MPLIST_INTEGER_P (pl))
+               {
+                 int c = MPLIST_INTEGER (pl);
+
+                 if (c < 0 || c > MCHAR_MAX)
+                   MERROR (MERROR_IM, -1);
+               }
              else if (MPLIST_PLIST_P (pl))
                {
-                 MPLIST_DO (pl, pl)
+                 MPLIST_DO (pl, MPLIST_PLIST (pl))
                    {
                      if (MPLIST_PLIST_P (pl))
                        {
@@ -830,8 +923,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 +974,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 +1000,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;
@@ -1034,34 +1128,48 @@ load_branch (MInputMethodInfo *im_info, MPlist *plist, MIMMap *map)
       if (branch_actions)
        M17N_OBJECT_REF (branch_actions);
     }
-  else if (im_info->maps
-          && (plist = (MPlist *) mplist_get (im_info->maps, map_name)))
+  else if (im_info->maps) 
     {
-      MPLIST_DO (plist, plist)
+      plist = (MPlist *) mplist_get (im_info->maps, map_name);
+      if (! plist && im_info->configured_vars)
        {
-         MPlist *keylist, *map_actions;
+         MPlist *p = mplist__assq (im_info->configured_vars, map_name);
 
-         if (! MPLIST_PLIST_P (plist))
-           MERROR (MERROR_IM, -1);
-         keylist = MPLIST_PLIST (plist);
-         map_actions = MPLIST_NEXT (keylist);
-         if (MPLIST_SYMBOL_P (keylist))
+         if (p && MPLIST_PLIST_P (p))
+           {
+             p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p))));
+             if (MPLIST_SYMBOL_P (p))
+               plist = mplist_get (im_info->maps, MPLIST_SYMBOL (p));
+           }
+       }
+      if (plist)
+       {
+         MPLIST_DO (plist, plist)
            {
-             MSymbol command = MPLIST_SYMBOL (keylist);
-             MPlist *pl;
+             MPlist *keylist, *map_actions;
 
-             if (MFAILP (command != Mat_reload))
-               continue;
-             pl = resolve_command (im_info->configured_cmds, command);
-             if (MFAILP (pl))
-               continue;
-             MPLIST_DO (pl, pl)
-               load_translation (map, pl, map_actions, branch_actions,
+             if (! MPLIST_PLIST_P (plist))
+               MERROR (MERROR_IM, -1);
+             keylist = MPLIST_PLIST (plist);
+             map_actions = MPLIST_NEXT (keylist);
+             if (MPLIST_SYMBOL_P (keylist))
+               {
+                 MSymbol command = MPLIST_SYMBOL (keylist);
+                 MPlist *pl;
+
+                 if (MFAILP (command != Mat_reload))
+                   continue;
+                 pl = resolve_command (im_info->configured_cmds, command);
+                 if (MFAILP (pl))
+                   continue;
+                 MPLIST_DO (pl, pl)
+                   load_translation (map, pl, map_actions, branch_actions,
+                                     im_info->macros);
+               }
+             else
+               load_translation (map, keylist, map_actions, branch_actions,
                                  im_info->macros);
            }
-         else
-           load_translation (map, keylist, map_actions, branch_actions,
-                             im_info->macros);
        }
     }
 
@@ -1069,7 +1177,7 @@ load_branch (MInputMethodInfo *im_info, MPlist *plist, MIMMap *map)
 }
 
 /* Load a macro from PLIST into IM_INFO->macros.
-   PLIST has this from:
+   PLIST has this form:
       PLIST ::= ( MACRO-NAME ACTION * )
    IM_INFO->macros is a plist of macro names vs action list.  */
 
@@ -1083,8 +1191,7 @@ load_macros (MInputMethodInfo *im_info, MPlist *plist)
     MERROR (MERROR_IM, -1);
   name = MPLIST_SYMBOL (plist);
   plist = MPLIST_NEXT (plist);
-  if (MPLIST_TAIL_P (plist)
-      || parse_action_list (plist, im_info->macros) < 0)
+  if (MFAILP (! MPLIST_TAIL_P (plist)))
     MERROR (MERROR_IM, -1);
   pl = mplist_get (im_info->macros, name);
   M17N_OBJECT_UNREF (pl);
@@ -1112,9 +1219,11 @@ load_external_module (MInputMethodInfo *im_info, MPlist *plist)
     module = msymbol ((char *) MTEXT_DATA (MPLIST_MTEXT (plist)));
   else if (MPLIST_SYMBOL_P (plist))
     module = MPLIST_SYMBOL (plist);
-  module_file = alloca (strlen (MSYMBOL_NAME (module))
+  module_file = alloca (strlen (M17N_MODULE_DIR) + 1
+                       + strlen (MSYMBOL_NAME (module))
                        + strlen (DLOPEN_SHLIB_EXT) + 1);
-  sprintf (module_file, "%s%s", MSYMBOL_NAME (module), DLOPEN_SHLIB_EXT);
+  sprintf (module_file, "%s/%s%s",
+          M17N_MODULE_DIR, MSYMBOL_NAME (module), DLOPEN_SHLIB_EXT);
 
   handle = dlopen (module_file, RTLD_NOW);
   if (MFAILP (handle))
@@ -1412,14 +1521,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);
@@ -1445,6 +1552,8 @@ update_global_info (void)
     {
       MDatabase *mdb = mdatabase_find (Minput_method, Mt, Mnil, Mglobal);
 
+      if (! mdb)
+       return -1;
       global_info = new_im_info (mdb, Mt, Mnil, Mglobal, im_info_list);
     }
   if (! global_info->mdb
@@ -1514,6 +1623,8 @@ get_im_info (MSymbol language, MSymbol name, MSymbol extra, MSymbol key)
        im_info->cmds = mplist ();
       if (! im_info->vars)
        im_info->vars = mplist ();
+      if (! im_info->states)
+       im_info->states = mplist ();
     }
   if (! im_info->title
       && (key == Mnil || key == Mtitle))
@@ -1534,9 +1645,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 +1656,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 +1688,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 +1777,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 +1784,108 @@ 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 = MPLIST_SYMBOL (plist);
+  MSymbol status;
+  MPlist *description, *keyseq;
+
+  if (global_cmds && (global = mplist__assq (global_cmds, name)))
+    global = MPLIST_NEXT (MPLIST_PLIST (global));  
+
+  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 +1893,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 +1914,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 +1964,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 +1976,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 +2011,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)))
-       {
-         /* GLOBAL ::= ((NAME DESC ...) ...) */
-         global = MPLIST_PLIST (global); /* GLOBAL ::= (NAME DESC ...) */
-         global = MPLIST_NEXT (global);  /* GLOBAL ::= (DESC VALUE ...) */
-       }
-      if (! MPLIST_MTEXT_P (p))
+      if (im_info == global_info)
        {
-         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 +2200,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 +2228,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 +2236,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,20 +2375,29 @@ 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);
-
          }
       }
+  if (im_info->macros)
+    {
+      MPLIST_DO (pl, im_info->macros)
+       parse_action_list (MPLIST_PLIST (pl), im_info->macros);
+    }
+
   im_info->tick = time (NULL);
 }
 
 \f
 
 static int take_action_list (MInputContext *ic, MPlist *action_list);
-static void preedit_commit (MInputContext *ic);
+static void preedit_commit (MInputContext *ic, int need_prefix);
+
+/* Shift to the state of name STATE_NAME.  If STATE_NAME is `t', shift
+   to the previous state (if any).  If STATE_NAME is `nil', shift to
+   the initial state.  */
 
 static void
 shift_state (MInputContext *ic, MSymbol state_name)
@@ -2107,7 +2425,15 @@ shift_state (MInputContext *ic, MSymbol state_name)
        state = (MIMState *) MPLIST_VAL (im_info->states);
     }
 
-  MDEBUG_PRINT1 ("\n  [IM] (shift %s)", MSYMBOL_NAME (state->name));
+  if (MDEBUG_FLAG ())
+    {
+      if (orig_state)
+       MDEBUG_PRINT2 ("\n  [IM] [%s] (shift %s)\n",
+                      MSYMBOL_NAME (orig_state->name),
+                      MSYMBOL_NAME (state->name));
+      else
+       MDEBUG_PRINT1 (" (shift %s)\n", MSYMBOL_NAME (state->name));
+    }
 
   /* Enter the new state.  */
   ic_info->state = state;
@@ -2116,13 +2442,18 @@ shift_state (MInputContext *ic, MSymbol state_name)
   if (state == (MIMState *) MPLIST_VAL (im_info->states)
       && orig_state)
     /* We have shifted to the initial state.  */
-    preedit_commit (ic);
+    preedit_commit (ic, 0);
   mtext_cpy (ic_info->preedit_saved, ic->preedit);
   ic_info->state_pos = ic->cursor_pos;
-  if (state != orig_state)
+  if (state != orig_state || state_name == Mnil)
     {
       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;
 
@@ -2131,12 +2462,7 @@ shift_state (MInputContext *ic, MSymbol state_name)
       else
        ic->status = im_info->title;
       ic->status_changed = 1;
-      if (ic_info->map == ic_info->state->map
-         && ic_info->map->map_actions)
-       {
-         MDEBUG_PRINT (" init-actions:");
-         take_action_list (ic, ic_info->map->map_actions);
-       }
+      ic_info->state_hook = ic_info->map->map_actions;
     }
 }
 
@@ -2175,22 +2501,62 @@ find_candidates_group (MPlist *plist, int index,
   return NULL;
 }
 
+/* Adjust markers for the change of preedit text.
+   If FROM == TO, the change is insertion of INS chars.
+   If FROM < TO and INS == 0, the change is deletion of the range.
+   If FROM < TO and INS > 0, the change is replacement.  */
+
 static void
-preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
+adjust_markers (MInputContext *ic, int from, int to, int ins)
 {
   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
   MPlist *markers;
+
+  if (from == to)
+    {
+      MPLIST_DO (markers, ic_info->markers)
+       if (MPLIST_INTEGER (markers) > from)
+         MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + ins);
+      if (ic->cursor_pos >= from)
+       ic->cursor_pos += ins;
+    }
+  else
+    {
+      MPLIST_DO (markers, ic_info->markers)
+       {
+         if (MPLIST_INTEGER (markers) >= to)
+           MPLIST_VAL (markers)
+             = (void *) (MPLIST_INTEGER (markers) + ins - (to - from));
+         else if (MPLIST_INTEGER (markers) > from)
+           MPLIST_VAL (markers) = (void *) from;
+       }
+      if (ic->cursor_pos >= to)
+       ic->cursor_pos += ins - (to - from);
+      else if (ic->cursor_pos > from)
+       ic->cursor_pos = from;
+    }
+}
+
+
+static void
+preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
+{
   int nchars = mt ? mtext_nchars (mt) : 1;
 
   if (mt)
-    mtext_ins (ic->preedit, pos, mt);
+    {
+      mtext_ins (ic->preedit, pos, mt);
+      MDEBUG_PRINT1 ("(\"%s\")", MTEXT_DATA (mt));
+    }
   else
-    mtext_ins_char (ic->preedit, pos, c, 1);
-  MPLIST_DO (markers, ic_info->markers)
-    if (MPLIST_INTEGER (markers) > pos)
-      MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars);
-  if (ic->cursor_pos >= pos)
-    ic->cursor_pos += nchars;
+    {
+      mtext_ins_char (ic->preedit, pos, c, 1);
+      if (c < 0x7F)
+       MDEBUG_PRINT1 ("('%c')", c);
+      else
+       MDEBUG_PRINT1 ("(U+%04X)", c);
+    }
+  adjust_markers (ic, pos, pos, nchars);
   ic->preedit_changed = 1;
 }
 
@@ -2198,27 +2564,34 @@ preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
 static void
 preedit_delete (MInputContext *ic, int from, int to)
 {
-  MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
-  MPlist *markers;
+  mtext_del (ic->preedit, from, to);
+  adjust_markers (ic, from, to, 0);
+  ic->preedit_changed = 1;
+}
+
+static void
+preedit_replace (MInputContext *ic, int from, int to, MText *mt, int c)
+{
+  int ins;
 
   mtext_del (ic->preedit, from, to);
-  MPLIST_DO (markers, ic_info->markers)
-    {
-      if (MPLIST_INTEGER (markers) > to)
-       MPLIST_VAL (markers)
-         = (void *) (MPLIST_INTEGER (markers) - (to - from));
-      else if (MPLIST_INTEGER (markers) > from);
-       MPLIST_VAL (markers) = (void *) from;
-    }
-  if (ic->cursor_pos >= to)
-    ic->cursor_pos -= to - from;
-  else if (ic->cursor_pos > from)
-    ic->cursor_pos = from;
+  if (mt)
+    {
+      mtext_ins (ic->preedit, from, mt);
+      ins = mtext_nchars (mt);
+    }
+  else
+    {
+      mtext_ins_char (ic->preedit, from, c, 1);
+      ins = 1;
+    }
+  adjust_markers (ic, from, to, ins);
   ic->preedit_changed = 1;
 }
 
+
 static void
-preedit_commit (MInputContext *ic)
+preedit_commit (MInputContext *ic, int need_prefix)
 {
   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
   int preedit_len = mtext_nchars (ic->preedit);
@@ -2232,27 +2605,33 @@ preedit_commit (MInputContext *ic)
       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
                             Mcandidate_index, NULL, 0);
       mtext_cat (ic->produced, ic->preedit);
-      if ((mdebug__flag & mdebug_mask)
-         && mtext_nchars (ic->preedit) > 0)
+      if (MDEBUG_FLAG ())
        {
          int i;
 
-         MDEBUG_PRINT (" (produced");
+         if (need_prefix)
+           MDEBUG_PRINT1 ("\n  [IM] [%s]",
+                          MSYMBOL_NAME (ic_info->state->name));
+         MDEBUG_PRINT (" (commit");
          for (i = 0; i < mtext_nchars (ic->preedit); i++)
            MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->preedit, i));
          MDEBUG_PRINT (")");
        }
+
       mtext_reset (ic->preedit);
       mtext_reset (ic_info->preedit_saved);
       MPLIST_DO (p, ic_info->markers)
        MPLIST_VAL (p) = 0;
       ic->cursor_pos = ic_info->state_pos = 0;
       ic->preedit_changed = 1;
+      ic_info->commit_key_head = ic_info->key_head;
     }
   if (ic->candidate_list)
     {
       M17N_OBJECT_UNREF (ic->candidate_list);
       ic->candidate_list = NULL;
+      ic->candidate_index = 0;
+      ic->candidate_from = ic->candidate_to = 0;
       ic->candidates_changed = MINPUT_CANDIDATES_LIST_CHANGED;
       if (ic->candidate_show)
        {
@@ -2260,16 +2639,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 +2688,11 @@ update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
   int ingroup_index = idx - start;
   MText *mt;
 
-  preedit_delete (ic, from, to);
+  candidate_list = mplist_copy (candidate_list);
   if (MPLIST_MTEXT_P (group))
     {
       mt = MPLIST_MTEXT (group);
-      preedit_insert (ic, from, NULL, mtext_ref_char (mt, ingroup_index));
+      preedit_replace (ic, from, to, NULL, mtext_ref_char (mt, ingroup_index));
       to = from + 1;
     }
   else
@@ -2328,10 +2703,11 @@ update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
           i++, plist = MPLIST_NEXT (plist));
       mt = MPLIST_MTEXT (plist);
-      preedit_insert (ic, from, mt, 0);
+      preedit_replace (ic, from, to, mt, 0);
       to = from + mtext_nchars (mt);
     }
   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
+  M17N_OBJECT_UNREF (candidate_list);
   mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
   ic->cursor_pos = to;
 }
@@ -2350,6 +2726,8 @@ get_select_charset (MInputContextInfo * ic_info)
   return MCHARSET (sym);
 }
 
+/* The returned plist must be UNREFed.  */
+
 static MPlist *
 adjust_candidates (MPlist *plist, MCharset *charset)
 {
@@ -2452,6 +2830,8 @@ adjust_candidates (MPlist *plist, MCharset *charset)
   return plist;
 }
 
+/* The returned Plist must be UNREFed.  */
+
 static MPlist *
 get_candidate_list (MInputContextInfo *ic_info, MPlist *args)
 {
@@ -2464,92 +2844,90 @@ get_candidate_list (MInputContextInfo *ic_info, MPlist *args)
   column = MPLIST_INTEGER (plist);
 
   plist = MPLIST_PLIST (args);
+  if (! plist)
+    return NULL;
   if (charset)
     {
-      if (! (plist = adjust_candidates (plist, charset)))
+      plist = adjust_candidates (plist, charset);
+      if (! plist)
        return NULL;
     }
   else
     M17N_OBJECT_REF (plist);
 
-  if (column > 0)
+  if (column == 0)
+    return plist;
+
+  if (MPLIST_MTEXT_P (plist))
     {
-      if (MPLIST_MTEXT_P (plist))
-       {
-         MText *mt = MPLIST_MTEXT (plist);
-         MPlist *next = MPLIST_NEXT (plist);
+      MText *mt = MPLIST_MTEXT (plist);
+      MPlist *next = MPLIST_NEXT (plist);
 
-         if (MPLIST_TAIL_P (next))
-           M17N_OBJECT_REF (mt);
-         else
+      if (MPLIST_TAIL_P (next))
+       M17N_OBJECT_REF (mt);
+      else
+       {
+         mt = mtext_dup (mt);
+         while (! MPLIST_TAIL_P (next))
            {
-             mt = mtext_dup (mt);
-             while (! MPLIST_TAIL_P (next))
-               {
-                 mt = mtext_cat (mt, MPLIST_MTEXT (next));
-                 next = MPLIST_NEXT (next);
-               }
+             mt = mtext_cat (mt, MPLIST_MTEXT (next));
+             next = MPLIST_NEXT (next);
            }
-         M17N_OBJECT_UNREF (plist);
-         plist = mplist ();
-         len = mtext_nchars (mt);
-         if (len <= column)
-           mplist_add (plist, Mtext, mt);
-         else
+       }
+      M17N_OBJECT_UNREF (plist);
+      plist = mplist ();
+      len = mtext_nchars (mt);
+      if (len <= column)
+       mplist_add (plist, Mtext, mt);
+      else
+       {
+         for (i = 0; i < len; i += column)
            {
-             for (i = 0; i < len; i += column)
-               {
-                 int to = (i + column < len ? i + column : len);
-                 MText *sub = mtext_copy (mtext (), 0, mt, i, to);
+             int to = (i + column < len ? i + column : len);
+             MText *sub = mtext_copy (mtext (), 0, mt, i, to);
                                                       
-                 mplist_add (plist, Mtext, sub);
-                 M17N_OBJECT_UNREF (sub);
-               }
+             mplist_add (plist, Mtext, sub);
+             M17N_OBJECT_UNREF (sub);
            }
-         M17N_OBJECT_UNREF (mt);
        }
-      else             /* MPLIST_PLIST_P (plist) */
+      M17N_OBJECT_UNREF (mt);
+    }
+  else if (MPLIST_PLIST_P (plist))
+    {
+      MPlist *tail = plist;
+      MPlist *new = mplist ();
+      MPlist *this = mplist ();
+      int count = 0;
+
+      MPLIST_DO (tail, tail)
        {
-         MPlist *pl = MPLIST_PLIST (plist), *p;
-         MPlist *next = MPLIST_NEXT (plist);
-         int j;
+         MPlist *p = MPLIST_PLIST (tail);
 
-         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 (p, p)
            {
-             MPlist *p0 = pl;
+             MText *mt = MPLIST_MTEXT (p);
 
-             for (i = 0; i < len; i += column)
+             if (count == column)
                {
-                 p = mplist ();
-                 mplist_add (plist, Mplist, p);
-                 M17N_OBJECT_UNREF (p);
-                 for (j = 0; j < column && i + j < len; j++)
-                   {
-                     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 +2987,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
@@ -2649,10 +3027,16 @@ take_action_list (MInputContext *ic, MPlist *action_list)
       else if (name == M_candidates)
        {
          MPlist *plist = get_candidate_list (ic_info, args);
+         MPlist *pl;
          int len;
 
          if (! plist)
            continue;
+         if (MPLIST_PLIST_P (plist) && MPLIST_TAIL_P (plist))
+           {
+             M17N_OBJECT_UNREF (plist);
+             continue;
+           }
          if (MPLIST_MTEXT_P (plist))
            {
              preedit_insert (ic, ic->cursor_pos, NULL,
@@ -2666,13 +3050,15 @@ take_action_list (MInputContext *ic, MPlist *action_list)
              preedit_insert (ic, ic->cursor_pos, mt, 0);
              len = mtext_nchars (mt);
            }
+         pl = mplist_copy (plist);
+         M17N_OBJECT_UNREF (plist);
          mtext_put_prop (ic->preedit,
                          ic->cursor_pos - len, ic->cursor_pos,
-                         Mcandidate_list, plist);
+                         Mcandidate_list, pl);
+         M17N_OBJECT_UNREF (pl);
          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 +3066,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 +3142,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;
@@ -2758,9 +3155,19 @@ take_action_list (MInputContext *ic, MPlist *action_list)
          int to;
 
          if (MPLIST_SYMBOL_P (args)
-             && (pos = surrounding_pos (MPLIST_SYMBOL (args))) != 0)
+             && surrounding_pos (MPLIST_SYMBOL (args), &pos))
            {
-             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 +3179,13 @@ 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);
+             pos = to - ic->cursor_pos;
            }
+         MDEBUG_PRINT1 ("(%d)", 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 +3205,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 +3279,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 +3302,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 +3315,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),
@@ -2911,29 +3341,40 @@ take_action_list (MInputContext *ic, MPlist *action_list)
        {
          int intarg = (MPLIST_TAIL_P (args)
                        ? ic_info->used - 2
-                       : integer_value (ic, args, NULL, 0));
+                       : integer_value (ic, args, 0));
 
          mtext_reset (ic->preedit);
          mtext_reset (ic_info->preedit_saved);
+         mtext_reset (ic->produced);
+         M17N_OBJECT_UNREF (ic_info->vars);
+         ic_info->vars = mplist_copy (ic_info->vars_saved);
          ic->cursor_pos = ic_info->state_pos = 0;
-         ic_info->state_key_head = ic_info->key_head = 0;
+         ic_info->state_key_head = ic_info->key_head
+           = ic_info->commit_key_head = 0;
 
+         shift_state (ic, Mnil);
          if (intarg < 0)
-           ic_info->used += intarg;
+           {
+             if (MPLIST_TAIL_P (args))
+               {
+                 ic_info->used = 0;
+                 return -1;
+               }
+             ic_info->used += intarg;
+           }
          else
            ic_info->used = intarg;
-         shift_state (ic, Mnil);
          break;
        }
       else if (name == Mset || name == Madd || name == Msub
               || name == Mmul || name == Mdiv)
        {
          MSymbol sym = MPLIST_SYMBOL (args);
+         MPlist *value = resolve_variable (ic_info, sym);
          int val1, val2;
-         MPlist *value;
          char *op;
 
-         val1 = integer_value (ic, args, &value, 0);
+         val1 = MPLIST_INTEGER (value);
          args = MPLIST_NEXT (args);
          val2 = resolve_expression (ic, args);
          if (name == Mset)
@@ -2948,8 +3389,7 @@ take_action_list (MInputContext *ic, MPlist *action_list)
            val1 /= val2, op = "/=";
          MDEBUG_PRINT4 ("(%s %s 0x%X(%d))",
                         MSYMBOL_NAME (sym), op, val1, val1);
-         if (value)
-           mplist_set (value, Minteger, (void *) val1);
+         mplist_set (value, Minteger, (void *) val1);
        }
       else if (name == Mequal || name == Mless || name == Mgreater
               || name == Mless_equal || name == Mgreater_equal)
@@ -3010,11 +3450,11 @@ take_action_list (MInputContext *ic, MPlist *action_list)
        }
       else if (name == Mcommit)
        {
-         preedit_commit (ic);
+         preedit_commit (ic, 0);
        }
       else if (name == Munhandle)
        {
-         preedit_commit (ic);
+         preedit_commit (ic, 0);
          return -1;
        }
       else
@@ -3031,7 +3471,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)))
@@ -3070,8 +3514,16 @@ handle_key (MInputContext *ic)
   MSymbol alias = Mnil;
   int i;
 
-  MDEBUG_PRINT2 ("  [IM] handle `%s' in state %s", 
-                msymbol_name (key), MSYMBOL_NAME (ic_info->state->name));
+  if (ic_info->state_hook)
+    {
+      MDEBUG_PRINT1 ("  [IM] [%s] init-actions:",
+                    MSYMBOL_NAME (ic_info->state->name));
+      take_action_list (ic, ic_info->state_hook);
+      ic_info->state_hook = NULL;
+    }
+
+  MDEBUG_PRINT2 ("  [IM] [%s] handle `%s'", 
+                MSYMBOL_NAME (ic_info->state->name), msymbol_name (key));
 
   if (map->submaps)
     {
@@ -3138,47 +3590,44 @@ 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");
+             ic_info->state_hook = map->map_actions;
+             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 +3651,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 +3676,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 +3705,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 +3717,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 +3739,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)
     {
@@ -3306,8 +3763,20 @@ re_init_ic (MInputContext *ic, int reload)
   fini_ic_info (ic);
   if (reload)
     reload_im_info (im_info);
+  if (! im_info->states)
+    {
+      struct MIMState *state;
+
+      M17N_OBJECT (state, free_state, MERROR_IM);
+      state->name = msymbol ("init");
+      state->title = mtext__from_data ("ERROR!", 6, MTEXT_FORMAT_US_ASCII, 0);
+      MSTRUCT_CALLOC (state->map, MERROR_IM);
+      im_info->states = mplist ();
+      mplist_add (im_info->states, state->name, state);
+    }
   init_ic_info (ic);
   shift_state (ic, Mnil);
+
   ic->status_changed = status_changed;
   ic->preedit_changed = preedit_changed;
   ic->cursor_pos_changed = cursor_pos_changed;
@@ -3326,7 +3795,7 @@ open_im (MInputMethod *im)
 {
   MInputMethodInfo *im_info = get_im_info (im->language, im->name, Mnil, Mnil);
 
-  if (! im_info)
+  if (! im_info || ! im_info->states)
     MERROR (MERROR_IM, -1);
   im->info = im_info;
 
@@ -3430,6 +3899,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 +3912,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,17 +3933,37 @@ filter (MInputContext *ic, MSymbol key, void *arg)
 
   /* If the current map is the root of the initial state, we should
      produce any preedit text in ic->produced.  */
-  if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map
-      && mtext_nchars (ic->preedit) > 0)
-    shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
+  if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
+    preedit_commit (ic, 1);
 
   if (mtext_nchars (ic->produced) > 0)
     {
-      MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
+      if (MDEBUG_FLAG ())
+       {
+         MDEBUG_PRINT1 ("\n  [IM] [%s] (produced",
+                        MSYMBOL_NAME (ic_info->state->name));
+         for (i = 0; i < mtext_nchars (ic->produced); i++)
+           MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->produced, i));
+         MDEBUG_PRINT (")");
+       }
 
-      if (lang != Mnil)
-       mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
-                       Mlanguage, ic->im->language);
+      mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
+                     Mlanguage, ic->im->language);
+    }
+  if (ic_info->commit_key_head > 0)
+    {
+      memmove (ic_info->keys, ic_info->keys + ic_info->commit_key_head,
+              sizeof (int) * (ic_info->used - ic_info->commit_key_head));
+      ic_info->used -= ic_info->commit_key_head;
+      ic_info->key_head -= ic_info->commit_key_head;
+      ic_info->state_key_head -= ic_info->commit_key_head;
+      ic_info->commit_key_head = 0;
+    }
+  if (ic_info->key_unhandled)
+    {
+      ic_info->used = 0;
+      ic_info->key_head = ic_info->state_key_head
+       = ic_info->commit_key_head = 0;
     }
 
   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
@@ -3517,24 +4011,24 @@ dump_im_map (MPlist *map_list, int indent)
   memset (prefix, 32, indent);
   prefix[indent] = '\0';
 
-  fprintf (stderr, "(\"%s\" ", msymbol_name (key));
+  fprintf (mdebug__output, "(\"%s\" ", msymbol_name (key));
   if (map->map_actions)
     mdebug_dump_plist (map->map_actions, indent + 2);
   if (map->submaps)
     {
       MPLIST_DO (map_list, map->submaps)
        {
-         fprintf (stderr, "\n%s  ", prefix);
+         fprintf (mdebug__output, "\n%s  ", prefix);
          dump_im_map (map_list, indent + 2);
        }
     }
   if (map->branch_actions)
     {
-      fprintf (stderr, "\n%s  (branch\n%s    ", prefix, prefix);
+      fprintf (mdebug__output, "\n%s  (branch\n%s    ", prefix, prefix);
       mdebug_dump_plist (map->branch_actions, indent + 4);
-      fprintf (stderr, ")");      
+      fprintf (mdebug__output, ")");      
     }
-  fprintf (stderr, ")");
+  fprintf (mdebug__output, ")");
 }
 
 
@@ -3548,16 +4042,16 @@ dump_im_state (MIMState *state, int indent)
   memset (prefix, 32, indent);
   prefix[indent] = '\0';
 
-  fprintf (stderr, "(%s", msymbol_name (state->name));
+  fprintf (mdebug__output, "(%s", msymbol_name (state->name));
   if (state->map->submaps)
     {
       MPLIST_DO (map_list, state->map->submaps)
        {
-         fprintf (stderr, "\n%s  ", prefix);
+         fprintf (mdebug__output, "\n%s  ", prefix);
          dump_im_map (map_list, indent + 2);
        }
     }
-  fprintf (stderr, ")");
+  fprintf (mdebug__output, ")");
 }
 
 \f
@@ -3584,6 +4078,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 +4089,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 +4115,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)
 {
@@ -3653,52 +4135,84 @@ minput__char_to_key (int c)
 /*=*/
 
 /***en
-    @name Variables: Predefined symbols for callback commands.
+    @brief Symbol whose name is "input-method".
+ */
+/***ja
+    @brief "input-method" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë.
+ */
+MSymbol Minput_method;
 
+/***en
+    @name Variables: Predefined symbols for callback commands.  */
+/***ja
+    @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.  */
+/*** @{ */ 
+/***en
     These are the predefined symbols that are used as the @c COMMAND
     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
+    @b Minput_get_surrounding_text: When a callback function assigned for
     this command is called, the first element of #MInputContext::plist
     has key #Minteger and the value specifies which portion of the
     surrounding text should be retrieved.  If the value is positive,
     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
     #MInputContext::plist.
 
-    Minput_delete_surrounding_text: When a callback function assigned
+    @b Minput_delete_surrounding_text: When a callback function assigned
     for this command is called, the first element of
     #MInputContext::plist has key #Minteger and the value specifies
     which portion of the surrounding text should be deleted in the
     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 ¤òÊѤ¨¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */ 
 MSymbol Minput_preedit_start;
 MSymbol Minput_preedit_done;
 MSymbol Minput_preedit_draw;
@@ -3722,6 +4236,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 +4251,25 @@ MSymbol Minput_focus_move;
 /*** @} */
 
 /*=*/
+/***en
+    @name Variables: Predefined symbols used in input method information.  */
+/***ja
+    @name ÊÑ¿ô: ÆþÎϥ᥽¥Ã¥É¾ðÊóÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.  */
+/*** @{ */ 
+/*=*/
+/***en
+    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
+    ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤äÊÑ¿ô¤Î¾õÂÖ¤òɽ¤·¡¢minput_get_command () ¤È
+    minput_get_variable () ¤ÎÌá¤êÃͤȤ·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë¡£  */
+MSymbol Minherited;
+MSymbol Mcustomized;
+MSymbol Mconfigured;
+/*** @} */ 
+
+/*=*/
 
 /***en
     @brief The default driver for internal input methods.
@@ -3755,7 +4292,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 ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
 
@@ -3796,11 +4332,25 @@ MInputDriver minput_default_driver;
 
 MInputDriver *minput_driver;
 
+/*=*/
+/***
+    The variable #Minput_driver is a symbol for a foreign input method.
+    See @ref foreign-input-method "foreign input method" for the detail.  */
 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 +4372,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 ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
 
@@ -3857,7 +4406,11 @@ minput_open_im (MSymbol language, MSymbol name, void *arg)
   MDEBUG_PRINT2 ("  [IM] opening (%s %s) ... ",
                 msymbol_name (language), msymbol_name (name));
   if (language)
-    driver = minput_driver;
+    {
+      if (name == Mnil)
+       MERROR (MERROR_IM, NULL);
+      driver = minput_driver;
+    }
   else
     {
       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
@@ -3911,8 +4464,8 @@ minput_close_im (MInputMethod *im)
 
     The minput_create_ic () function creates an input context object
     associated with input method $IM, and calls callback functions
-    corresponding to #Minput_preedit_start, #Minput_status_start, and
-    #Minput_status_draw in this order.
+    corresponding to @b Minput_preedit_start, @b Minput_status_start, and
+    @b Minput_status_draw in this order.
 
     @return
     If an input context is successfully created, minput_create_ic ()
@@ -3923,7 +4476,7 @@ minput_close_im (MInputMethod *im)
 
     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM
     ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢
-    #Minput_preedit_start, #Minput_status_start, #Minput_status_draw
+    @b Minput_preedit_start, @b Minput_status_start, @b Minput_status_draw
     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
 
     @return
@@ -3959,9 +4512,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");
@@ -3975,8 +4528,8 @@ minput_create_ic (MInputMethod *im, void *arg)
 
     The minput_destroy_ic () function destroys the input context $IC,
     which must have been created by minput_create_ic ().  It calls
-    callback functions corresponding to #Minput_preedit_done,
-    #Minput_status_done, and #Minput_candidates_done in this order.  */
+    callback functions corresponding to @b Minput_preedit_done,
+    @b Minput_status_done, and @b Minput_candidates_done in this order.  */
 
 /***ja
     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë.
@@ -3984,7 +4537,7 @@ minput_create_ic (MInputMethod *im, void *arg)
     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£
     ¤³¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () 
     ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï 
-    #Minput_preedit_done, #Minput_status_done, #Minput_candidates_done 
+    @b Minput_preedit_done, @b Minput_status_done, @b Minput_candidates_done 
     ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
   */
 
@@ -3995,9 +4548,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);
@@ -4014,8 +4567,8 @@ minput_destroy_ic (MInputContext *ic)
 
     The minput_filter () function filters input key $KEY according to
     input context $IC, and calls callback functions corresponding to
-    #Minput_preedit_draw, #Minput_status_draw, and
-    #Minput_candidates_draw if the preedit text, the status, and the
+    @b Minput_preedit_draw, @b Minput_status_draw, and
+    @b Minput_candidates_draw if the preedit text, the status, and the
     current candidate are changed respectively.
 
     To make the input method commit the current preedit text (if any)
@@ -4023,14 +4576,14 @@ minput_destroy_ic (MInputContext *ic)
     $KEY.
 
     To inform the input method about the focus-out event, call this
-    function with #Minput_focus_out as $KEY.
+    function with @b Minput_focus_out as $KEY.
 
     To inform the input method about the focus-in event, call this
-    function with #Minput_focus_in as $KEY.
+    function with @b Minput_focus_in as $KEY.
 
     To inform the input method about the focus-move event (i.e. input
     spot change within the same input context), call this function
-    with #Minput_focus_move as $KEY.
+    with @b Minput_focus_move as $KEY.
 
     @return
     If $KEY is filtered out, this function returns 1.  In that case,
@@ -4043,8 +4596,8 @@ minput_destroy_ic (MInputContext *ic)
 
     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC 
     ¤Ë±þ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½¤·¤¿»þÅÀ¤Ç¡¢¤½¤ì¤¾¤ì
-    #Minput_preedit_draw, #Minput_status_draw,
-    #Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
+    @b Minput_preedit_draw, @b Minput_status_draw,
+    @b Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
 
     @return 
     $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£
@@ -4063,16 +4616,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 +4732,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 +4752,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;
 }
 
@@ -4205,27 +4762,27 @@ minput_toggle (MInputContext *ic)
     @brief Reset an input context.
 
     The minput_reset_ic () function resets input context $IC by
-    calling a callback function corresponding to #Minput_reset.  It
+    calling a callback function corresponding to @b Minput_reset.  It
     resets the status of $IC to its initial one.  As the
     current preedit text is deleted without commitment, if necessary,
-    call minput_filter () with the arg @r key #Mnil to force the input
+    call minput_filter () with the arg @b key #Mnil to force the input
     method to commit the preedit in advance.  */
 
 /***ja
     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë.
 
-    ´Ø¿ô minput_reset_ic () ¤Ï #Minput_reset ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô
+    ´Ø¿ô minput_reset_ic () ¤Ï @b Minput_reset ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô
     ¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¥ê¥»¥Ã¥È¤È¤Ï¡¢
     ¼ÂºÝ¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤ò½é´ü¾õÂ֤˰ܤ¹¤³¤È¤Ç¤¢¤ë¡£¸½ºßÆþÎÏÃæ¤Î¥Æ¥­¥¹
     ¥È¤Ï¥³¥ß¥Ã¥È¤µ¤ì¤ë¤³¤È¤Ê¤¯ºï½ü¤µ¤ì¤ë¤Î¤Ç¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é
-    ¥à¤Ï¡¢É¬Íפʤé¤Ðͽ¤á minput_filter () ¤ò°ú¿ô @r key #Mnil ¤Ç¸Æ¤ó¤Ç
+    ¥à¤Ï¡¢É¬Íפʤé¤Ðͽ¤á minput_filter () ¤ò°ú¿ô @b key #Mnil ¤Ç¸Æ¤ó¤Ç
     ¶¯À©Åª¤Ë¥×¥ê¥¨¥Ç¥£¥Ã¥È¥Æ¥­¥¹¥È¤ò¥³¥ß¥Ã¥È¤µ¤»¤ë¤³¤È¡£  */
 
 void
 minput_reset_ic (MInputContext *ic)
 {
   if (ic->im->driver.callback_list)
-    minput__callback (ic, Minput_reset);
+    minput_callback (ic, Minput_reset);
 }
 
 /*=*/
@@ -4246,6 +4803,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)
@@ -4309,7 +4881,8 @@ minput_get_title_icon (MSymbol language, MSymbol name)
     ´Ø¿ô minput_get_description () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄê
     ¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤òÀâÌÀ¤¹¤ë M-text ¤òÊÖ¤¹¡£
 
-    @return »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤¬ÀâÌÀ¤¹¤ë¥Æ¥­¥¹¥È¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢
+    @return
+    »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤¬ÀâÌÀ¤¹¤ë¥Æ¥­¥¹¥È¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢
     #MText ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤½¤ì¤ò m17n_object_unref
     () ¤òÍѤ¤¤Æ²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ÆþÎϥ᥽¥Ã¥É¤ËÀâÌÀ¥Æ¥­¥¹¥È¤¬Ìµ¤±
     ¤ì¤Ð@c NULL ¤òÊÖ¤¹¡£ */
@@ -4318,200 +4891,152 @@ 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.
-
-    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.
+    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.
 
-    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.
+    If $LANGUAGE is #Mt and $NAME is #Mnil, this function returns
+    information about a global command.  Otherwise information about a
+    local command is returned.
 
-    As the returned plist is kept in the library, the caller must not
-    modify nor free it.  */
-/***ja
-    @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
+    If $COMMAND is #Mnil, information about all commands is returned.
 
-    ´Ø¿ô minput_get_commands () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
-    ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã
-    ¥É¥³¥Þ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢¤½¤ì¤¾¤ì¤Ë£±¤Ä°Ê¾å¤Î¼ÂºÝ¤Î
-    ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¤â¤Î¤ò»Ø¤¹¡£
+    The return value is a @e well-formed plist (@ref m17nPlist) of this
+    format:
+@verbatim
+  ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
+@endverbatim
+    @c NAME is a symbol representing the command name.
 
-    ¥³¥Þ¥ó¥É¤Ë¤Ï¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É
-    ¤ÏÊ£¿ô¤ÎÆþÎϥ᥽¥Ã¥É¤Ë¤ª¤¤¤Æ¡¢Æ±¤¸ÌÜŪ¤Ç¡¢¥°¥í¡¼¥Ð¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ
-    ¤ÇÍѤ¤¤é¤ì¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤ÏÆÃÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Î¤ß¡¢¥í¡¼¥«¥ë
-    ¤Ê¥­¡¼³äÅö¤Ç»ÈÍѤµ¤ì¤ë¡£
+    @c DESCRIPTION is an M-text describing the command, or #Mnil if the
+    command has no description.
 
-    ¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ï¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Î¥­¡¼³äÅö¤òÊѹ¹¤¹¤ë¤³¤È¤â¤Ç
-    ¤­¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥ÉÍѤΥ°¥í¡¼¥Ð¥ë¥­¡¼³ä¤êÅö¤Æ¤Ï¡¢»ÈÍѤ¹¤ëÆþÎÏ
-    ¥á¥½¥Ã¥É¤Ë¤ª¤¤¤Æ¤½¤Î¥³¥Þ¥ó¥ÉÍÑ¤Î¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤¬Â¸ºß¤·¤Ê¤¤¾ì¹ç
-    ¤Ë¤Î¤ßÍ­¸ú¤Ç¤¢¤ë¡£
+    @c STATUS is a symbol representing how the key assignment is decided.
+    The value is #Mnil (the default key assignment), @b Mcustomized (the
+    key assignment is customized by per-user customization file), or
+    @b Mconfigured (the key assignment is set by the call of
+    minput_config_command ()).  For a local command only, it may also
+    be @b Minherited (the key assignment is inherited from the
+    corresponding global command).
 
-    $NAME ¤¬ #Mnil ¤Ç¤¢¤ì¤Ð¡¢¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤³¤Î
-    ¾ì¹ç¡¢$LANGUAGE ¤Ï̵»ë¤µ¤ì¤ë¡£
+    @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).
 
-    $NAME ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþ
-    Îϥ᥽¥Ã¥É¤ËÃÖ¤±¤ë¥í¡¼¥«¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ¤ò»ý¤Ä¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó
-    ¤òÊÖ¤¹¡£
+    If $COMMAND is not #Mnil, the first element of the returned plist
+    contains the information about $COMMAND.
 
     @return
-    ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï @c NULL ¤òÊÖ¤¹¡£
-
-    ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹¥È¤Î³ÆÍ×ÁǤÎ
-    ¥­¡¼¤Ï¸Ä¡¹¤Î¥³¥Þ¥ó¥É¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢Ãͤϲ¼µ­¤Î COMMAND-INFO
-    ¤Î·Á¼°¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ë¡£
 
-    COMMAND-INFO ¤ÎÂè°ìÍ×ÁǤΥ­¡¼¤Ï #Mtext ¤Þ¤¿¤Ï #Msymbol ¤Ç¤¢¤ë¡£¥­¡¼
-    ¤¬ #Mtext ¤Ê¤é¡¢ÃͤϤ½¤Î¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£¥­¡¼¤¬
-    #Msymbol ¤Ê¤éÃͤϠ#Mnil ¤Ç¤¢¤ê¡¢¤³¤Î¥³¥Þ¥ó¥É¤ÏÀâÌÀ¥Æ¥­¥¹¥È¤ò»ý¤¿¤Ê
-    ¤¤¤³¤È¤Ë¤Ê¤ë¡£
-
-    ¤½¤ì°Ê³°¤ÎÍ×ÁǤ¬Ìµ¤±¤ì¤Ð¡¢¤³¤Î¥³¥Þ¥ó¥É¤ËÂФ·¤Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä
-    ¤êÅö¤Æ¤é¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢»Ä¤ê¤Î³ÆÍ×ÁǤϥ­
-    ¡¼¤È¤·¤Æ#Mplist ¤ò¡¢ÃͤȤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò»ý¤Ä¡£¤³¤Î¥×¥í¥Ñ¥Æ¥£
-    ¥ê¥¹¥È¤Î¥­¡¼¤Ï #Msymbol ¤Ç¤¢¤ê¡¢Ãͤϸ½ºß¤½¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì
-    ¤Æ¤¤¤ëÆþÎÏ¥­¡¼¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
+    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 ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
 
-MPlist *
-minput_get_commands (MSymbol language, MSymbol name)
-{
-  MInputMethodInfo *im_info;
-  MPlist *cmds;
+    ´Ø¿ô minput_get_command () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎÏ
+    ¥á¥½¥Ã¥É¤Î¥³¥Þ¥ó¥É $COMMAND ¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ
+    ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢£±¤Ä°Ê¾å¤Î¼ÂºÝ¤ÎÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨
+    ¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤ë¡£
 
-  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 ();
+    $LANGUAGE ¤¬ #Mt ¤Ç $NAME ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤³¤Î´Ø¿ô¤Ï¥°¥í¡¼¥Ð¥ë¥³
+    ¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¤â
+    ¤Î¤òÊÖ¤¹¡£
 
-      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;
-}
+    $COMMAND ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£
 
-/***en
-    @brief Assign a key sequence to an input method command (obsolete).
+    Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (@ref m17nPlist) ¤Ç¤¢¤ë¡£
 
-    This function is obsolete.  Use minput_config_command () instead.
+@verbatim
+  ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
+@endverbatim
+    @c 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.
+    @c DESCRIPTION ¤Ï¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë
+    ¤Ï #Mnil ¤Ç¤¢¤ë¡£
 
-    Each element of $KEYSEQ must have the key $Msymbol and the value
-    must be a symbol representing an input key.
+    @c STATUS ¤Ï¥­¡¼³ä¤êÅö¤Æ¤¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë
+    ¤Ç¤¢¤ê¡¢¤½¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤Î³ä¤êÅö¤Æ¡Ë, @b Mcustomized ¡Ê¥æ¡¼
+    ¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿³ä¤êÅö¤Æ¡Ë,
+    @b Mconfigured ¡Êminput_config_command ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ë
+    ³ä¤êÅö¤Æ¡Ë¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Î¾ì¹ç¤Ë¤Ï¡¢
+    @b Minherited ¡ÊÂбþ¤¹¤ë¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤«¤é¤Î·Ñ¾µ¤Ë¤è¤ë³ä¤êÅö¤Æ¡Ë
+    ¤Ç¤â¤è¤¤¡£
 
-    $KEYSEQ may be @c NULL, in which case, all assignments are deleted
-    globally or locally.
+    @c KEYSEQ ¤Ï£±¤Ä°Ê¾å¤Î¥·¥ó¥Ü¥ë¤«¤é¤Ê¤ë plist ¤Ç¤¢¤ê¡¢³Æ¥·¥ó¥Ü¥ë¤Ï¥³¥Þ
+    ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òɽ¤¹¡£KEYSEQ ¤¬Ìµ¤¤¾ì¹ç¤Ï¡¢
+    ¤½¤Î¥³¥Þ¥ó¥É¤Ï¸½¾õ¤Ç»ÈÍÑÉÔǽ¤Ç¤¢¤ë¡£¡Ê¤¹¤Ê¤ï¤Á¥³¥Þ¥ó¥É¤ÎÆ°ºî¤òµ¯
+    Æ°¤Ç¤­¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Ìµ¤¤¡£¡Ë
 
-    This assignment gets effective in a newly opened input method.
+    $COMMAND ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÖ¤µ¤ì¤ë plist ¤ÎºÇ½é¤ÎÍ×ÁǤϡ¢
+    $COMMAND ¤Ë´Ø¤¹¤ë¾ðÊó¤ò´Þ¤à¡£
 
     @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 ¤Ç¤â¤è¤¤¡£¤³¤Î¾ì¹ç¡¢¥°¥í¡¼¥Ð¥ë¤â¤·¤¯¤Ï¥í¡¼¥«¥ë¤Ê
-    ¤¹¤Ù¤Æ¤Î³ä¤êÅö¤Æ¤¬¾Ãµî¤µ¤ì¤ë¡£
 
-    ¤³¤Î³ä¤êÅö¤Æ¤Ï¡¢³ä¤êÅö¤Æ°Ê¹ß¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­
-    ¸ú¤Ë¤Ê¤ë¡£
+    µá¤á¤é¤ì¤¿¾ðÊ󤬸«¤Ä¤«¤ì¤Ð¡¢¶õ¤Ç¤Ê¤¤ plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹
+    ¥È¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð¦¤¬Êѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë
+    ¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
 
-    @return ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
-    #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
+    ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤¹¤Ê¤ï¤Á»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ä¥³¥Þ¥ó¥É¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð
+    @c NULL ¤òÊÖ¤¹¡£  */
 
-int
-minput_assign_command_keys (MSymbol language, MSymbol name,
-                           MSymbol command, MPlist *keyseq)
+#if EXAMPLE_CODE
+MText *
+get_im_command_description (MSymbol language, MSymbol name, MSymbol command)
 {
-  int ret;
-
-  MINPUT__INIT ();
-
-  if (command == Mnil)
-    MERROR (MERROR_IM, -1);
-  if (keyseq)
-    {
-      MPlist *plist;
+  /* 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  (! 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;
+  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_command (MSymbol language, MSymbol name, MSymbol command)
@@ -4521,91 +5046,153 @@ minput_get_command (MSymbol language, MSymbol name, MSymbol command)
   MINPUT__INIT ();
 
   im_info = get_im_info (language, name, Mnil, Mcommand);
-  if (! im_info || ! im_info->configured_cmds)
+  if (! im_info
+      || ! im_info->configured_cmds
+      || MPLIST_TAIL_P (im_info->configured_cmds))
     return NULL;
   if (command == Mnil)
     return im_info->configured_cmds;
   return mplist__assq (im_info->configured_cmds, command);
 }
 
-#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)
-{
-  MPlist *cmd = minput_get_command (langauge, name, command);
-  MPlist *plist;
-
-  if (! cmds)
-    return NULL;
-  plist = mplist_value (cmds); /* (NAME DESCRIPTION KEY-SEQ ...) */
-  plist = mplist_next (plist); /* (DESCRIPTION KEY-SEQ ...) */
-  return (MText *) mplist_value (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.
+    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.
+
+    If $KEYSEQLIST is a non-empty plist, it must be a list of key
+    sequences, and each key sequence must be a plist of symbols.
 
-    If $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 $KEYSEQLIST is an empty plist, any configuration and
+    customization of the command are cancelled, and default key
+    sequences become effective.
 
-    If $KEYSEQ is an empty plist, the command become unusable.
+    If $KEYSEQLIST is NULL, the configuration of the command is
+    canceled, and the original key sequences (what saved in per-user
+    customization file, or the default one) become effective.
 
-    If $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.
+    In the latter two cases, $COMMAND can be #Mnil to make all the
+    commands of the input method the target of the operation.
 
-    If $NAME is #Mnil, this function configure the global key sequence
-    assignments, not that of a specific input method.
+    If $NAME is #Mnil, this function configures the key assignment of a
+    global command, 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
+    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 ().
 
     @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>
+
+    @seealso
+    minput_get_commands (), minput_save_config ().
+*/
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òÀßÄꤹ¤ë.
+
+    ´Ø¿ô minput_config_command () ¤Ï¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È
+    $KEYSEQLIST ¤ò¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤Î
+    ¥³¥Þ¥ó¥É $COMMAND ¤Ë³ä¤êÅö¤Æ¤ë¡£
+
+    $KEYSEQLIST ¤¬¶õ¥ê¥¹¥È¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È¤Ç¤¢¤ê¡¢
+    ³Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥·¥ó¥Ü¥ë¤Î plist ¤Ç¤¢¤ë¡£
+
+    $KEYSEQLIST ¤¬¶õ¤Î plist ¤Ê¤é¤Ð¡¢¤½¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤ä¥«¥¹¥¿¥Þ¥¤¥º¤Ï
+    ¤¹¤Ù¤Æ¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¥Ç¥Õ¥©¥ë¥È¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Í­¸ú¤Ë¤Ê¤ë¡£
 
-    $KEYSEQ is not in a valid form.
+    $KEYSEQLIST ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢¤½¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢
+    ¸µ¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¡Ê¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤µ¤ì¤Æ¤¤
+    ¤ë¤â¤Î¡¢¤¢¤ë¤¤¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¤â¤Î¡Ë¤¬Í­¸ú¤Ë¤Ê¤ë¡£
 
-    $COMMAND is not available for the input method.
+    ¸å¤Î¤Õ¤¿¤Ä¤Î¾ì¹ç¤Ë¤Ï¡¢$COMMAND ¤Ï #Mnil ¤ò¤È¤ë¤³¤È¤¬¤Ç¤­¡¢»ØÄê¤ÎÆþ
+    Îϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤Î¥³¥Þ¥ó¥ÉÀßÄê¤Î¥­¥ã¥ó¥»¥ë¤ò°ÕÌ£¤¹¤ë¡£
 
-    $LANGUAGE and $NAME don't specify an existing input method.
+    $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð
+    ¥ë¤Ê¥³¥Þ¥ó¥É¤Î¥­¡¼³ä¤êÅö¤Æ¤òÀßÄꤹ¤ë¡£
+
+    ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï
+    ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹
+    ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤
+    ¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+
+    @return
+
+    ¤³¤Î´Ø¿ô¤Ï¡¢½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤ò¡¢¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ¤¹¡£¼ºÇԤȤϰʲ¼¤Î¾ì¹ç¤Ç¤¢¤ë¡£
+    <ul>
+    <li>$KEYSEQLIST ¤¬Í­¸ú¤Ê·Á¼°¤Ç¤Ê¤¤¡£
+    <li>$COMMAND ¤¬»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÇÍøÍѤǤ­¤Ê¤¤¡£
+    <li>$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¤Ê¤¤¡£
+    </ul>
 
     @seealso
-    minput_get_commands (), minput_save_config ().  */
+    minput_get_commands (), minput_save_config ().
+*/
+
+#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 = 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
 
 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 +5204,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,256 +5240,194 @@ 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 (@ref 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), @b Mcustomized (the value is
+    customized by per-user customization file), or @b Mconfigured (the
+    value is set by the call of minput_config_variable ()).  For a
+    local variable only, it may also be @b 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:
-
-    @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.
+    If there no @c VALID-VALUE, the variable can have any value as long
+    as the type is the same as @c VALUE.
 
-@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
+    If $VARIABLE is not #Mnil, the first element of the returned plist
+    contains the information about $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) °Ê
-    ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£
-
-@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 ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹¡£
+    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 variable
+    does not exist), @c NULL is returned.  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
 
-    @li name:intvar, ÀâÌÀ:"value is an integer",
-        ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20
+    ´Ø¿ô minput_get_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎÏ
+    ¥á¥½¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤È¤Ï¡¢
+    ÆþÎϥ᥽¥Ã¥É¤Î¿¶Éñ¤òÀ©¸æ¤¹¤ë¤â¤Î¤Ç¤¢¤ë¡£
 
-    @li name:symvar, ÀâÌÀ:"value is a symbol",
-         ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil
+    ÊÑ¿ô¤Ë¤Ï¡¢¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¤ÊÊÑ¿ô¤Ï¥°
+    ¥í¡¼¥Ð¥ë¤ËÄêµÁ¤µ¤ì¡¢¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤Ï¤½¤ÎÀâÌÀ¤ÈÃͤò·Ñ¾µ¤¹¤ë¤³¤È¤¬¤Ç
+    ¤­¤ë¡£³ÆÆþÎϥ᥽¥Ã¥É¤Ï¥í¡¼¥«¥ë¤ÊÃͤò»ý¤Ä¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤òÄêµÁ¤¹¤ë¡£
+    ¤Þ¤¿Æ±Ì¾¤Î¥°¥í¡¼¥Ð¥ë¤ÊÊÑ¿ô¤ÎÄêµÁ¤ò·Ñ¾µ¤¹¤ë¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤òÀë¸À¤¹¤ë
+    ¤³¤È¤â¤Ç¤­¤ë¡£
 
-    @li name:txtvar, ÀâÌÀ:"value is an M-text",
-        ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä)
+    $LANGUAGE ¤¬ #Mt ¤Ç $NAME ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤³¤Î´Ø¿ô¤Ï¥°¥í¡¼¥Ð¥ëÊÑ
+    ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥í¡¼¥«¥ëÊÑ¿ô¤Ë´Ø¤¹¤ë¤â¤Î¤òÊÖ¤¹¡£
 
-    ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
+    $VARIABLE ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£
 
+    Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (@ref m17nPlist) ¤Ç¤¢¤ë¡£
 @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" ""))
+  ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...)
 @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.
+    @c NAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
 
-    By default, the initial value is 0.
+    @c DESCRIPTION ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë¤Ï
+    #Mnil ¤Ç¤¢¤ë¡£
 
-    This setting gets effective in a newly opened input method.
+    @c STATUS ¤ÏÃͤ¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢
+    @c STATUS ¤ÎÃͤϠ#Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¡Ë, @b Mcustomized ¡Ê¥æ¡¼¥¶Ëè¤Î
+    ¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿ÃÍ¡Ë, @b Mconfigured
+    ¡Êminput_config_variable ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ëÃ͡ˤΤ¤¤º¤ì
+    ¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ëÊÑ¿ô¤Î¾ì¹ç¤Ë¤Ï¡¢@b Minherited ¡ÊÂбþ¤¹¤ë¥°¥í¡¼¥Ð¥ë
+    ÊÑ¿ô¤«¤é·Ñ¾µ¤·¤¿Ã͡ˤǤâ¤è¤¤¡£
 
-    @return
-    If the operation was successful, 0 is returned.  Otherwise -1 is
-    returned, and #merror_code is set to #MERROR_IM.  */
-/***ja
-    @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë.
+    @c VALUE ¤ÏÊÑ¿ô¤Î½é´üÃͤǤ¢¤ë¡£¤³¤ÎÍ×ÁǤΥ­¡¼¤¬#Mt ¤Ç¤¢¤ì¤Ð½é´üÃͤò»ý
+    ¤¿¤Ê¤¤¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¤Ï #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì
+    ¤«¤Ç¤¢¤ê¡¢ÃͤϤ½¤ì¤¾¤ìÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£
 
-    ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME 
-    ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE
-    ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£
+    @c VALID-VALUE ¤Ï¤â¤·¤¢¤ì¤Ð¡¢ÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò»ØÄꤹ¤ë¡£¤³¤ì¤Ï @c VALUE
+    ¤ÈƱ¤¸·¿(¤¹¤Ê¤ï¤ÁƱ¤¸¥­¡¼¤ò»ý¤Ä) ¤Ç¤¢¤ë¤¬¡¢Îã³°¤È¤·¤Æ @c VALUE ¤¬
+    integer ¤Î¾ì¹ç¤Ï @c VALID-VALUE ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹Æó¤Ä¤ÎÀ°¿ô¤«¤é
+    ¤Ê¤ë plist ¤È¤Ê¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
 
-    ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃͤϠ0 ¤Ç¤¢¤ë¡£
+    @c VALID-VALUE ¤¬¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô¤Ï @c VALUE ¤ÈƱ¤¸·¿¤Ç¤¢¤ë¸Â¤ê¤¤¤«¤Ê¤ëÃͤâ
+    ¤È¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
 
-    ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£
+    $VARIABLE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÖ¤µ¤ì¤ë plist ¤ÎºÇ½é¤ÎÍ×ÁǤÏ
+    $VARIABLE ¤Ë´Ø¤¹¤ë¾ðÊó¤ò´Þ¤à¡£
 
     @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 ();
+    µá¤á¤é¤ì¤¿¾ðÊ󤬸«¤Ä¤«¤ì¤Ð¡¢¶õ¤Ç¤Ê¤¤ plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹
+    ¥È¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð¦¤¬Êѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë
+    ¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£
 
-  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;
-}
+    ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤¹¤Ê¤ï¤Á»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤äÊÑ¿ô¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð
+    @c NULL ¤òÊÖ¤¹¡£ */
 
 MPlist *
 minput_get_variable (MSymbol language, MSymbol name, MSymbol variable)
@@ -4903,43 +5444,90 @@ minput_get_variable (MSymbol language, MSymbol name, MSymbol variable)
   return mplist__assq (im_info->configured_vars, variable);
 }
 
+/*=*/
+
 /***en
     @brief Configure the value of an input method variable.
 
-    The minput_config_variable () function assigns the value $VALUE to
-    the variable $VARIABLE of 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.
 
-    If $VALUE is not NULL, it must be a plist of one element whose key
-    is #Minteger, #Msymbol, or #Mtext, and the value is of the
-    corresponding type.
+    If $VALUE is a non-empty plist, it must be a plist of one element
+    whose key is #Minteger, #Msymbol, or #Mtext, and the value is of
+    the corresponding type.  That value is assigned to the variable.
+
+    If $VALUE is an empty plist, any configuration and customization
+    of the variable are canceled, and the default value is assigned to
+    the variable.
 
-    If $VALUE is NULL, 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.
+    If $VALUE is NULL, the configuration of the variable is canceled,
+    and the original value (what saved in per-user customization file,
+    or the default value) is assigned to the variable.
 
-    If $NAME is #Mnil, this function configure the global value, not
-    that of a specific input method.
+    In the latter two cases, $VARIABLE can be #Mnil to make all the
+    variables of the input method the target of the operation.
 
-    The configulation takes effect instantly for the current session
-    even for already opened input methods.  To make the configulation
+    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 If the operation was successful, this function returns 0,
+    @return
+
+    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>
 
-    $VALUE is not in a valid form, or the type doesn't much the
-    definition.
+    @seealso
+    minput_get_variable (), minput_save_config ().  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë.
 
-    $VARIABLE is not available for the input method.
+    ´Ø¿ô minput_config_variable () ¤ÏÃÍ $VALUE ¤ò¡¢$LANGUAGE ¤È $NAME
+    ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤ë¡£
 
-    $LANGUAGE and $NAME don't specify an existing input method.  
+    $VALUE ¤¬ ¶õ¥ê¥¹¥È¤Ç¤Ê¤±¤ì¤Ð¡¢£±Í×ÁǤΠplist ¤Ç¤¢¤ê¡¢¤½¤Î¥­¡¼¤Ï
+    #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì¤«¡¢ÃͤÏÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£
+    ¤³¤ÎÃͤ¬ÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤é¤ì¤ë¡£
 
-    @seealso
-    minput_get_variables (), minput_save_config ().  */
+    $VALUE ¤¬ ¶õ¥ê¥¹¥È¤Ç¤¢¤ì¤Ð¡¢ÊÑ¿ô¤ÎÀßÄê¤È¥«¥¹¥¿¥Þ¥¤¥º¤¬¥­¥ã¥ó¥»¥ë¤µ
+    ¤ì¡¢¥Ç¥Õ¥©¥ë¥ÈÃͤ¬ÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤é¤ì¤ë¡£
+
+    $VALUE ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢ÊÑ¿ô¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¸µ¤ÎÃ͡ʥ桼¥¶
+    Ëè¤Î¥«¥¹¥¿¥Þ¥¤¥º¥Õ¥¡¥¤¥ëÃæ¤ÎÃÍ¡¢¤Þ¤¿¤Ï¥Ç¥Õ¥©¥ë¥È¤ÎÃ͡ˤ¬³ä¤êÅö¤Æ¤é¤ì¤ë¡£
+
+    ¸å¤Î¤Õ¤¿¤Ä¤Î¾ì¹ç¤Ë¤Ï¡¢$VARIABLE ¤Ï #Mnil ¤ò¤È¤ë¤³¤È¤¬¤Ç¤­¡¢»ØÄꤵ¤ì
+    ¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤ÎÊÑ¿ôÀßÄê¤Î¥­¥ã¥ó¥»¥ë¤ò°ÕÌ£¤¹¤ë¡£
+
+    $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð
+    ¥ë¤ÊÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë¡£
+
+    ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï
+    ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹
+    ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤Î¥«¥¹¥¿¥Þ¥¤
+    ¥º¥Õ¥¡¥¤¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+
+    @return
+
+    ¤³¤Î´Ø¿ô¤Ï¡¢½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤ò¡¢¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ¤¹¡£¼ºÇԤȤϰʲ¼¤Î¾ì¹ç¤Ç¤¢¤ë¡£
+    <ul>
+    <li>$VALUE¤¬Í­¸ú¤Ê·Á¼°¤Ç¤Ê¤¤¡£·¿¤¬ÄêµÁ¤Ë¹ç¤ï¤Ê¤¤¡¢¤Þ¤¿¤ÏÃͤ¬Èϰϳ°¤Ç¤¢¤ë¡£
+    <li>$VARIABLE ¤¬»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÇÍøÍѤǤ­¤Ê¤¤¡£
+    <li>$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¤Ê¤¤¡£
+    </ul>
 
+    @seealso
+    minput_get_commands (), minput_save_config ().
+*/
 int
 minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
                        MPlist *value)
@@ -4952,14 +5540,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 +5566,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 +5602,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 <tt>${HOME}/.m17n.d</tt> (${HOME} is 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 +5764,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 +5792,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 +5818,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 +5853,495 @@ 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
+    (@ref 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 ¤Ç¤¢¤ê(@ref 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 @c MERROR_IM.  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë.
+
+    ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME 
+    ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE
+    ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£
+
+    ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃͤϠ0 ¤Ç¤¢¤ë¡£
+
+    ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£
+
+    @return
+    ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
+    #merror_code ¤ò @c 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 @c 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 ¤ò @c 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 */
@@ -5185,16 +6353,18 @@ minput_save_config (void)
     @brief Dump an input method.
 
     The mdebug_dump_im () function prints the input method $IM in a
-    human readable way to the stderr.  $INDENT specifies how many
-    columns to indent the lines but the first one.
+    human readable way to the stderr or to what specified by the
+    environment variable MDEBUG_OUTPUT_FILE.  $INDENT specifies how
+    many columns to indent the lines but the first one.
 
     @return
     This function returns $IM.  */
 /***ja
     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
 
-    ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ò stderr 
-    ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
+    ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤òɸ½à¥¨¥é¡¼½ÐÎϤ⤷¤¯¤Ï
+    ´Ä¶­ÊÑ¿ô MDEBUG_DUMP_FONT ¤Ç»ØÄꤵ¤ì¤¿¥Õ¥¡¥¤¥ë¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç½Ð
+    ÎϤ¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
 
     @return
     ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
@@ -5209,7 +6379,7 @@ mdebug_dump_im (MInputMethod *im, int indent)
   memset (prefix, 32, indent);
   prefix[indent] = '\0';
 
-  fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
+  fprintf (mdebug__output, "(input-method %s %s ", msymbol_name (im->language),
           msymbol_name (im->name));
   mdebug_dump_mtext (im_info->title, 0, 0);
   if (im->name != Mnil)
@@ -5218,11 +6388,11 @@ mdebug_dump_im (MInputMethod *im, int indent)
 
       MPLIST_DO (state, im_info->states)
        {
-         fprintf (stderr, "\n%s  ", prefix);
+         fprintf (mdebug__output, "\n%s  ", prefix);
          dump_im_state (MPLIST_VAL (state), indent + 2);
        }
     }
-  fprintf (stderr, ")");
+  fprintf (mdebug__output, ")");
   return im;
 }