(resolve_command): Adjusted for the format change of
authorhanda <handa>
Thu, 14 Sep 2006 00:55:48 +0000 (00:55 +0000)
committerhanda <handa>
Thu, 14 Sep 2006 00:55:48 +0000 (00:55 +0000)
configured_cmds member.
(load_commands, load_variables): Fix for errornous data handling.
(config_command, config_variable): New function.
(config_all_commands, config_all_variables): Renamed from
config_commands and config_variables.  Utilize the above function.
(check_variable_value): Argument changed.  Callers changed.
(load_im_info): Call config_all_commands and config_all_variables.
(init_ic_info): Adjusted for the format change of configured_vars
member.
(minput__init): Initialize Mcustomized, Mconfigured, and
Minherited.
(Mcustomized, Mconfigured, Minherited): New variables.
(minput_get_command): Be sure to return NULL if an input method
use no local command.
(minput_get_variable): Be sure to return NULL if an input method
use no local variable.
(minput_config_command, minput_config_variable)
(minput_save_config): Adjusted for the format change of
configured_cmds and configured_vars members.

src/input.c

index b13eb4d..edeb216 100644 (file)
@@ -907,7 +907,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;
@@ -1610,8 +1611,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 +1618,114 @@ 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 (! MPLIST_MTEXT_P (p)
+             && (! MPLIST_SYMBOL_P (p) || MPLIST_SYMBOL (p) != Mnil))
            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;
+  MText *description = NULL;
+  MSymbol status;
+  MPlist *keyseq;
+
+  name = MPLIST_SYMBOL (plist);
+  plist = MPLIST_NEXT (plist);
+  if (MPLIST_MTEXT_P (plist))
+    description = MPLIST_MTEXT (plist);
+  else if (global_cmds && ((global = mplist__assq (global_cmds, name))))
+    {
+      global = MPLIST_NEXT (MPLIST_PLIST (global));
+      description = MPLIST_MTEXT_P (global) ? MPLIST_MTEXT (global) : NULL;
+    }
+  if (MPLIST_TAIL_P (plist))
+    {
+      if (! global
+         && global_cmds && ((global = mplist__assq (global_cmds, name))))
+       global = MPLIST_NEXT (MPLIST_PLIST (global));
+      if (global)
+       {
+         keyseq = MPLIST_NEXT (global);
+         status = Minherited;
+       }
+      else
+       {
+         keyseq = plist;
+         status = Mnil;
+       }
+    }
+  else
+    {
+      keyseq = MPLIST_NEXT (plist);
+      status = Mnil;
+    }
+
+  if (config_cmds && (config = mplist__assq (config_cmds, name)))
+    {
+      config = MPLIST_NEXT (MPLIST_PLIST (config));
+      if (! MPLIST_TAIL_P (config))
+       {
+         keyseq = MPLIST_NEXT (config);
+         status = Mconfigured;
+       }
+    }
+  else if (custom_cmds && (custom = mplist__assq (custom_cmds, name)))
+    {
+      custom = MPLIST_NEXT (MPLIST_PLIST (custom));
+      if (! MPLIST_TAIL_P (custom))
+       {
+         keyseq = MPLIST_NEXT (custom);
+         status = Mcustomized;
+       }
+    }
+  
+  plist = mplist ();
+  mplist_add (plist, Msymbol, name);
+  if (description)
+    mplist_add (plist, Mtext, 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,41 +1733,17 @@ 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)
-       {
-         M17N_OBJECT_UNREF (pl);
-         pl = MPLIST_NEXT (pl);
-         pl = MPLIST_NEXT (pl);
-         mplist_set (pl, Mnil, NULL);
-         mplist__conc (pl, p);
-       }
+      MPlist *pl = config_command (MPLIST_PLIST (plist),
+                                  global_cmds, custom_cmds, config_cmds);
+      if (pl)
+       tail = mplist_add (tail, Mplist, pl);
     }
 }
 
@@ -1707,29 +1751,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 +1801,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 +1813,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 +1848,188 @@ load_variables (MInputMethodInfo *im_info, MPlist *plist)
   MPlist *tail;
 
   im_info->vars = tail = mplist ();
-
   MPLIST_DO (plist, MPLIST_NEXT (plist))
     {
-      MPlist *pl, *p, *global = NULL;
-      MSymbol name;
-      MPlist *valid_values;
+      MPlist *pl, *p;
 
       if (MFAILP (MPLIST_PLIST_P (plist)))
        continue;
-      pl = MPLIST_PLIST (plist); /* PL ::= (NAME [DESC VALUE VALID ...]) */
+      pl = MPLIST_PLIST (plist); /* PL ::= (NAME DESC VALUE VALID ...) */
       if (MFAILP (MPLIST_SYMBOL_P (pl)))
        continue;
-      name = MPLIST_SYMBOL (pl);
-      p = MPLIST_NEXT (pl);    /* P ::= ([DESC VALUE VALID ...]) */
-      if (global_vars
-         && (global = mplist__assq (global_vars, name)))
+      if (im_info == global_info)
        {
-         /* GLOBAL ::= ((NAME DESC ...) ...) */
-         global = MPLIST_PLIST (global); /* GLOBAL ::= (NAME DESC ...) */
-         global = MPLIST_NEXT (global);  /* GLOBAL ::= (DESC VALUE ...) */
-       }
-      if (! MPLIST_MTEXT_P (p))
-       {
-         if (global && MPLIST_MTEXT_P (global))
-           mplist_set (p, Mtext, MPLIST_MTEXT (global));
+         /* Loading a global variable.  */
+         p = MPLIST_NEXT (pl);
+         if (MPLIST_TAIL_P (p))
+           mplist_add (p, Msymbol, Mnil);
          else
-           mplist_set (p, Msymbol, Mnil);
+           {
+             if (MFAILP (MPLIST_MTEXT_P (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 (p); /* P ::= (VALUE ...) */
+           }
+
+         p = MPLIST_NEXT (pl); /* P ::= (DESC VALUE VALID ...) */
+         if (! MPLIST_TAIL_P (p))
+           {
+             if (MFAILP (MPLIST_MTEXT_P (p)
+                         || (MPLIST_SYMBOL_P (p)
+                             && MPLIST_SYMBOL (p) == Mnil)))
+               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);
+  MText *description = NULL;
+  MSymbol status;
+  MPlist *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))
+    description = MPLIST_MTEXT (plist);
+  else if (global && MPLIST_MTEXT (global))
+    description = MPLIST_MTEXT (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)))
+    {
+      config = MPLIST_NEXT (MPLIST_PLIST (config));
+      if (! MPLIST_TAIL_P (config))
+       {
+         value = MPLIST_NEXT (config);
+         if (MFAILP (check_variable_value (value, global ? global : plist)))
+           value = NULL;
+         status = Mconfigured;
+       }
+    }
+  else if (custom_vars && (custom = mplist__assq (custom_vars, name)))
+    {
+      custom = MPLIST_NEXT (MPLIST_PLIST (custom));
+      if (! MPLIST_TAIL_P (custom))
+       {
+         value = MPLIST_NEXT (custom);
+         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, Mtext, 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 +2037,22 @@ 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);
-           }
-       }
+      MPlist *pl = config_variable (MPLIST_PLIST (plist),
+                                   global_vars, custom_vars, config_vars);
+      if (pl)
       tail = mplist_add (tail, Mplist, pl);
-      if (p)
-       {
-         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 +2062,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 +2070,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);
     }
@@ -3202,14 +3345,19 @@ 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));
+       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));
+         }
       }
 
   if (im_info->externals)
@@ -3584,6 +3732,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;
@@ -3733,6 +3884,20 @@ MSymbol Minput_focus_move;
 /*** @} */
 
 /*=*/
+/***en
+    @name Variables: Predefined symbols used in input method information.
+
+    These are the predefined symbols describing status of input method
+    command and variable, and are used in a return value of
+    minput_get_command () and minput_get_variable ().  */
+/*** @{ */ 
+/*=*/
+MSymbol Minherited;
+MSymbol Mcustomized;
+MSymbol Mconfigured;
+/*** @} */ 
+
+/*=*/
 
 /***en
     @brief The default driver for internal input methods.
@@ -4328,283 +4493,198 @@ minput_get_description (MSymbol language, MSymbol name)
   return im_info->description;
 }
 
-/***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.
+/***en
+    @brief Get information about input method command(s).
 
-    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 minput_get_command () function returns information about
+    $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.
 
-    The first element of COMMAND-INFO has the key #Mtext, and the
-    value is an M-text describing the command.
+    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 local key assignment.  It may
+    also declares a local command that inherits definition of a
+    global command of the same name.
 
-    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, information about a global
+    command is returned.  Othewise 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 (#m17nPlist) of this
+    format:
+@verbatim
+  ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...)
+@endverbatim
+    NAME is a symbol representing the command name.
 
-    ¥³¥Þ¥ó¥É¤Ë¤Ï¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É
-    ¤ÏÊ£¿ô¤ÎÆþÎϥ᥽¥Ã¥É¤Ë¤ª¤¤¤Æ¡¢Æ±¤¸ÌÜŪ¤Ç¡¢¥°¥í¡¼¥Ð¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ
-    ¤ÇÍѤ¤¤é¤ì¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤ÏÆÃÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Î¤ß¡¢¥í¡¼¥«¥ë
-    ¤Ê¥­¡¼³äÅö¤Ç»ÈÍѤµ¤ì¤ë¡£
+    DESCRIPTION is an M-text describing the command, or #Mnil if the
+    command has no description.
 
-    ¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ï¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Î¥­¡¼³äÅö¤òÊѹ¹¤¹¤ë¤³¤È¤â¤Ç
-    ¤­¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥ÉÍѤΥ°¥í¡¼¥Ð¥ë¥­¡¼³ä¤êÅö¤Æ¤Ï¡¢»ÈÍѤ¹¤ëÆþÎÏ
-    ¥á¥½¥Ã¥É¤Ë¤ª¤¤¤Æ¤½¤Î¥³¥Þ¥ó¥ÉÍÑ¤Î¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤¬Â¸ºß¤·¤Ê¤¤¾ì¹ç
-    ¤Ë¤Î¤ßÍ­¸ú¤Ç¤¢¤ë¡£
+    STATUS is a symbol representing how the key assignment is decided.
+    The value is #Mnil (the default key assignment), #Mcustomized (the
+    key assignment is customized by per-user configuration file), or
+    #Mconfigured (the key assignment is set by the call of
+    minput_config_command ()).  For a local command only, it may also
+    be #Minherited (the key assignment is inherited from the
+    corresponding global command).
 
-    $NAME ¤¬ #Mnil ¤Ç¤¢¤ì¤Ð¡¢¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤³¤Î
-    ¾ì¹ç¡¢$LANGUAGE ¤Ï̵»ë¤µ¤ì¤ë¡£
+    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
-    ¤Î·Á¼°¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ë¡£
+    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.
 
-    COMMAND-INFO ¤ÎÂè°ìÍ×ÁǤΥ­¡¼¤Ï #Mtext ¤Þ¤¿¤Ï #Msymbol ¤Ç¤¢¤ë¡£¥­¡¼
-    ¤¬ #Mtext ¤Ê¤é¡¢ÃͤϤ½¤Î¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£¥­¡¼¤¬
-    #Msymbol ¤Ê¤éÃͤϠ#Mnil ¤Ç¤¢¤ê¡¢¤³¤Î¥³¥Þ¥ó¥É¤ÏÀâÌÀ¥Æ¥­¥¹¥È¤ò»ý¤¿¤Ê
-    ¤¤¤³¤È¤Ë¤Ê¤ë¡£
+    Otherwide (the specified input method or the specified command
+    doesn't exist), @c NULL is returned.  */
 
-    ¤½¤ì°Ê³°¤ÎÍ×ÁǤ¬Ìµ¤±¤ì¤Ð¡¢¤³¤Î¥³¥Þ¥ó¥É¤ËÂФ·¤Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä
-    ¤êÅö¤Æ¤é¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢»Ä¤ê¤Î³ÆÍ×ÁǤϥ­
-    ¡¼¤È¤·¤Æ#Mplist ¤ò¡¢ÃͤȤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò»ý¤Ä¡£¤³¤Î¥×¥í¥Ñ¥Æ¥£
-    ¥ê¥¹¥È¤Î¥­¡¼¤Ï #Msymbol ¤Ç¤¢¤ê¡¢Ãͤϸ½ºß¤½¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì
-    ¤Æ¤¤¤ëÆþÎÏ¥­¡¼¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
+#if EXAMPLE_CODE
+MText *
+get_im_command_description (MSymbol language, MSymbol name, MSymbol command)
+{
+  /* Return a description of the command COMMAND of the input method */
+  /* specified by LANGUAGE and NAME.  */
+  MPlist *cmd = minput_get_command (langauge, name, command);
+  MPlist *plist;
 
-    ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð
-    ¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£*/
+  if (! cmds)
+    return NULL;
+  plist = mplist_value (cmds); /* (NAME DESCRIPTION KEY-SEQ ...) */
+  plist = mplist_next (plist); /* (DESCRIPTION KEY-SEQ ...) */
+  return  (mplist_key (plist) == Mtext
+          ? (MText *) mplist_value (plist)
+          : NULL);
+}
+#endif
 
 MPlist *
-minput_get_commands (MSymbol language, MSymbol name)
+minput_get_command (MSymbol language, MSymbol name, MSymbol command)
 {
   MInputMethodInfo *im_info;
-  MPlist *cmds;
 
   MINPUT__INIT ();
 
   im_info = get_im_info (language, name, Mnil, Mcommand);
-  if (! im_info || ! im_info->configured_vars)
-    return NULL;
-  M17N_OBJECT_UNREF (im_info->bc_cmds);
-  im_info->bc_cmds = mplist ();
-  MPLIST_DO (cmds, im_info->configured_cmds)
-    {
-      MPlist *plist = MPLIST_PLIST (cmds);
-      MPlist *elt = mplist ();
-
-      mplist_push (im_info->bc_cmds, Mplist, elt);
-      mplist_add (elt, MPLIST_SYMBOL (plist),
-                 mplist_copy (MPLIST_NEXT (plist)));
-      M17N_OBJECT_UNREF (elt);
-    }
-  return im_info->bc_cmds;
-}
-
-/***en
-    @brief Assign a key sequence to an input method command (obsolete).
-
-    This function is obsolete.  Use minput_config_command () instead.
-
-    The minput_assign_command_keys () function assigns input key
-    sequence $KEYSEQ to input method command $COMMAND for the input
-    method specified by $LANGUAGE and $NAME.  If $NAME is #Mnil, the
-    key sequence is assigned globally no matter what $LANGUAGE is.
-    Otherwise the key sequence is assigned locally.
-
-    Each element of $KEYSEQ must have the key $Msymbol and the value
-    must be a symbol representing an input key.
-
-    $KEYSEQ may be @c NULL, in which case, all assignments are deleted
-    globally or locally.
-
-    This assignment gets effective in a newly opened input method.
-
-    @return
-    If the operation was successful, 0 is returned.  Otherwise -1 is
-    returned, and #merror_code is set to #MERROR_IM.  */
-/***ja
-    @brief ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤ò³ä¤êÅö¤Æ¤ë.
-
-    ´Ø¿ô minput_assign_command_keys () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ
-    »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥ÉÍѤÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É $COMMAND ¤ËÂФ·¤Æ¡¢
-    ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹ $KEYSEQ ¤ò³ä¤êÅö¤Æ¤ë¡£ $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢
-    $LANGUAGE ¤Ë´Ø·¸¤Ê¤¯¡¢ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥°¥í¡¼¥Ð¥ë¤Ë³ä¤êÅö¤Æ¤é
-    ¤ì¤ë¡£¤½¤¦¤Ç¤Ê¤ì¤Ð¡¢³ä¤êÅö¤Æ¤Ï¥í¡¼¥«¥ë¤Ç¤¢¤ë¡£
-
-    $KEYSEQ ¤Î³ÆÍ×ÁǤϥ­¡¼¤È¤·¤Æ $Msymbol ¤ò¡¢ÃͤȤ·¤ÆÆþÎÏ¥­¡¼¤òɽ¤¹¥·
-    ¥ó¥Ü¥ë¤ò»ý¤¿¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
-
-    $KEYSEQ ¤Ï @c NULL ¤Ç¤â¤è¤¤¡£¤³¤Î¾ì¹ç¡¢¥°¥í¡¼¥Ð¥ë¤â¤·¤¯¤Ï¥í¡¼¥«¥ë¤Ê
-    ¤¹¤Ù¤Æ¤Î³ä¤êÅö¤Æ¤¬¾Ãµî¤µ¤ì¤ë¡£
-
-    ¤³¤Î³ä¤êÅö¤Æ¤Ï¡¢³ä¤êÅö¤Æ°Ê¹ß¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­
-    ¸ú¤Ë¤Ê¤ë¡£
-
-    @return ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
-    #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
-
-int
-minput_assign_command_keys (MSymbol language, MSymbol name,
-                           MSymbol command, MPlist *keyseq)
-{
-  int ret;
-
-  MINPUT__INIT ();
-
-  if (command == Mnil)
-    MERROR (MERROR_IM, -1);
-  if (keyseq)
-    {
-      MPlist *plist;
-
-      if  (! check_command_keyseq (keyseq))
-       MERROR (MERROR_IM, -1);
-      plist = mplist ();
-      mplist_add (plist, Mplist, keyseq);
-      keyseq = plist;
-    }  
-  else
-    keyseq = mplist ();
-  ret = minput_config_command (language, name, command, keyseq);
-  M17N_OBJECT_UNREF (keyseq);
-  return ret;
-}
-
-MPlist *
-minput_get_command (MSymbol language, MSymbol name, MSymbol command)
-{
-  MInputMethodInfo *im_info;
-
-  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.
+    sequences $KEYSEQLIST to the command $COMMAND of the input method
+    specified by $LANGUAGE and $NAME.
 
-    If $KEYSEQ-LIST is a non-empty plist, it must be a list of key
-    sequences, and each key sequence must be a plist of key symbols.
+    If $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 is an empty plist, the command become unusable.
+    If $KEYSEQLIST is an empty plist, the command becomes unusable.
 
-    If $KEYSEQ is NULL, all configulations of the command for the
-    input method are canceled, and the default key sequences become
+    If $KEYSEQLIST is NULL, a configuration of the command for the
+    input method is canceled, and the default key sequences become
     effective.  In that case, if $COMMAND is #Mnil, configurations for
     all commands of the input method are canceled.
 
-    If $NAME is #Mnil, this function configure the global key sequence
-    assignments, not that of a specific input method.
+    If $NAME is #Mnil, this function configure 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
-    minput_save_config ().
+    The configuration takes effect for input methods opened or
+    re-opened later in the current session.  To make the configuration
+    take effect for the future session, it must be saved in a per-user
+    configuration file by the function minput_save_config ().
 
     @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 don't specify an existing input method.
+    </ul>
 
-    $KEYSEQ is not in a valid form.
+    @seealso
+    minput_get_commands (), minput_save_config ().
+*/
 
-    $COMMAND is not available for the input method.
+#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;
 
-    $LANGUAGE and $NAME don't specify an existing input method.
+  /* 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 */
+      /* should come some error handling code.  */
+    }
+  /* Now CMD == ((start DESCRIPTION KEY-SEQUENCE ...) ...).  Extract */
+  /* the part (KEY-SEQUENCE ...).  */
+  plist = mplist_next (mplist_next (mplist_value (cmd)));
+  /* 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);
 
-    @seealso
-    minput_get_commands (), minput_save_config ().  */
+  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 (keyseqlist)
     {
-      if (keyseq)
+      if (command == Mnil)
        MERROR (MERROR_IM, -1);
+      MPLIST_DO (plist, keyseqlist)
+       if (! MPLIST_PLIST_P (plist)
+           || ! check_command_keyseq (plist))
+         MERROR (MERROR_IM, -1);
     }
-  else if (! im_info->cmds
-          || ! mplist__assq (im_info->cmds, command))
+
+  im_info = get_im_info (language, name, Mnil, Mcommand);
+  if (! im_info)
+    MERROR (MERROR_IM, -1);
+  if (command != Mnil
+      && (! im_info->cmds
+         || ! mplist__assq (im_info->cmds, command)))
     MERROR (MERROR_IM, -1);
 
   config = get_config_info (im_info);
@@ -4639,306 +4719,157 @@ minput_config_command (MSymbol language, MSymbol name, MSymbol command,
       plist = mplist__assq (config->cmds, command);
       if (plist)
        {
-         plist = MPLIST_PLIST (plist); /* (NAME DESC KEY-SEQUENCE ...)  */
-         plist = MPLIST_NEXT (plist);  /* (DESC ...) */
-         mplist_set (plist, Mnil, NULL);
+         plist = MPLIST_PLIST (plist); /* (NAME [nil KEY-SEQUENCE ...])  */
+         plist = MPLIST_NEXT (plist);  /* ([nil ...]) */
+         if (! MPLIST_TAIL_P (plist))
+           mplist_set (plist, Mnil, NULL); /* () */
        }
       else
        {
          plist = mplist ();
-         mplist_push (config->cmds, Mplist, plist);
+         mplist_add (config->cmds, Mplist, plist);
          M17N_OBJECT_UNREF (plist);
          plist = mplist_add (plist, Msymbol, command);
+         plist = MPLIST_NEXT (plist);
        }
-      if (keyseq)
+      if (keyseqlist)
        {
-         MPlist *pl, *p;
+         MPlist *pl;
 
-         keyseq = mplist_copy (keyseq);
-         MPLIST_DO (pl, keyseq)
+         plist = mplist_add (plist, Msymbol, Mnil);
+         MPLIST_DO (keyseqlist, keyseqlist)
            {
-             p = mplist_copy (MPLIST_VAL (pl));
-             mplist_set (pl, Mplist, p);
-             M17N_OBJECT_UNREF (p);
+             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 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 definitin, 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 declares 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.  Othewise information about a local variable
+    is returned.
 
-    The minput_get_variables () function returns a plist (#MPlist) of
-    variables used to control the behavior of the input method
-    specified by $LANGUAGE and $NAME.  The plist is @e well-formed
-    (#m17nPlist) of the following format:
+    If $VARIABLE is #Mnil, information about all variables is
+    returned.
 
+    The return value is a @e well-formed plist (#m17nPlist) of this
+    format:
 @verbatim
-    (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
-     VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
-     ...)
+  ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...)
 @endverbatim
+    NAME is a symbol representing the variable name.
 
-    @c VARNAME is a symbol representing the variable name.
+    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.
+    STATUS is a symbol representing how the value is decided.  The
+    value is #Mnil (the default value), #Mcustomized (the value is
+    customized by per-user configuration file), or #Mconfigured (the
+    value is set byq the call of minput_config_command ()).  For a
+    local variable only, it may also be #Minherited (the value is
+    inherited from the corresponding global variable).
 
-    @c DEFAULT-VALUE is the default value of the variable.  It is a
-    symbol, integer, or M-text.
+    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
+    VALID-VALUEs (if any) specify which values the variable can have.
+    They have the same type (i.e. having the same key) as VALUE except
+    for the case that VALUE is an integer.  In that case, VALID-VALUE
+    may be a plist of two integers specifying the range of possible
     values.
 
-    For instance, suppose an input method has the variables:
+    If there no VALID-VALUE, the variable can have any value as long
+    as the type is the same as VALUE.
 
-    @li name:intvar, description:"value is an integer",
-         initial value:0, value-range:0..3,10,20
+    If $VALIABLE is not #Mnil, the first element of the returned plist
+    contains the information about $VALIABLE.
 
-    @li name:symvar, description:"value is a symbol",
-         initial value:nil, value-range:a, b, c, nil
+    @return
 
-    @li name:txtvar, description:"value is an M-text",
-         initial value:empty text, no value-range (i.e. any text)
+    If the requested information was found, a pointer to a non-empty
+    plist is returned.  As the plist is kept in the library, the
+    caller must not modify nor free it.
 
-    Then, the returned plist is as follows.
+    Otherwide (the specified input method or the specified variable
+    doesn't exist), @c NULL is returned.  */
 
-@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
+MPlist *
+minput_get_variable (MSymbol language, MSymbol name, MSymbol variable)
+{
+  MInputMethodInfo *im_info;
 
-    @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__INIT ();
 
-    ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
-    ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È
-    (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(#m17nPlist) °Ê
-    ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£
+  im_info = get_im_info (language, name, Mnil, Mvariable);
+  if (! im_info || ! im_info->configured_vars)
+    return NULL;
+  if (variable == Mnil)
+    return im_info->configured_vars;
+  return mplist__assq (im_info->configured_vars, variable);
+}
 
-@verbatim
-    (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
-     VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
-     ...)
-@endverbatim
+/*=*/
 
-    @c VARNAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
+/***en
+    @brief Configure the value of an input method variable.
 
-    @c DOC-MTEXT ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£
+    The minput_config_variable () function assigns $VALUE to the
+    variable $VARIABLE of the input method specified by $LANGUAGE and
+    $NAME.
 
-    @c DEFAULT-VALUE ¤ÏÊÑ¿ô¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤǤ¢¤ê¡¢¥·¥ó¥Ü¥ë¡¢À°¿ô¤â¤·¤¯¤Ï
-    M-text ¤Ç¤¢¤ë¡£
+    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.
 
-    @c VALUE ¤Ï¡¢¤â¤·»ØÄꤵ¤ì¤Æ¤¤¤ì¤ÐÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò¼¨¤¹¡£¤â¤·
-    @c DEFAULT-VALUE ¤¬À°¿ô¤Ê¤é¡¢ @c VALUE ¤Ï (@c FROM @c TO) ¤È¤¤¤¦·Á
-    ¤Î¥ê¥¹¥È¤Ç¤âÎɤ¤¡£¤³¤Î¾ì¹ç @c FROM ¤È @c TO ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹¡£
+    If $VALUE is NULL, a configuration for the variable for the input
+    method is canceled, and the variable is initialized to the default
+    value.  In that case, if $VARIABLE is #Mnil, configurations for
+    all variables of the input method are canceled.
 
-    Îã¤È¤·¤Æ¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤¬¼¡¤Î¤è¤¦¤ÊÊÑ¿ô¤ò»ý¤Ä¾ì¹ç¤ò¹Í¤¨¤è¤¦¡£
+    If $NAME is #Mnil, this function configure the value of global
+    variable, not that of a specific input method.
 
-    @li name:intvar, ÀâÌÀ:"value is an integer",
-        ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20
+    The configuration takes effect for input methods opened or
+    re-opened later in the current session.  To make the configuration
+    take effect for the future session, it must be saved in a per-user
+    configuration file by the function minput_save_config ().
 
-    @li name:symvar, ÀâÌÀ:"value is a symbol",
-         ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil
+    @return
 
-    @li name:txtvar, ÀâÌÀ:"value is an M-text",
-        ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä)
-
-    ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
-
-@verbatim
-    (intvar ("value is an integer" 0 (0 3) 10 20)
-     symvar ("value is a symbol" nil a b c nil)
-     txtvar ("value is an M-text" ""))
-@endverbatim
-
-    @return 
-    ÆþÎϥ᥽¥Ã¥É¤¬²¿¤é¤«¤ÎÊÑ¿ô¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð #MPlist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
-    ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
-    ÆþÎϥ᥽¥Ã¥É¤¬ÊÑ¿ô¤ò°ìÀÚ»ÈÍѤ·¤Æ¤Ê¤±¤ì¤Ð¡¢@c NULL ¤òÊÖ¤¹¡£  */
-
-MPlist *
-minput_get_variables (MSymbol language, MSymbol name)
-{
-  MInputMethodInfo *im_info;
-  MPlist *vars;
-
-  MINPUT__INIT ();
-
-  im_info = get_im_info (language, name, Mnil, Mvariable);
-  if (! im_info || ! im_info->configured_vars)
-    return NULL;
-
-  M17N_OBJECT_UNREF (im_info->bc_vars);
-  im_info->bc_vars = mplist ();
-  MPLIST_DO (vars, im_info->configured_vars)
-    {
-      MPlist *plist = MPLIST_PLIST (vars);
-      MPlist *elt = mplist ();
-
-      mplist_push (im_info->bc_vars, Mplist, elt);
-      mplist_add (elt, Msymbol, MPLIST_SYMBOL (plist));
-      elt = MPLIST_NEXT (elt);
-      mplist_set (elt, Mplist, mplist_copy (MPLIST_NEXT (plist)));
-      M17N_OBJECT_UNREF (elt);
-    }
-  return im_info->bc_vars;
-}
-
-/***en
-    @brief Set the initial value of an input method variable.
-
-    The minput_set_variable () function sets the initial value of
-    input method variable $VARIABLE to $VALUE for the input method
-    specified by $LANGUAGE and $NAME.
-
-    By default, the initial value is 0.
-
-    This setting gets effective in a newly opened input method.
-
-    @return
-    If the operation was successful, 0 is returned.  Otherwise -1 is
-    returned, and #merror_code is set to #MERROR_IM.  */
-/***ja
-    @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë.
-
-    ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME 
-    ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE
-    ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£
-
-    ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃͤϠ0 ¤Ç¤¢¤ë¡£
-
-    ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£
-
-    @return
-    ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
-    #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
-
-int
-minput_set_variable (MSymbol language, MSymbol name,
-                    MSymbol variable, void *value)
-{
-  MPlist *plist, *pl;
-  MInputMethodInfo *im_info;
-  int ret;
-
-  MINPUT__INIT ();
-
-  if (variable == Mnil)
-    MERROR (MERROR_IM, -1);
-  plist = minput_get_variable (language, name, variable);
-  plist = MPLIST_PLIST (plist);
-  plist = MPLIST_NEXT (plist);
-  pl = mplist ();
-  mplist_add (pl, MPLIST_KEY (plist), value);
-  ret = minput_config_variable (language, name, variable, pl);
-  M17N_OBJECT_UNREF (pl);
-  if (ret == 0)
-    {
-      im_info = get_im_info (language, name, Mnil, Mvariable);
-      im_info->tick = 0;
-    }
-  return ret;
-}
-
-MPlist *
-minput_get_variable (MSymbol language, MSymbol name, MSymbol variable)
-{
-  MInputMethodInfo *im_info;
-
-  MINPUT__INIT ();
-
-  im_info = get_im_info (language, name, Mnil, Mvariable);
-  if (! im_info || ! im_info->configured_vars)
-    return NULL;
-  if (variable == Mnil)
-    return im_info->configured_vars;
-  return mplist__assq (im_info->configured_vars, variable);
-}
-
-/***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.
-
-    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 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 $NAME is #Mnil, this function configure the global value, not
-    that of a specific input method.
-
-    The configulation takes effect instantly for the current session
-    even for already opened input methods.  To make the configulation
-    take effect for the future session, it must be saved in a per-user
-    customization file by the function minput_save_config ().
-
-    @return If the operation was successful, this function returns 0,
+    If the operation was successful, this function returns 0,
     otherwise returns -1.  The operation fails in these cases:
-
-    $VALUE is not in a valid form, or the type doesn't much the
-    definition.
-
-    $VARIABLE is not available for the input method.
-
-    $LANGUAGE and $NAME don't specify an existing input method.  
+    <ul>
+    <li>$VALUE is not in a valid form, the type doesn't much the
+    definition, or the value is our of range.
+    <li>$VARIABLE is not available for the input method.
+    <li>$LANGUAGE and $NAME don't specify an existing input method.  
+    </ul>
 
     @seealso
-    minput_get_variables (), minput_save_config ().  */
+    minput_get_variable (), minput_save_config ().  */
 
 int
 minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
@@ -4958,9 +4889,20 @@ minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
        MERROR (MERROR_IM, -1);
     }
   else if (! im_info->vars
-          || ! mplist__assq (im_info->vars, variable))
+          || ! (plist = mplist__assq (im_info->configured_vars, variable)))
     MERROR (MERROR_IM, -1);
 
+  if (variable != Mnil && 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);
+    }
+
   config = get_config_info (im_info);
   if (! config)
     {
@@ -4993,9 +4935,10 @@ minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
       plist = mplist__assq (config->vars, variable);
       if (plist)
        {
-         plist = MPLIST_PLIST (plist); /* (NAME DESC VALUE) */
-         plist = MPLIST_NEXT (plist);  /* (DESC VALUE) */
-         mplist_set (plist, Mnil ,NULL);
+         plist = MPLIST_PLIST (plist); /* (NAME nil VALUE) */
+         plist = MPLIST_NEXT (plist);  /* ([nil VALUE]) */
+         if (! MPLIST_TAIL_P (plist))
+           mplist_set (plist, Mnil ,NULL); /* () */
        }
       else
        {
@@ -5003,26 +4946,72 @@ minput_config_variable (MSymbol language, MSymbol name, MSymbol variable,
          mplist_add (config->vars, Mplist, plist);
          M17N_OBJECT_UNREF (plist);
          plist = mplist_add (plist, Msymbol, variable);
+         plist = MPLIST_NEXT (plist);
        }
       if (value)
        {
          plist = mplist_add (plist, Msymbol, Mnil);
-         plist = MPLIST_NEXT (plist);
-         mplist_set (plist, MPLIST_KEY (value), MPLIST_VAL (value));
+         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 configuration file.
+    
+    The minput_config_file () function returns the absolute path name
+    of per-user configuration file into which minput_save_config ()
+    save configurations.  It is usually "config.mic" under the
+    directory ".m17n.d" of user's home directory.  It is not assured
+    that the file of the returned name exists nor is
+    readable/writable.  If minput_save_config () fails and returns -1,
+    an application program would like to 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_config_file ()
+*/
+
 char *
 minput_config_file ()
 {
   MINPUT__INIT ();
+
   return mdatabase__file (im_custom_mdb);
 }
 
+/*=*/
+
+/***en
+    @brief Save configurations in per-user configuration file.
+
+    The minput_save_config () functions saves the configurations done
+    so far in the current session into the per-user configuration
+    file.
+
+    @return
+
+    If the operation was successful, 1 is returned.  If the per-user
+    configuration file is currently locked, 0 is returned.  In that
+    case, the caller may wait for a while and try again.  If the
+    customization 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 ()  */
+
 int
 minput_save_config (void)
 {
@@ -5125,7 +5114,7 @@ minput_save_config (void)
     {
       MPlist *pl = MPLIST_PLIST (plist);
       MSymbol language, name, extra;
-      MInputMethodInfo *custom;
+      MInputMethodInfo *custom, *im_info;
 
       language = MPLIST_SYMBOL (pl);
       pl  = MPLIST_NEXT (pl);
@@ -5134,6 +5123,14 @@ minput_save_config (void)
       extra = MPLIST_SYMBOL (pl);
       pl = MPLIST_NEXT (pl);
       custom = MPLIST_VAL (pl);
+      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);
@@ -5166,66 +5163,450 @@ minput_save_config (void)
        }
     }
 
-  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);
 }
 
-
-/*** @} */
-/*=*/
-/*** @addtogroup m17nDebug */
-/*=*/
-/*** @{  */
 /*=*/
 
 /***en
-    @brief Dump an input method.
+    @name Obsolete functions
+*/
+/*** @{ */
 
-    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.
+/*=*/
+/***en
+    @brief Get a list of variables of an input method (obsolete).
 
-    @return
-    This function returns $IM.  */
-/***ja
-    @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
+    This function is obsolete.  Use minput_get_variable () instead.
 
-    ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ò stderr 
-    ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
+    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:
 
-    @return
-    ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
+@verbatim
+    (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
+     VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
+     ...)
+@endverbatim
 
-MInputMethod *
-mdebug_dump_im (MInputMethod *im, int indent)
-{
-  MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
-  char *prefix;
+    @c VARNAME is a symbol representing the variable name.
 
-  prefix = (char *) alloca (indent + 1);
-  memset (prefix, 32, indent);
-  prefix[indent] = '\0';
+    @c DOC-MTEXT is an M-text describing the variable.
 
-  fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
-          msymbol_name (im->name));
-  mdebug_dump_mtext (im_info->title, 0, 0);
-  if (im->name != Mnil)
-    {
-      MPlist *state;
+    @c DEFAULT-VALUE is the default value of the variable.  It is a
+    symbol, integer, or M-text.
 
-      MPLIST_DO (state, im_info->states)
-       {
-         fprintf (stderr, "\n%s  ", prefix);
-         dump_im_state (MPLIST_VAL (state), indent + 2);
-       }
-    }
-  fprintf (stderr, ")");
-  return im;
-}
+    @c VALUEs (if any) specifies the possible values of the variable.
+    If @c DEFAULT-VALUE is an integer, @c VALUE may be a plist (@c FROM
+    @c TO), where @c FROM and @c TO specifies a range of possible
+    values.
+
+    For instance, suppose an input method has the variables:
+
+    @li name:intvar, description:"value is an integer",
+         initial value:0, value-range:0..3,10,20
+
+    @li name:symvar, description:"value is a symbol",
+         initial value:nil, value-range:a, b, c, nil
+
+    @li name:txtvar, description:"value is an M-text",
+         initial value:empty text, no value-range (i.e. any text)
+
+    Then, the returned plist is as follows.
+
+@verbatim
+    (intvar ("value is an integer" 0 (0 3) 10 20)
+     symvar ("value is a symbol" nil a b c nil)
+     txtvar ("value is an M-text" ""))
+@endverbatim
+
+    @return
+    If the input method uses any variables, a pointer to #MPlist is
+    returned.  As the plist is kept in the library, the caller must not
+    modify nor free it.  If the input method does not use any
+    variable, @c NULL is returned.  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¥ê¥¹¥È¤òÆÀ¤ë.
 
+    ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
+    ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È
+    (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(#m17nPlist) °Ê
+    ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£
+
+@verbatim
+    (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
+     VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] )
+     ...)
+@endverbatim
+
+    @c VARNAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
+
+    @c DOC-MTEXT ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£
+
+    @c DEFAULT-VALUE ¤ÏÊÑ¿ô¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤǤ¢¤ê¡¢¥·¥ó¥Ü¥ë¡¢À°¿ô¤â¤·¤¯¤Ï
+    M-text ¤Ç¤¢¤ë¡£
+
+    @c VALUE ¤Ï¡¢¤â¤·»ØÄꤵ¤ì¤Æ¤¤¤ì¤ÐÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò¼¨¤¹¡£¤â¤·
+    @c DEFAULT-VALUE ¤¬À°¿ô¤Ê¤é¡¢ @c VALUE ¤Ï (@c FROM @c TO) ¤È¤¤¤¦·Á
+    ¤Î¥ê¥¹¥È¤Ç¤âÎɤ¤¡£¤³¤Î¾ì¹ç @c FROM ¤È @c TO ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹¡£
+
+    Îã¤È¤·¤Æ¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤¬¼¡¤Î¤è¤¦¤ÊÊÑ¿ô¤ò»ý¤Ä¾ì¹ç¤ò¹Í¤¨¤è¤¦¡£
+
+    @li name:intvar, ÀâÌÀ:"value is an integer",
+        ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20
+
+    @li name:symvar, ÀâÌÀ:"value is a symbol",
+         ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil
+
+    @li name:txtvar, ÀâÌÀ:"value is an M-text",
+        ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä)
+
+    ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
+
+@verbatim
+    (intvar ("value is an integer" 0 (0 3) 10 20)
+     symvar ("value is a symbol" nil a b c nil)
+     txtvar ("value is an M-text" ""))
+@endverbatim
+
+    @return 
+    ÆþÎϥ᥽¥Ã¥É¤¬²¿¤é¤«¤ÎÊÑ¿ô¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð #MPlist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
+    ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+    ÆþÎϥ᥽¥Ã¥É¤¬ÊÑ¿ô¤ò°ìÀÚ»ÈÍѤ·¤Æ¤Ê¤±¤ì¤Ð¡¢@c NULL ¤òÊÖ¤¹¡£  */
+
+MPlist *
+minput_get_variables (MSymbol language, MSymbol name)
+{
+  MInputMethodInfo *im_info;
+  MPlist *vars;
+
+  MINPUT__INIT ();
+
+  im_info = get_im_info (language, name, Mnil, Mvariable);
+  if (! im_info || ! im_info->configured_vars)
+    return NULL;
+
+  M17N_OBJECT_UNREF (im_info->bc_vars);
+  im_info->bc_vars = mplist ();
+  MPLIST_DO (vars, im_info->configured_vars)
+    {
+      MPlist *plist = MPLIST_PLIST (vars);
+      MPlist *elt = mplist ();
+
+      mplist_push (im_info->bc_vars, Mplist, elt);
+      mplist_add (elt, Msymbol, MPLIST_SYMBOL (plist));
+      elt = MPLIST_NEXT (elt);
+      mplist_set (elt, Mplist, mplist_copy (MPLIST_NEXT (plist)));
+      M17N_OBJECT_UNREF (elt);
+    }
+  return im_info->bc_vars;
+}
+
+/*=*/
+
+/***en
+    @brief Set the initial value of an input method variable.
+
+    The minput_set_variable () function sets the initial value of
+    input method variable $VARIABLE to $VALUE for the input method
+    specified by $LANGUAGE and $NAME.
+
+    By default, the initial value is 0.
+
+    This setting gets effective in a newly opened input method.
+
+    @return
+    If the operation was successful, 0 is returned.  Otherwise -1 is
+    returned, and #merror_code is set to #MERROR_IM.  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë.
+
+    ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME 
+    ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE
+    ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£
+
+    ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃͤϠ0 ¤Ç¤¢¤ë¡£
+
+    ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£
+
+    @return
+    ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
+    #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
+
+int
+minput_set_variable (MSymbol language, MSymbol name,
+                    MSymbol variable, void *value)
+{
+  MPlist *plist, *pl;
+  MInputMethodInfo *im_info;
+  int ret;
+
+  MINPUT__INIT ();
+
+  if (variable == Mnil)
+    MERROR (MERROR_IM, -1);
+  plist = minput_get_variable (language, name, variable);
+  plist = MPLIST_PLIST (plist);
+  plist = MPLIST_NEXT (plist);
+  pl = mplist ();
+  mplist_add (pl, MPLIST_KEY (plist), value);
+  ret = minput_config_variable (language, name, variable, pl);
+  M17N_OBJECT_UNREF (pl);
+  if (ret == 0)
+    {
+      im_info = get_im_info (language, name, Mnil, Mvariable);
+      im_info->tick = 0;
+    }
+  return ret;
+}
+
+/*=*/
+
+/***en
+    @brief Get information about input method commands.
+
+    The minput_get_commands () function returns information about
+    input method commands of the input method specified by $LANGUAGE
+    and $NAME.  An input method command is a pseudo key event to which
+    one or more actual input key sequences are assigned.
+
+    There are two kinds of commands, global and local.  Global
+    commands are used by multiple input methods for the same purpose,
+    and have global key assignments.  Local commands are used only by
+    a specific input method, and have only local key assignments.
+
+    Each input method may locally change key assignments for global
+    commands.  The global key assignment for a global command is
+    effective only when the current input method does not have local
+    key assignments for that command.
+
+    If $NAME is #Mnil, information about global commands is returned.
+    In this case $LANGUAGE is ignored.
+
+    If $NAME is not #Mnil, information about those commands that have
+    local key assignments in the input method specified by $LANGUAGE
+    and $NAME is returned.
+
+    @return
+    If no input method commands are found, this function returns @c NULL.
+
+    Otherwise, a pointer to a plist is returned.  The key of each
+    element in the plist is a symbol representing a command, and the
+    value is a plist of the form COMMAND-INFO described below.
+
+    The first element of COMMAND-INFO has the key #Mtext, and the
+    value is an M-text describing the command.
+
+    If there are no more elements, that means no key sequences are
+    assigned to the command.  Otherwise, each of the remaining
+    elements has the key #Mplist, and the value is a plist whose keys are
+    #Msymbol and values are symbols representing input keys, which are
+    currently assigned to the command.
+
+    As the returned plist is kept in the library, the caller must not
+    modify nor free it.  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë.
+
+    ´Ø¿ô minput_get_commands () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ
+    ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã
+    ¥É¥³¥Þ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢¤½¤ì¤¾¤ì¤Ë£±¤Ä°Ê¾å¤Î¼ÂºÝ¤Î
+    ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¤â¤Î¤ò»Ø¤¹¡£
+
+    ¥³¥Þ¥ó¥É¤Ë¤Ï¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É
+    ¤ÏÊ£¿ô¤ÎÆþÎϥ᥽¥Ã¥É¤Ë¤ª¤¤¤Æ¡¢Æ±¤¸ÌÜŪ¤Ç¡¢¥°¥í¡¼¥Ð¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ
+    ¤ÇÍѤ¤¤é¤ì¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤ÏÆÃÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Î¤ß¡¢¥í¡¼¥«¥ë
+    ¤Ê¥­¡¼³äÅö¤Ç»ÈÍѤµ¤ì¤ë¡£
+
+    ¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ï¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Î¥­¡¼³äÅö¤òÊѹ¹¤¹¤ë¤³¤È¤â¤Ç
+    ¤­¤ë¡£¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥ÉÍѤΥ°¥í¡¼¥Ð¥ë¥­¡¼³ä¤êÅö¤Æ¤Ï¡¢»ÈÍѤ¹¤ëÆþÎÏ
+    ¥á¥½¥Ã¥É¤Ë¤ª¤¤¤Æ¤½¤Î¥³¥Þ¥ó¥ÉÍÑ¤Î¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤¬Â¸ºß¤·¤Ê¤¤¾ì¹ç
+    ¤Ë¤Î¤ßÍ­¸ú¤Ç¤¢¤ë¡£
+
+    $NAME ¤¬ #Mnil ¤Ç¤¢¤ì¤Ð¡¢¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤³¤Î
+    ¾ì¹ç¡¢$LANGUAGE ¤Ï̵»ë¤µ¤ì¤ë¡£
+
+    $NAME ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþ
+    Îϥ᥽¥Ã¥É¤ËÃÖ¤±¤ë¥í¡¼¥«¥ë¤Ê¥­¡¼³ä¤êÅö¤Æ¤ò»ý¤Ä¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó
+    ¤òÊÖ¤¹¡£
+
+    @return
+    ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤¬¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï @c NULL ¤òÊÖ¤¹¡£
+
+    ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹¥È¤Î³ÆÍ×ÁǤÎ
+    ¥­¡¼¤Ï¸Ä¡¹¤Î¥³¥Þ¥ó¥É¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢Ãͤϲ¼µ­¤Î COMMAND-INFO
+    ¤Î·Á¼°¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ç¤¢¤ë¡£
+
+    COMMAND-INFO ¤ÎÂè°ìÍ×ÁǤΥ­¡¼¤Ï #Mtext ¤Þ¤¿¤Ï #Msymbol ¤Ç¤¢¤ë¡£¥­¡¼
+    ¤¬ #Mtext ¤Ê¤é¡¢ÃͤϤ½¤Î¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£¥­¡¼¤¬
+    #Msymbol ¤Ê¤éÃͤϠ#Mnil ¤Ç¤¢¤ê¡¢¤³¤Î¥³¥Þ¥ó¥É¤ÏÀâÌÀ¥Æ¥­¥¹¥È¤ò»ý¤¿¤Ê
+    ¤¤¤³¤È¤Ë¤Ê¤ë¡£
+
+    ¤½¤ì°Ê³°¤ÎÍ×ÁǤ¬Ìµ¤±¤ì¤Ð¡¢¤³¤Î¥³¥Þ¥ó¥É¤ËÂФ·¤Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬³ä
+    ¤êÅö¤Æ¤é¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤ò°ÕÌ£¤¹¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢»Ä¤ê¤Î³ÆÍ×ÁǤϥ­
+    ¡¼¤È¤·¤Æ#Mplist ¤ò¡¢ÃͤȤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò»ý¤Ä¡£¤³¤Î¥×¥í¥Ñ¥Æ¥£
+    ¥ê¥¹¥È¤Î¥­¡¼¤Ï #Msymbol ¤Ç¤¢¤ê¡¢Ãͤϸ½ºß¤½¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì
+    ¤Æ¤¤¤ëÆþÎÏ¥­¡¼¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
+
+    ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð
+    ¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£*/
+
+MPlist *
+minput_get_commands (MSymbol language, MSymbol name)
+{
+  MInputMethodInfo *im_info;
+  MPlist *cmds;
+
+  MINPUT__INIT ();
+
+  im_info = get_im_info (language, name, Mnil, Mcommand);
+  if (! im_info || ! im_info->configured_vars)
+    return NULL;
+  M17N_OBJECT_UNREF (im_info->bc_cmds);
+  im_info->bc_cmds = mplist ();
+  MPLIST_DO (cmds, im_info->configured_cmds)
+    {
+      MPlist *plist = MPLIST_PLIST (cmds);
+      MPlist *elt = mplist ();
+
+      mplist_push (im_info->bc_cmds, Mplist, elt);
+      mplist_add (elt, MPLIST_SYMBOL (plist),
+                 mplist_copy (MPLIST_NEXT (plist)));
+      M17N_OBJECT_UNREF (elt);
+    }
+  return im_info->bc_cmds;
+}
+
+/*=*/
+
+/***en
+    @brief Assign a key sequence to an input method command (obsolete).
+
+    This function is obsolete.  Use minput_config_command () instead.
+
+    The minput_assign_command_keys () function assigns input key
+    sequence $KEYSEQ to input method command $COMMAND for the input
+    method specified by $LANGUAGE and $NAME.  If $NAME is #Mnil, the
+    key sequence is assigned globally no matter what $LANGUAGE is.
+    Otherwise the key sequence is assigned locally.
+
+    Each element of $KEYSEQ must have the key $Msymbol and the value
+    must be a symbol representing an input key.
+
+    $KEYSEQ may be @c NULL, in which case, all assignments are deleted
+    globally or locally.
+
+    This assignment gets effective in a newly opened input method.
+
+    @return
+    If the operation was successful, 0 is returned.  Otherwise -1 is
+    returned, and #merror_code is set to #MERROR_IM.  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É¤Ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤ò³ä¤êÅö¤Æ¤ë.
+
+    ´Ø¿ô minput_assign_command_keys () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ
+    »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥ÉÍѤÎÆþÎϥ᥽¥Ã¥É¥³¥Þ¥ó¥É $COMMAND ¤ËÂФ·¤Æ¡¢
+    ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹ $KEYSEQ ¤ò³ä¤êÅö¤Æ¤ë¡£ $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢
+    $LANGUAGE ¤Ë´Ø·¸¤Ê¤¯¡¢ÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥°¥í¡¼¥Ð¥ë¤Ë³ä¤êÅö¤Æ¤é
+    ¤ì¤ë¡£¤½¤¦¤Ç¤Ê¤ì¤Ð¡¢³ä¤êÅö¤Æ¤Ï¥í¡¼¥«¥ë¤Ç¤¢¤ë¡£
+
+    $KEYSEQ ¤Î³ÆÍ×ÁǤϥ­¡¼¤È¤·¤Æ $Msymbol ¤ò¡¢ÃͤȤ·¤ÆÆþÎÏ¥­¡¼¤òɽ¤¹¥·
+    ¥ó¥Ü¥ë¤ò»ý¤¿¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+
+    $KEYSEQ ¤Ï @c NULL ¤Ç¤â¤è¤¤¡£¤³¤Î¾ì¹ç¡¢¥°¥í¡¼¥Ð¥ë¤â¤·¤¯¤Ï¥í¡¼¥«¥ë¤Ê
+    ¤¹¤Ù¤Æ¤Î³ä¤êÅö¤Æ¤¬¾Ãµî¤µ¤ì¤ë¡£
+
+    ¤³¤Î³ä¤êÅö¤Æ¤Ï¡¢³ä¤êÅö¤Æ°Ê¹ß¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­
+    ¸ú¤Ë¤Ê¤ë¡£
+
+    @return ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢
+    #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£  */
+
+int
+minput_assign_command_keys (MSymbol language, MSymbol name,
+                           MSymbol command, MPlist *keyseq)
+{
+  int ret;
+
+  MINPUT__INIT ();
+
+  if (command == Mnil)
+    MERROR (MERROR_IM, -1);
+  if (keyseq)
+    {
+      MPlist *plist;
+
+      if  (! check_command_keyseq (keyseq))
+       MERROR (MERROR_IM, -1);
+      plist = mplist ();
+      mplist_add (plist, Mplist, keyseq);
+      keyseq = plist;
+    }  
+  else
+    keyseq = mplist ();
+  ret = minput_config_command (language, name, command, keyseq);
+  M17N_OBJECT_UNREF (keyseq);
+  return ret;
+}
+
+/*** @} */
+/*=*/
+/*** @addtogroup m17nDebug */
+/*=*/
+/*** @{  */
+/*=*/
+
+/***en
+    @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.
+
+    @return
+    This function returns $IM.  */
+/***ja
+    @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
+
+    ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ò stderr 
+    ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
+
+    @return
+    ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
+
+MInputMethod *
+mdebug_dump_im (MInputMethod *im, int indent)
+{
+  MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
+  char *prefix;
+
+  prefix = (char *) alloca (indent + 1);
+  memset (prefix, 32, indent);
+  prefix[indent] = '\0';
+
+  fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
+          msymbol_name (im->name));
+  mdebug_dump_mtext (im_info->title, 0, 0);
+  if (im->name != Mnil)
+    {
+      MPlist *state;
+
+      MPLIST_DO (state, im_info->states)
+       {
+         fprintf (stderr, "\n%s  ", prefix);
+         dump_im_state (MPLIST_VAL (state), indent + 2);
+       }
+    }
+  fprintf (stderr, ")");
+  return im;
+}
+
+/*** @} */ 
 /*** @} */ 
 
 /*