Update copyright years
[m17n/m17n-lib.git] / src / plist.c
index 4feaaf9..1e449db 100644 (file)
@@ -1,5 +1,5 @@
 /* plist.c -- plist module.
 /* plist.c -- plist module.
-   Copyright (C) 2003, 2004
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
      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
 
    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
    02111-1307, USA.  */
 
 /***en
 
     If the key of a property is a @e managing @e key, its @e value is
     a @e managed @e object.  A property list itself is a managed
 
     If the key of a property is a @e managing @e key, its @e value is
     a @e managed @e object.  A property list itself is a managed
-    objects.  */
+    objects.
+
+    If each key of a plist is one of #Msymbol, #Mtext, #Minteger, and
+    #Mplist, the plist is called as @e well-formed and represented by
+    the following notation in the documentation.
+
+@verbatim
+      PLIST ::= '(' ELEMENT * ')'
+
+      ELEMENT ::= INTEGER | SYMBOL | M-TEXT | PLIST
+
+      M-TEXT ::= '"' text data ... '"'
+@endverbatim
+
+    For instance, if a plist has four elements; integer -20, symbol of
+    name "sym", M-text of contents "abc", and plist of integer 10 and
+    symbol of name "another-symbol", it is represented as this:
+
+      (-20 sym "abc" (10 another-symbol))
+
+  */
+/***ja
+    @addtogroup m17nPlist
+
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤È¤½¤ì¤Ë´Ø¤¹¤ë API.
+
+    @e ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È (¤Þ¤¿¤Ï @e plist) ¤Ï 0 
+    ¸Ä°Ê¾å¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥ê¥¹¥È¤Ç¤¢¤ë¡£¥×¥í¥Ñ¥Æ¥£¤Ï @e ¥­¡¼ ¤È @e ÃÍ 
+    ¤«¤é¤Ê¤ë¡£¥­¡¼¤Ï¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢ÃͤϠ<tt>(void *)</tt> 
+    ¤Ë¥­¥ã¥¹¥È¤Ç¤­¤ë¤â¤Î¤Ê¤é¤Ð²¿¤Ç¤âÎɤ¤¡£
+
+    ¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤¬ @e ´ÉÍý¥­¡¼ ¤Ê¤é¤Ð¡¢¤½¤Î @e ÃÍ ¤Ï @e ´ÉÍý²¼
+    @e ¥ª¥Ö¥¸¥§¥¯¥È 
+    ¤Ç¤¢¤ë¡£¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¼«ÂΤâ´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë¡£  */
 
 /*=*/
 
 
 /*=*/
 
@@ -42,7 +75,9 @@
 
 #include <stdio.h>
 #include <string.h>
 
 #include <stdio.h>
 #include <string.h>
+#include <ctype.h>
 
 
+#include "config.h"
 #include "m17n.h"
 #include "m17n-misc.h"
 #include "internal.h"
 #include "m17n.h"
 #include "m17n-misc.h"
 #include "internal.h"
@@ -94,7 +129,8 @@ free_plist (void *object)
   do {
     MPlist *next = plist->next;
 
   do {
     MPlist *next = plist->next;
 
-    if (MPLIST_KEY (plist) != Mnil && MPLIST_KEY (plist)->managing_key)
+    if (MPLIST_KEY (plist) != Mnil
+       && MPLIST_KEY (plist)->managing_key)
       M17N_OBJECT_UNREF (MPLIST_VAL (plist));
     M17N_OBJECT_UNREGISTER (plist_table, plist);
     free (plist);
       M17N_OBJECT_UNREF (MPLIST_VAL (plist));
     M17N_OBJECT_UNREGISTER (plist_table, plist);
     free (plist);
@@ -137,12 +173,9 @@ get_byte (MStream *st)
   return st->buffer[0];
 }
 
   return st->buffer[0];
 }
 
-#define GETC(st)       \
-  ((st)->p < (st)->pend ? *(st)->p++ : get_byte (st))
+#define GETC(st) ((st)->p < (st)->pend ? *(st)->p++ : get_byte (st))
 
 
-
-#define UNGETC(c, st)  \
-  (*--(st)->p = (c))
+#define UNGETC(c, st) (--((st)->p))
 
 /** Mapping table for reading a number.  Hexadecimal chars
     (0..9,A..F,a..F) are mapped to the corresponding numbers.
 
 /** Mapping table for reading a number.  Hexadecimal chars
     (0..9,A..F,a..F) are mapped to the corresponding numbers.
@@ -195,35 +228,28 @@ read_hexadesimal (MStream *st)
 /** Read an M-text element from ST, and add it to LIST.  Return a list
     for the next element.  */
 
 /** Read an M-text element from ST, and add it to LIST.  Return a list
     for the next element.  */
 
+#define READ_MTEXT_BUF_SIZE 256
+
 static MPlist *
 static MPlist *
-read_mtext_element (MPlist *plist, MStream *st)
+read_mtext_element (MPlist *plist, MStream *st, int skip)
 {
 {
-  unsigned char buffer[1024];
-  int bufsize = 1024;
-  unsigned char *buf = buffer;
+  unsigned char buffer[READ_MTEXT_BUF_SIZE], *buf = buffer;
+  int nbytes = READ_MTEXT_BUF_SIZE;
   int c, i;
 
   i = 0;
   while ((c = GETC (st)) != EOF && c != '"')
     {
   int c, i;
 
   i = 0;
   while ((c = GETC (st)) != EOF && c != '"')
     {
-      if (i + MAX_UTF8_CHAR_BYTES >= bufsize)
-       {
-         bufsize *= 2;
-         if (buf == buffer)
-           {
-             MTABLE_MALLOC (buf, bufsize, MERROR_PLIST);
-             memcpy (buf, buffer, i);
-           }
-         else
-           MTABLE_REALLOC (buf, bufsize, MERROR_PLIST);
-       }
+      int is_char = 0;
 
       if (c == '\\')
        {
          c = GETC (st);
          if (c == EOF)
            break;
 
       if (c == '\\')
        {
          c = GETC (st);
          if (c == EOF)
            break;
-         if (c == 'x')
+         if (c == '\n')
+           continue;
+         if (c == 'x' || c == 'u')
            {
              int next_c;
 
            {
              int next_c;
 
@@ -231,18 +257,45 @@ read_mtext_element (MPlist *plist, MStream *st)
              next_c = GETC (st);
              if (next_c != ' ')
                UNGETC (next_c, st);
              next_c = GETC (st);
              if (next_c != ' ')
                UNGETC (next_c, st);
+             if (c >= 0x80)
+               is_char = 1;
            }
          else
            c = escape_mnemonic[c];
        }
 
            }
          else
            c = escape_mnemonic[c];
        }
 
-      buf[i++] = c;
+      if (! skip)
+       {
+         if (i + MAX_UTF8_CHAR_BYTES >= nbytes)
+           {
+             if (buf == buffer)
+               {
+                 nbytes *= 2;
+                 buf = malloc (nbytes);
+                 memcpy (buf, buffer, i);
+               }
+             else
+               {
+                 nbytes += READ_MTEXT_BUF_SIZE;
+                 buf = realloc (buf, nbytes);
+               }
+           }
+
+         if (is_char)
+           i += CHAR_STRING_UTF8 (c, buf);
+         else
+           buf[i++] = c;
+       }
     }
 
     }
 
-  MPLIST_SET_ADVANCE (plist, Mtext,
-                     mtext__from_data (buf, i, MTEXT_FORMAT_UTF_8, 1));
-  if (buf != buffer)
-    free (buf);
+  if (! skip)
+    {
+      MText *mt = mtext__from_data (buf, i, MTEXT_FORMAT_UTF_8,
+                                   (buf == buffer));
+      if (buf != buffer)
+       mt->allocated = nbytes;
+      MPLIST_SET_ADVANCE (plist, Mtext, mt);
+    }
   return plist;
 }
 
   return plist;
 }
 
@@ -270,22 +323,80 @@ read_character (MStream *st, int c)
 }
 
 
 }
 
 
+/** Read a symbol element from ST, and add it to LIST.  Return a list
+    for the next element.  */
+
+static MPlist *
+read_symbol_element (MPlist *plist, MStream *st, int c, int skip)
+{
+  unsigned char buffer[1024];
+  int bufsize = 1024;
+  unsigned char *buf = buffer;
+  int i;
+
+  i = 0;
+  while (c != EOF
+        && c > ' '
+        && c != ')' && c != '(' && c != '"')
+    {
+      if (i >= bufsize)
+       {
+         bufsize *= 2;
+         if (buf == buffer)
+           {
+             MTABLE_MALLOC (buf, bufsize, MERROR_PLIST);
+             memcpy (buf, buffer, i);
+           }
+         else
+           MTABLE_REALLOC (buf, bufsize, MERROR_PLIST);
+       }
+      if (c == '\\')
+       {
+         c = GETC (st);
+         if (c == EOF)
+           break;
+         c = escape_mnemonic[c];
+       }
+      if (! skip)
+       buf[i++] = c;
+      c = GETC (st);
+    }
+
+  if (c > ' ')
+    UNGETC (c, st);
+  if (! skip)
+    {
+      buf[i] = 0;
+      MPLIST_SET_ADVANCE (plist, Msymbol, msymbol ((char *) buf));
+      if (buf != buffer)
+       free (buf);
+    }
+  return plist;
+}
+
 /** Read an integer element from ST, and add it to LIST.  Return a
     list for the next element.  It is assumed that we have already
     read the character C. */
 
 static MPlist *
 /** Read an integer element from ST, and add it to LIST.  Return a
     list for the next element.  It is assumed that we have already
     read the character C. */
 
 static MPlist *
-read_integer_element (MPlist *plist, MStream *st, int c)
+read_integer_element (MPlist *plist, MStream *st, int c, int skip)
 {
   int num;
 
 {
   int num;
 
-  if (c == '0' || c == '#')
+  if (c == '#')
     {
       c = GETC (st);
     {
       c = GETC (st);
-      if (c == 'x')
-       num = read_hexadesimal (st);
-      else
-       num = read_decimal (st, c);
+      if (c != 'x')
+       {
+         UNGETC (c, st);
+         return read_symbol_element (plist, st, '#', skip);
+       }
+      num = read_hexadesimal (st);
+    }
+  else if (c == '0')
+    {
+      c = GETC (st);
+      num = (c == 'x' ? read_hexadesimal (st) : read_decimal (st, c));
     }
   else if (c == '?')
     {
     }
   else if (c == '?')
     {
@@ -311,57 +422,20 @@ read_integer_element (MPlist *plist, MStream *st, int c)
        }
     }
   else if (c == '-')
        }
     }
   else if (c == '-')
-    num = - read_decimal (st, GETC (st));
-  else
-    num = read_decimal (st, c);
-
-  MPLIST_SET_ADVANCE (plist, Minteger, (void *) num);
-  return plist;
-}
-
-/** Read a symbol element from ST, and add it to LIST.  Return a list
-    for the next element.  */
-
-static MPlist *
-read_symbol_element (MPlist *plist, MStream *st)
-{
-  unsigned char buffer[1024];
-  int bufsize = 1024;
-  unsigned char *buf = buffer;
-  int c, i;
-
-  i = 0;
-  while ((c = GETC (st)) != EOF
-        && c > ' '
-        && c != ')' && c != '(' && c != '"')
     {
     {
-      if (i >= bufsize)
-       {
-         bufsize *= 2;
-         if (buf == buffer)
-           {
-             MTABLE_MALLOC (buf, bufsize, MERROR_PLIST);
-             memcpy (buf, buffer, i);
-           }
-         else
-           MTABLE_REALLOC (buf, bufsize, MERROR_PLIST);
-       }
-      if (c == '\\')
+      c = GETC (st);
+      if (c < '0' || c > '9')
        {
        {
-         c = GETC (st);
-         if (c == EOF)
-           break;
-         c = escape_mnemonic[c];
+         UNGETC (c, st);
+         return read_symbol_element (plist, st, '-', skip);
        }
        }
-      buf[i++] = c;
+      num = - read_decimal (st, c);
     }
     }
+  else
+    num = read_decimal (st, c);
 
 
-  buf[i] = 0;
-  MPLIST_SET_ADVANCE (plist, Msymbol, msymbol ((char *) buf));
-  if (buf != buffer)
-    free (buf);
-  if (c > ' ')
-    UNGETC (c, st);
+  if (! skip)
+    MPLIST_SET_ADVANCE (plist, Minteger, (void *) num);
   return plist;
 }
 
   return plist;
 }
 
@@ -373,10 +447,14 @@ read_symbol_element (MPlist *plist, MStream *st)
        '0'..'9', '-': integer
        '?': integer representing character code
        the other ASCII letters: symbol
        '0'..'9', '-': integer
        '?': integer representing character code
        the other ASCII letters: symbol
-*/
+
+   If KEYS is not NULL, it is a plist contains target keys and stop
+   keys.  In this caes, read only a plist whose key has value 1 in
+   KEYS, and return NULL when we encounter a plist whose key has value
+   0 in KEYS while skipping any other elements.  */
 
 static MPlist *
 
 static MPlist *
-read_element (MPlist *plist, MStream *st)
+read_element (MPlist *plist, MStream *st, MPlist *keys)
 {
   int c;
 
 {
   int c;
 
@@ -397,45 +475,99 @@ read_element (MPlist *plist, MStream *st)
 
       MPLIST_NEW (pl);
       p = pl;
 
       MPLIST_NEW (pl);
       p = pl;
-      while ((p = read_element (p, st)));
-      MPLIST_SET_ADVANCE (plist, Mplist, pl);
+      p = read_element (p, st, NULL);
+      if (keys && p && MPLIST_SYMBOL_P (pl))
+       {
+         if (MPLIST_TAIL_P (keys))
+           {
+             while ((p = read_element (p, st, NULL)));
+             MPLIST_SET_ADVANCE (plist, Mplist, pl);
+             return NULL;
+           }
+         else
+           {
+             MPlist *p0 = keys;
+
+             MPLIST_FIND (p0, MPLIST_SYMBOL (pl));
+             if (! MPLIST_TAIL_P (p0) && ! MPLIST_VAL (p0))
+               {
+                 M17N_OBJECT_UNREF (pl);
+                 return NULL;
+               }
+             while ((p = read_element (p, st, NULL)));
+             if (! MPLIST_TAIL_P (p0))
+               {
+                 MPLIST_SET_ADVANCE (plist, Mplist, pl);
+                 return NULL;
+               }
+             else
+               M17N_OBJECT_UNREF (pl);
+           }
+       }
+      else
+       {
+         if (p)
+           while ((p = read_element (p, st, NULL)));
+         MPLIST_SET_ADVANCE (plist, Mplist, pl);
+       }
       return plist;
     }
   if (c == '"')
       return plist;
     }
   if (c == '"')
-    return read_mtext_element (plist, st);
+    return (read_mtext_element (plist, st, keys ? 1 : 0));
   if ((c >= '0' && c <= '9') || c == '-' || c == '?' || c == '#')
   if ((c >= '0' && c <= '9') || c == '-' || c == '?' || c == '#')
-    return read_integer_element (plist, st, c);
+    return (read_integer_element (plist, st, c, keys ? 1 : 0));
   if (c == EOF || c == ')')
     return NULL;
   if (c == EOF || c == ')')
     return NULL;
-  UNGETC (c, st);
-  return read_symbol_element (plist, st);
+  return (read_symbol_element (plist, st, c, keys ? 1 : 0));
 }
 
 }
 
-void
-write_element (MText *mt, MPlist *plist)
+#define PUTC(MT, C)                    \
+  do {                                 \
+    if (MT)                            \
+      mtext_cat_char ((MT), (C));      \
+    else                               \
+      putc ((C), mdebug__output);      \
+  } while (0);
+
+#define PUTS(MT, STR)                  \
+  do {                                 \
+    if (MT)                            \
+      MTEXT_CAT_ASCII ((MT), (STR));   \
+    else                               \
+      fputs ((STR), mdebug__output);   \
+  } while (0)
+
+
+static void 
+write_symbol (MText *mt, MSymbol sym)
 {
 {
-  if (MPLIST_SYMBOL_P (plist))
+  if (sym == Mnil)
+    {
+      PUTS (mt, "nil");
+    }
+  else
     {
     {
-      MSymbol sym = MPLIST_SYMBOL (plist);
+      char *name = MSYMBOL_NAME (sym);
 
 
-      if (sym == Mnil)
+      if (isdigit (*name))
+       PUTC (mt, '\\');
+      while (*name)
        {
        {
-         MTEXT_CAT_ASCII (mt, "nil");
+         if (*name <= ' ' || *name == '\\' || *name == '"'
+             || *name == '(' || *name == ')')
+           PUTC (mt, '\\');
+         PUTC (mt, *name); 
+         name++;
        }
        }
-      else
-       {
-         char *name = MSYMBOL_NAME (sym);
-         char *buf = alloca (MSYMBOL_NAMELEN (sym) * 2 + 1), *p = buf;
+    }
+}
 
 
-         while (*name)
-           {
-             if (*name <= ' ' || *name == '"' || *name == ')' || *name == ')')
-               *p++ = '\\';
-             *p++ = *name++;
-           }
-         *p = '\0';
-         MTEXT_CAT_ASCII (mt, buf);
-       }
+static void
+write_element (MText *mt, MPlist *plist, int indent)
+{
+  if (MPLIST_SYMBOL_P (plist))
+    {
+      write_symbol (mt, MPLIST_SYMBOL (plist));
     }
   else if (MPLIST_INTEGER_P (plist))
     {
     }
   else if (MPLIST_INTEGER_P (plist))
     {
@@ -443,91 +575,122 @@ write_element (MText *mt, MPlist *plist)
       char buf[128];
 
       sprintf (buf, "%d", num);
       char buf[128];
 
       sprintf (buf, "%d", num);
-      MTEXT_CAT_ASCII (mt, buf);
+      PUTS (mt, buf);
     }
     }
-  else if (MPLIST_PLIST_P (plist))
+  else if (MPLIST_PLIST_P (plist)
+          || MPLIST_NESTED_P (plist))
     {
       MPlist *pl;
     {
       MPlist *pl;
+      int newline = 0;
 
 
+      if (MPLIST_NESTED_P (plist))
+       {
+         write_symbol (mt, MPLIST_KEY (plist));
+         PUTC (mt, ':');
+       }
       plist = MPLIST_PLIST (plist);
       plist = MPLIST_PLIST (plist);
-      mtext_cat_char (mt, '(');
+      PUTC (mt, '(');
+      if (indent >= 0)
+       indent++;
       MPLIST_DO (pl, plist)
        {
          if (pl != plist)
       MPLIST_DO (pl, plist)
        {
          if (pl != plist)
-           mtext_cat_char (mt, ' ');
-         write_element (mt, pl);
+           {
+             if (indent > 0 && (MPLIST_PLIST_P (pl) || MPLIST_MTEXT_P (pl)))
+               newline = 1;
+             if (newline)
+               {
+                 int i;
+
+                 PUTC (mt, '\n');
+                 for (i = 1; i < indent; i++)
+                   PUTC (mt, ' ');
+               }
+             PUTC (mt, ' ');
+           }
+         write_element (mt, pl, indent);
+         if (indent >= 0)
+           newline = (MPLIST_PLIST_P (pl) || MPLIST_MTEXT_P (pl));
        }
        }
-      mtext_cat_char (mt, ')');
+      PUTC (mt, ')');
     }
   else if (MPLIST_MTEXT_P (plist))
     {
     }
   else if (MPLIST_MTEXT_P (plist))
     {
-      mtext_cat_char (mt, '"');
-      /* Not yet implemnted */
-      mtext_cat_char (mt, '"');
-    }
-}
-
-/* Support functions for mdebug_dump_plist.  */
+      MText *this_mt = MPLIST_MTEXT (plist);
+      int from = 0, to = mtext_nchars (this_mt);
+      int stop1 = 0, stop2 = 0;
 
 
-static void
-dump_string (char *str)
-{
-  char *p = str, *pend = p + strlen (p), *new, *p1;
-
-  new = p1 = alloca ((pend - p) * 4 + 1);
-  while (p < pend)
-    {
-      if (*p < 0)
+      if (! mt && this_mt->format > MTEXT_FORMAT_UTF_8)
        {
        {
-         sprintf (p1, "\\x%02X", (unsigned char) *p);
-         p1 += 4;
+         this_mt = mtext_dup (this_mt);
+         mtext__adjust_format (this_mt, MTEXT_FORMAT_UTF_8);
        }
        }
-      else if (*p < ' ')
+
+      PUTC (mt, '"');
+      while (1)
        {
        {
-         *p1++ = '^';
-         *p1++ = *p + '@';
+         int stop, escaped;
+
+         if (from == stop1)
+           {
+             if ((stop1 = mtext_character (this_mt, from, to, '"')) < 0)
+               stop1 = to;
+           }
+         if (from == stop2)
+           {
+             if ((stop2 = mtext_character (this_mt, from, to, '\\')) < 0)
+               stop2 = to;
+           }
+         if (stop1 < stop2)
+           stop = stop1++, escaped = '"';
+         else
+           stop = stop2++, escaped = '\\';
+         if (mt)
+           mtext_copy (mt, mtext_nchars (mt), this_mt, from, stop);
+         else
+           {
+             unsigned char *data = MTEXT_DATA (this_mt);
+             unsigned char *beg = data + mtext__char_to_byte (this_mt, from);
+             unsigned char *end = data + mtext__char_to_byte (this_mt, stop);
+
+             while (beg < end)
+               putc (*beg, mdebug__output), beg++;
+           }
+         if (stop == to)
+           break;
+         PUTC (mt, '\\');
+         PUTC (mt, escaped);
+         from = stop + 1;
        }
        }
-      else if (*p == ' ')
+      PUTC (mt, '"');
+      if (this_mt != MPLIST_MTEXT (plist))
+       M17N_OBJECT_UNREF (this_mt);
+    }
+  else if (MPLIST_STRING_P (plist))
+    {
+      char *str = MPLIST_STRING (plist);
+
+      if (mt)
        {
        {
-         *p1++ = '\\';
-         *p1++ = ' ';
+         MText *this_mt = mtext__from_data (str, strlen (str),
+                                            MTEXT_FORMAT_UTF_8, 0);
+
+         mtext_copy (mt, mtext_nchars (mt),
+                     this_mt, 0, mtext_nchars (this_mt));
+         M17N_OBJECT_UNREF (this_mt);
        }
       else
        }
       else
-       *p1++ = *p;
-      p++;
+       fprintf (mdebug__output, "%s", str);
     }
     }
-  *p1 = '\0';
-  fprintf (stderr, "%s", new);
-}
-
-static void
-dump_plist_element (MPlist *plist, int indent)
-{
-  char *prefix = (char *) alloca (indent + 1);
-  MSymbol key;
-
-  memset (prefix, 32, indent);
-  prefix[indent] = 0;
-
-  key = MPLIST_KEY (plist);
-  fprintf (stderr, "(%s(#%d) ", msymbol_name (MPLIST_KEY (plist)),
-          plist->control.ref_count);
-  if (key == Msymbol)
-    dump_string (msymbol_name (MPLIST_SYMBOL (plist)));
-  else if (key == Mtext)
-    mdebug_dump_mtext (MPLIST_MTEXT (plist), indent, 0);
-  else if (key == Minteger)
-    fprintf (stderr, "%x", MPLIST_INTEGER (plist));
-  else if (key == Mstring) 
-    fprintf (stderr, "\"%s\"", MPLIST_STRING (plist));
-  else if (key == Mplist)
+  else 
     {
     {
-      fprintf (stderr, "\n%s", prefix);
-      mdebug_dump_plist (MPLIST_PLIST (plist), indent);
+      char buf[128];
+
+      write_symbol (mt, MPLIST_KEY (plist));
+      PUTC (mt, ':');
+      sprintf (buf, "%04X", (unsigned) MPLIST_VAL (plist));
+      PUTS (mt, buf);
     }
     }
-  else
-    fprintf (stderr, "0x%X", (unsigned) MPLIST_VAL (plist));
-  fprintf (stderr, ")");
 }
 
 \f
 }
 
 \f
@@ -537,7 +700,7 @@ mplist__init ()
 {
   int i;
 
 {
   int i;
 
-  plist_table.count = 0;
+  M17N_OBJECT_ADD_ARRAY (plist_table, "Plist");
 
   Minteger = msymbol ("integer");
   Mplist = msymbol_as_managing_key ("plist");
 
   Minteger = msymbol ("integer");
   Mplist = msymbol_as_managing_key ("plist");
@@ -567,7 +730,6 @@ mplist__init ()
 void
 mplist__fini (void)
 {
 void
 mplist__fini (void)
 {
-  mdebug__report_object ("Plist", &plist_table);
 }
 
 
 }
 
 
@@ -592,8 +754,10 @@ mplist__from_plist (MPlist *plist)
       key = MPLIST_SYMBOL (plist);
       plist = MPLIST_NEXT (plist);
       type = MPLIST_KEY (plist);
       key = MPLIST_SYMBOL (plist);
       plist = MPLIST_NEXT (plist);
       type = MPLIST_KEY (plist);
-      if (type->managing_key)
+      if (type->managing_key && MPLIST_VAL (plist))
        M17N_OBJECT_REF (MPLIST_VAL (plist));
        M17N_OBJECT_REF (MPLIST_VAL (plist));
+      if (type == Mplist)
+       MPLIST_SET_NESTED_P (p);
       MPLIST_SET_ADVANCE (p, key, MPLIST_VAL (plist));
       plist = MPLIST_NEXT (plist);
     }
       MPLIST_SET_ADVANCE (p, key, MPLIST_VAL (plist));
       plist = MPLIST_NEXT (plist);
     }
@@ -622,6 +786,7 @@ mplist__from_alist (MPlist *plist)
       elt = MPLIST_PLIST (plist);
       if (! MPLIST_SYMBOL_P (elt))
        MERROR (MERROR_PLIST, NULL);
       elt = MPLIST_PLIST (plist);
       if (! MPLIST_SYMBOL_P (elt))
        MERROR (MERROR_PLIST, NULL);
+      MPLIST_SET_NESTED_P (p);
       MPLIST_SET_ADVANCE (p, MPLIST_SYMBOL (elt), MPLIST_NEXT (elt));
       M17N_OBJECT_REF (MPLIST_NEXT (elt));
     }
       MPLIST_SET_ADVANCE (p, MPLIST_SYMBOL (elt), MPLIST_NEXT (elt));
       M17N_OBJECT_REF (MPLIST_NEXT (elt));
     }
@@ -630,7 +795,7 @@ mplist__from_alist (MPlist *plist)
 
 
 MPlist *
 
 
 MPlist *
-mplist__from_file (FILE *fp)
+mplist__from_file (FILE *fp, MPlist *keys)
 {
   MPlist *plist, *pl;
   MStream st;
 {
   MPlist *plist, *pl;
   MStream st;
@@ -640,7 +805,7 @@ mplist__from_file (FILE *fp)
   st.p = st.pend = st.buffer;
   MPLIST_NEW (plist);
   pl = plist;
   st.p = st.pend = st.buffer;
   MPLIST_NEW (plist);
   pl = plist;
-  while ((pl = read_element (pl, &st)));
+  while ((pl = read_element (pl, &st, keys)));
   return plist;
 }
 
   return plist;
 }
 
@@ -689,24 +854,106 @@ mplist__from_string (unsigned char *str, int n)
   st.pend = str + n;
   MPLIST_NEW (plist);
   pl = plist;
   st.pend = str + n;
   MPLIST_NEW (plist);
   pl = plist;
-  while ((pl = read_element (pl, &st)));
+  while ((pl = read_element (pl, &st, NULL)));
   return plist;
 }
 
 int
   return plist;
 }
 
 int
-mplist__serialize (MText *mt, MPlist *plist)
+mplist__serialize (MText *mt, MPlist *plist, int pretty)
 {
   MPlist *pl;
 {
   MPlist *pl;
+  int separator = pretty ? '\n' : ' ';
 
   MPLIST_DO (pl, plist)
     {
       if (pl != plist)
 
   MPLIST_DO (pl, plist)
     {
       if (pl != plist)
-       mtext_cat_char (mt, ' ');
-      write_element (mt, pl);
+       mtext_cat_char (mt, separator);
+      write_element (mt, pl, pretty ? 0 : -1);
     }
     }
+  if (pretty)
+    mtext_cat_char (mt, separator);
   return 0;
 }
 
   return 0;
 }
 
+/**en
+    @brief Concatenate two plists.
+
+    The mplist__conc () function concatenates plist $TAIL at the end of
+    plist $PLIST and return $PLIST.  If $TAIL is empty, return $PLIST
+    without modifying it.  */
+
+MPlist *
+mplist__conc (MPlist *plist, MPlist *tail)
+{
+  MPlist *pl;
+
+  if (MPLIST_TAIL_P (tail))
+    return plist;
+  MPLIST_DO (pl, plist);
+  MPLIST_KEY (pl) = MPLIST_KEY (tail);
+  MPLIST_VAL (pl) = MPLIST_VAL (tail);
+  if (MPLIST_KEY (pl)->managing_key && MPLIST_VAL (pl))
+    M17N_OBJECT_REF (MPLIST_VAL (pl));
+  if (MPLIST_NESTED_P (tail))
+    MPLIST_SET_NESTED_P (pl);
+  tail = MPLIST_NEXT (tail);
+  MPLIST_NEXT (pl) = tail;
+  M17N_OBJECT_REF (tail);
+  return plist;
+}
+
+/*=*/
+/**en
+    @brief Discard a property at the beginning of a property list.
+
+    The mplist__pop_unref () function removes a property at the
+    beginning of property list $PLIST, and if the property value is a
+    managed object, unref it.  As a result, the second key and value
+    of the original $PLIST become the first of those of the new
+    $PLIST.  */
+
+void
+mplist__pop_unref (MPlist *plist)
+{
+  MSymbol key;
+  void *val;
+
+  if (MPLIST_TAIL_P (plist))
+    return;
+  key = MPLIST_KEY (plist);
+  val = mplist_pop (plist);
+  if (key->managing_key)
+    M17N_OBJECT_UNREF (val);
+}
+
+/**en
+    @brief Search for an element of an alist represented by a plist.
+
+    The mplist__assq () function treats $PLIST as an association list
+    (elements are plists (key is #Mplist) whose first element is a
+    symbol (key is #Msymbol)), and find an element whose first element
+    has key #Msymbol and value $KEY.
+
+    Non-plist elements of $PLIST are ignored.
+
+    @return
+    This function returns a found element or NULL if no element
+    matches with $KEY.  */
+
+MPlist *
+mplist__assq (MPlist *plist, MSymbol key)
+{
+  MPLIST_DO (plist, plist)
+    if (MPLIST_PLIST_P (plist))
+      {
+       MPlist *pl = MPLIST_PLIST (plist);
+
+       if (MPLIST_SYMBOL_P (pl) && MPLIST_SYMBOL (pl) == key)
+         return plist;
+      }
+  return NULL;
+}
+
 /*** @} */
 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
 
 /*** @} */
 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
 
@@ -720,8 +967,13 @@ mplist__serialize (MText *mt, MPlist *plist)
 /***en
     @brief Symbol whose name is "integer".
 
 /***en
     @brief Symbol whose name is "integer".
 
-    The symbol @c Minteger has the name <tt>"integer"</tt>.  A value
-    of a plist whose key is @c Minteger must be an integer.  */
+    The symbol @c Minteger has the name <tt>"integer"</tt>.  The value
+    of a property whose key is @c Minteger must be an integer.  */
+/***ja
+    @brief "integer" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë.
+
+    ¥·¥ó¥Ü¥ë @c Minteger ¤Ï <tt>"integer"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¡£¥­¡¼¤¬
+    @c Minteger ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ÎÃͤÏÀ°¿ôÃͤǤʤ¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */
 
 MSymbol Minteger;
 /*=*/
 
 MSymbol Minteger;
 /*=*/
@@ -730,8 +982,14 @@ MSymbol Minteger;
     @brief Symbol whose name is "plist".
 
     The symbol @c Mplist has the name <tt>"plist"</tt>.  It is a
     @brief Symbol whose name is "plist".
 
     The symbol @c Mplist has the name <tt>"plist"</tt>.  It is a
-    managing key.  A value of a plist whose key is @c Mplist must be a
-    plist.  */
+    managing key.  A value of a property whose key is @c Mplist must
+    be a plist.  */
+/***ja
+    @brief "plist" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë.
+
+    ¥·¥ó¥Ü¥ë @c Mplist ¤Ï <tt>"plist"</tt> 
+    ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¡£¤³¤ì¤Ï´ÉÍý¥­¡¼¤Ç¤¢¤ë¡£¥­¡¼¤¬ @c Mplist 
+    ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϠplist ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */
 
 MSymbol Mplist;
 /*=*/
 
 MSymbol Mplist;
 /*=*/
@@ -740,18 +998,18 @@ MSymbol Mplist;
     @brief Symbol whose name is "mtext".
 
     The symbol @c Mtext has the name <tt>"mtext"</tt>.  It is a
     @brief Symbol whose name is "mtext".
 
     The symbol @c Mtext has the name <tt>"mtext"</tt>.  It is a
-    managing key.  A value of a plist whose key is @c Mtext must be an
+    managing key.  A value of a property whose key is @c Mtext must be an
     M-text.  */
 
 /***ja
     M-text.  */
 
 /***ja
-    @brief "text" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë
+    @brief "mtext" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë.
 
 
-    ÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë @c Mtext ¤Ï <tt>"text"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä´ÉÍý
-    ¥­¡¼¤Ç¤¢¤ë¡£ */
+    ¥·¥ó¥Ü¥ë @c Mtext ¤Ï <tt>"mtext"</tt>
+    ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä´ÉÍý¥­¡¼¤Ç¤¢¤ë¡£¥­¡¼¤¬ @c Mtext 
+    ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϠM-text ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£      */
 
 MSymbol Mtext;
 
 
 MSymbol Mtext;
 
-
 /*=*/
 /***en
     @brief Create a property list object.
 /*=*/
 /***en
     @brief Create a property list object.
@@ -764,9 +1022,19 @@ MSymbol Mtext;
 
     @errors
     This function never fails.  */
 
     @errors
     This function never fails.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òºî¤ë.
+
+    ´Ø¿ô mplist () ¤ÏŤµ 0 ¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤ò¿·¤·¤¯ºî¤Ã¤ÆÊÖ¤¹¡£
+
+    @returns
+    ¤³¤Î´Ø¿ô¤Ï¿·¤·¤¯ºî¤é¤ì¤¿¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
+
+    @errors
+    ¤³¤Î´Ø¿ô¤Ï·è¤·¤Æ¼ºÇÔ¤·¤Ê¤¤¡£     */
 
 MPlist *
 
 MPlist *
-mplist ()
+mplist (void)
 {
   MPlist *plist;
 
 {
   MPlist *plist;
 
@@ -776,17 +1044,28 @@ mplist ()
 
 /*=*/
 /***en
 
 /*=*/
 /***en
-    @brief Copy a plist.
+    @brief Copy a property list.
 
 
-    The mplist_copy () function copies $PLIST.  In the copy, the
-    values are the same as those of $PLIST.
+    The mplist_copy () function copies property list $PLIST.  In the
+    copy, the values are the same as those of $PLIST.
 
     @return
     This function returns a newly created plist which is a copy of
 
     @return
     This function returns a newly created plist which is a copy of
-    $PLIST.  */
-/***
+    $PLIST.  
+
     @errors
     This function never fails.  */ 
     @errors
     This function never fails.  */ 
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò¥³¥Ô¡¼¤¹¤ë.
+
+    ´Ø¿ô mplist_copy () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
+    ¤ò¥³¥Ô¡¼¤¹¤ë¡£¥³¥Ô¡¼¤Î¤¹¤Ù¤Æ¤ÎÃͤϥ³¥Ô¡¼¸µ $PLIST ¤ÎÃͤÈƱ¤¸¤Ç¤¢¤ë¡£
+
+    @return
+    ¤³¤Î´Ø¿ô¤Ï¿·¤·¤¯ºî¤é¤ì¤¿¡¢$PLIST ¤Î¥³¥Ô¡¼¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òÊÖ¤¹¡£    
+
+    @errors
+    ¤³¤Î´Ø¿ô¤Ï·è¤·¤Æ¼ºÇÔ¤·¤Ê¤¤¡£     */
 
 MPlist *
 mplist_copy (MPlist *plist)
 
 MPlist *
 mplist_copy (MPlist *plist)
@@ -794,16 +1073,20 @@ mplist_copy (MPlist *plist)
   MPlist *copy = mplist (), *pl = copy;
 
   MPLIST_DO (plist, plist)
   MPlist *copy = mplist (), *pl = copy;
 
   MPLIST_DO (plist, plist)
-    pl = mplist_add (pl, MPLIST_KEY (plist), MPLIST_VAL (plist));
+    {
+      if (MPLIST_NESTED_P (plist))
+       MPLIST_SET_NESTED_P (pl);
+      pl = mplist_add (pl, MPLIST_KEY (plist), MPLIST_VAL (plist));
+    }
   return copy;
 }
 
 /*=*/
 
 /***en
   return copy;
 }
 
 /*=*/
 
 /***en
-    @brief Set the value of a property in a property list object.
+    @brief Set the value of a property in a property list.
 
 
-    The mplist_put () function searches property list object $PLIST
+    The mplist_put () function searches property list $PLIST
     from the beginning for a property whose key is $KEY.  If such a
     property is found, its value is changed to $VALUE.  Otherwise, a
     new property whose key is $KEY and value is $VALUE is appended at
     from the beginning for a property whose key is $KEY.  If such a
     property is found, its value is changed to $VALUE.  Otherwise, a
     new property whose key is $KEY and value is $VALUE is appended at
@@ -818,6 +1101,22 @@ mplist_copy (MPlist *plist)
     If the operation was successful, mplist_put () returns a sublist of
     $PLIST whose first element is the just modified or added one.
     Otherwise, it returns @c NULL.  */
     If the operation was successful, mplist_put () returns a sublist of
     $PLIST whose first element is the just modified or added one.
     Otherwise, it returns @c NULL.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÀßÄꤹ¤ë.
+
+    ´Ø¿ô mplist_put () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ò»Ï¤á¤«¤éõ¤·¤Æ¡¢¥­¡¼¤¬
+    $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤ÎÃͤò $VALUE 
+    ¤ËÊѹ¹¤¹¤ë¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¥­¡¼¤¬ $KEY ¤ÇÃͤ¬ $VALUE 
+    ¤Ç¤¢¤ë¿·¤·¤¤¥×¥í¥Ñ¥Æ¥£¤¬ $PLIST ¤ÎËöÈø¤ËÄɲ䵤ì¤ë¡£$KEY ¤È $VAL
+    ¤ËÂФ¹¤ëÀ©¸Â¤Ë¤Ä¤¤¤Æ¤Ï¡¢mplist_add () ¤ÎÀâÌÀ¤ò»²¾È¡£
+
+    $KEY ¤¬´ÉÍý¥­¡¼¤Ê¤é¤Ð¡¢
+    $VAL ¤Ï´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç¡¢¸Å¤¤Ãͤλ²¾È¿ô¤Ï 
+    @c NULL ¤Ç¤Ê¤±¤ì¤Ð 1 ¸º¤é¤µ¤ì¡¢$VAL ¤Î»²¾È¿ô¤Ï 1 Áý¤ä¤µ¤ì¤ë¡£
+
+    @return 
+    ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mplist_put () ¤ÏÊѹ¹¤µ¤ì¤¿¤«Äɲ䵤줿Í×ÁǤ«¤é»Ï¤Þ¤ë
+    $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£   */
 
 MPlist *
 mplist_put (MPlist *plist, MSymbol key, void *val)
 
 MPlist *
 mplist_put (MPlist *plist, MSymbol key, void *val)
@@ -829,7 +1128,8 @@ mplist_put (MPlist *plist, MSymbol key, void *val)
     {
       if (! MPLIST_TAIL_P (plist))
        M17N_OBJECT_UNREF (MPLIST_VAL (plist));
     {
       if (! MPLIST_TAIL_P (plist))
        M17N_OBJECT_UNREF (MPLIST_VAL (plist));
-      M17N_OBJECT_REF (val);
+      if (val)
+       M17N_OBJECT_REF (val);
     }
   MPLIST_SET (plist, key, val);
   return plist;
     }
   MPLIST_SET (plist, key, val);
   return plist;
@@ -838,18 +1138,29 @@ mplist_put (MPlist *plist, MSymbol key, void *val)
 /*=*/
 
 /***en
 /*=*/
 
 /***en
-    @brief Get the value of a property in a property list object.
+    @brief Get the value of a property in a property list.
 
 
-    The mplist_get () function searches property list object $PLIST
-    from the beginning for a property whose key is $KEY.  If such a
-    property is found, a pointer to its value is returned as the type
-    of <tt>(void *)</tt>.  If not found, @c NULL is returned.
+    The mplist_get () function searches property list $PLIST from the
+    beginning for a property whose key is $KEY.  If such a property is
+    found, its value is returned as the type of <tt>(void *)</tt>.  If
+    not found, @c NULL is returned.
 
     When @c NULL is returned, there are two possibilities: one is the
     case where no property is found (see above); the other is the case
     where a property is found and its value is @c NULL.  In case that
     these two cases must be distinguished, use the mplist_find_by_key ()
     function.  */
 
     When @c NULL is returned, there are two possibilities: one is the
     case where no property is found (see above); the other is the case
     where a property is found and its value is @c NULL.  In case that
     these two cases must be distinguished, use the mplist_find_by_key ()
     function.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÆÀ¤ë.
+
+    ´Ø¿ô mplist_get () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ò»Ï¤á¤«¤éõ¤·¤Æ¡¢¥­¡¼
+    ¤¬ $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤ÎÃͤò
+    <tt>(void *)</tt> ·¿¤ÇÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
+
+    @c NULL ¤¬Ê֤俺ݤˤÏÆó¤Ä¤Î²ÄǽÀ­¤¬¤¢¤ë: 
+    ¾åµ­¤Î¤è¤¦¤Ë¥×¥í¥Ñ¥Æ¥£¤¬¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤È¡¢¥×¥í¥Ñ¥Æ¥£¤¬¸«¤Ä¤«¤ê¡¢¤½¤ÎÃͤ¬
+    @c NULL ¤Ç¤¢¤ë¾ì¹ç¤Ç¤¢¤ë¡£¤³¤ì¤é¤ò¶èÊ̤¹¤ëɬÍפ¬¤¢¤ë¾ì¹ç¤Ë¤Ï´Ø¿ô 
+    mplist_find_by_key () ¤ò»È¤¦¤³¤È¡£  */
 
 /***
     @seealso
 
 /***
     @seealso
@@ -865,11 +1176,72 @@ mplist_get (MPlist *plist, MSymbol key)
 /*=*/
 
 /***en
 /*=*/
 
 /***en
-    @brief Add a property at the end of a property list object.
+    @brief Set the value (function pointer) of a property in a property list.
+
+    The mplist_put_func () function is similar to mplist_put () but for
+    setting function pointer $FUNC in property list $PLIST for key
+    $KEY.  $KEY must not be a managing key.  */
+
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤Î¥×¥í¥Ñ¥Æ¥£¤Ë´Ø¿ô¥Ý¥¤¥ó¥¿¤Ç¤¢¤ëÃͤòÀßÄꤹ¤ë.
 
 
-    The mplist_add () function appends at the end of $PLIST a property
-    whose key is $KEY and value is $VAL.  $KEY can be any symbol
-    other than @c Mnil.
+    ´Ø¿ô mplist_put_func () ¤Ï´Ø¿ô mplist_put () Æ±ÍÍ¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST
+    Ãæ¤Ç¥­¡¼¤¬ $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ËÃͤòÀßÄꤹ¤ë¡£Ã¢¤·¤½¤ÎÃͤϴؿô¥Ý¥¤¥ó¥¿
+    $FUNC ¤Ç¤¢¤ë¡£$KEY ¤Ï´ÉÍý¥­¡¼¤Ç¤¢¤Ã¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */
+
+
+/***
+    @seealso
+    mplist_put (), M17N_FUNC ()  */
+
+MPlist *
+mplist_put_func (MPlist *plist, MSymbol key, M17NFunc func)
+{
+  if (key == Mnil || key->managing_key)
+    MERROR (MERROR_PLIST, NULL);
+  MPLIST_FIND (plist, key);
+  MPLIST_KEY (plist) = key;
+  MPLIST_FUNC (plist) = func;
+  MPLIST_SET_VAL_FUNC_P (plist);
+  if (! plist->next)
+    MPLIST_NEW ((plist)->next);
+  return plist;
+}
+
+/*=*/
+
+/***en
+    @brief Get the value (function pointer) of a property in a property list.
+
+    The mplist_get_func () function is similar to mplist_get () but for
+    getting a function pointer from property list $PLIST by key $KEY.  */
+
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤«¤é¥×¥í¥Ñ¥Æ¥£¤Î´Ø¿ô¥Ý¥¤¥ó¥¿¤Ç¤¢¤ëÃͤòÆÀ¤ë.
+
+    ´Ø¿ô mplist_get_func () ¤Ï´Ø¿ô mplist_get () ¤ÈƱÍͤˡ¢¥×¥í¥Ñ¥Æ¥£¥ê
+    ¥¹¥È $PLIST Ãæ¤Ç¥­¡¼¤¬ $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ÎÃÍ¡¢Ã¢¤·´Ø¿ô¥Ý¥¤¥ó¥¿¡¢
+    ¤òÆÀ¤ë¡£ */
+
+
+/***
+    @seealso
+    mplist_get () */
+M17NFunc
+mplist_get_func (MPlist *plist, MSymbol key)
+{
+  MPLIST_FIND (plist, key);
+  return (MPLIST_TAIL_P (plist) ? NULL : MPLIST_FUNC (plist));
+}
+
+/*=*/
+
+/***en
+    @brief Add a property at the end of a property list.
+
+    The mplist_add () function appends at the end of property list
+    $PLIST a property whose key is $KEY and value is $VAL.  $KEY can
+    be any symbol other than @c Mnil.
 
     If $KEY is a managing key, $VAL must be a managed object.  In this
     case, the reference count of $VAL is incremented by one.
 
     If $KEY is a managing key, $VAL must be a managed object.  In this
     case, the reference count of $VAL is incremented by one.
@@ -878,6 +1250,18 @@ mplist_get (MPlist *plist, MSymbol key)
     If the operation was successful, mplist_add () returns a sublist of
     $PLIST whose first element is the just added one.  Otherwise, it
     returns @c NULL.  */
     If the operation was successful, mplist_add () returns a sublist of
     $PLIST whose first element is the just added one.  Otherwise, it
     returns @c NULL.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈËöÈø¤Ë¥×¥í¥Ñ¥Æ¥£¤òÄɲ乤ë.
+
+    ´Ø¿ô mplist_add () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ÎËöÈø¤Ë¥­¡¼¤¬ $KEY 
+    ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤òÄɲ乤롣$KEY ¤Ï¡¢@c Mnil °Ê³°¤ÎǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
+
+    $KEY ¤¬´ÉÍý¥­¡¼¤Ê¤é¤Ð¡¢$VAL ¤Ï´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç¡¢
+    $VAL ¤Î»²¾È¿ô¤Ï 1 Áý¤ä¤µ¤ì¤ë¡£
+
+    @return
+    ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mplist_add () ¤ÏÄɲ䵤줿Í×ÁǤ«¤é»Ï¤Þ¤ë $PLIST 
+    ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£  */
 
 MPlist *
 mplist_add (MPlist *plist, MSymbol key, void *val)
 
 MPlist *
 mplist_add (MPlist *plist, MSymbol key, void *val)
@@ -885,7 +1269,7 @@ mplist_add (MPlist *plist, MSymbol key, void *val)
   if (key == Mnil)
     MERROR (MERROR_PLIST, NULL);
   MPLIST_FIND (plist, Mnil);
   if (key == Mnil)
     MERROR (MERROR_PLIST, NULL);
   MPLIST_FIND (plist, Mnil);
-  if (key->managing_key)
+  if (val && key->managing_key)
     M17N_OBJECT_REF (val);
   MPLIST_KEY (plist) = key;
   MPLIST_VAL (plist) = val;
     M17N_OBJECT_REF (val);
   MPLIST_KEY (plist) = key;
   MPLIST_VAL (plist) = val;
@@ -896,10 +1280,10 @@ mplist_add (MPlist *plist, MSymbol key, void *val)
 /*=*/
 
 /***en
 /*=*/
 
 /***en
-    @brief Push a property to a property list object.
+    @brief Add a property at the beginning of a property list.
 
 
-    The mplist_push () function pushes at the top of $PLIST a
-    property whose key is $KEY and value si $VAL.
+    The mplist_push () function inserts at the beginning of property
+    list $PLIST a property whose key is $KEY and value is $VAL.
 
     If $KEY is a managing key, $VAL must be a managed object.  In this
     case, the reference count of $VAL is incremented by one.
 
     If $KEY is a managing key, $VAL must be a managed object.  In this
     case, the reference count of $VAL is incremented by one.
@@ -907,6 +1291,18 @@ mplist_add (MPlist *plist, MSymbol key, void *val)
     @return
     If the operation was successful, this function returns $PLIST.
     Otherwise, it returns @c NULL.  */
     @return
     If the operation was successful, this function returns $PLIST.
     Otherwise, it returns @c NULL.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎÀèƬ¤Ë¥×¥í¥Ñ¥Æ¥£¤òÁÞÆþ¤¹¤ë.
+
+    ´Ø¿ô mplist_push () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ÎÀèƬ¤Ë¥­¡¼¤¬ $KEY 
+    ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¥ª¥Ö¥¸¥§¥¯¥È¤òÁÞÆþ¤¹¤ë¡£
+
+    $KEY ¤¬´ÉÍý¥­¡¼¤Ê¤é¤Ð¡¢$VAL ¤Ï´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç¡¢
+    $VAL ¤Î»²¾È¿ô¤Ï 1 Áý¤ä¤µ¤ì¤ë¡£
+
+    @return
+    ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¤³¤Î´Ø¿ô¤Ï $PLIST ¤òÊÖ¤·¡¢¤½¤¦¤Ç¤Ê¤±¤ì¤Ð@c NULL 
+    ¤òÊÖ¤¹¡£  */
 
 MPlist *
 mplist_push (MPlist *plist, MSymbol key, void *val)
 
 MPlist *
 mplist_push (MPlist *plist, MSymbol key, void *val)
@@ -918,9 +1314,11 @@ mplist_push (MPlist *plist, MSymbol key, void *val)
   MPLIST_NEW (pl);
   MPLIST_KEY (pl) = MPLIST_KEY (plist);
   MPLIST_VAL (pl) = MPLIST_VAL (plist);
   MPLIST_NEW (pl);
   MPLIST_KEY (pl) = MPLIST_KEY (plist);
   MPLIST_VAL (pl) = MPLIST_VAL (plist);
-  pl->next = plist->next;
+  if (MPLIST_NESTED_P (plist))
+    MPLIST_SET_NESTED_P (pl);
+  MPLIST_NEXT (pl) = MPLIST_NEXT (plist);
   plist->next = pl;
   plist->next = pl;
-  if (key->managing_key)
+  if (val && key->managing_key)
     M17N_OBJECT_REF (val);
   MPLIST_KEY (plist) = key;
   MPLIST_VAL (plist) = val;
     M17N_OBJECT_REF (val);
   MPLIST_KEY (plist) = key;
   MPLIST_VAL (plist) = val;
@@ -930,15 +1328,24 @@ mplist_push (MPlist *plist, MSymbol key, void *val)
 /*=*/
 
 /***en
 /*=*/
 
 /***en
-    @brief Pop a property from a property list object.
+    @brief Remove a property at the beginning of a property list.
 
 
-    The mplist_pop () function pops the topmost property from $PLIST.
-    As a result, the key and value of $PLIST becomes those of the next
-    of $PLIST.
+    The mplist_pop () function removes a property at the beginning of
+    property list $PLIST.  As a result, the second key and value of
+    the $PLIST become the first ones.
 
     @return
     If the operation was successful, this function return the value of
     the just popped property.  Otherwise, it returns @c NULL.  */
 
     @return
     If the operation was successful, this function return the value of
     the just popped property.  Otherwise, it returns @c NULL.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎÀèƬ¤«¤é¥×¥í¥Ñ¥Æ¥£¤òºï½ü¤¹¤ë.
+
+    ´Ø¿ô mplist_pop () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ÎÀèƬ¤Î¥×¥í¥Ñ¥Æ¥£¤òºï
+    ½ü¤¹¤ë¡£·ë²Ì¤È¤·¤Æ¡¢¸µ¤Î2ÈÖÌܤΥ­¡¼¤ÈÃͤ¬ÀèƬ¤Î¥­¡¼¤ÈÃͤˤʤ롣
+
+    @return 
+    ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ïºï½ü¤µ¤ì¤¿¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð
+    @c NULL ¤òÊÖ¤¹¡£  */
 
 void *
 mplist_pop (MPlist *plist)
 
 void *
 mplist_pop (MPlist *plist)
@@ -949,14 +1356,14 @@ mplist_pop (MPlist *plist)
   if (MPLIST_TAIL_P (plist))
     return NULL;
   val = MPLIST_VAL (plist);
   if (MPLIST_TAIL_P (plist))
     return NULL;
   val = MPLIST_VAL (plist);
-  next = plist->next;
+  next = MPLIST_NEXT (plist);
   MPLIST_KEY (plist) = MPLIST_KEY (next);
   MPLIST_VAL (plist) = MPLIST_VAL (next);
   if (MPLIST_KEY (plist) != Mnil
       && MPLIST_KEY (plist)->managing_key
       && MPLIST_VAL (plist))
     M17N_OBJECT_REF (MPLIST_VAL (plist));
   MPLIST_KEY (plist) = MPLIST_KEY (next);
   MPLIST_VAL (plist) = MPLIST_VAL (next);
   if (MPLIST_KEY (plist) != Mnil
       && MPLIST_KEY (plist)->managing_key
       && MPLIST_VAL (plist))
     M17N_OBJECT_REF (MPLIST_VAL (plist));
-  plist->next = next->next;
+  MPLIST_NEXT (plist) = MPLIST_NEXT (next);
   if (plist->next)
     M17N_OBJECT_REF (plist->next);
   M17N_OBJECT_UNREF (next);
   if (plist->next)
     M17N_OBJECT_REF (plist->next);
   M17N_OBJECT_UNREF (next);
@@ -965,15 +1372,24 @@ mplist_pop (MPlist *plist)
 
 /*=*/
 /***en
 
 /*=*/
 /***en
-    @brief Find a property of a specific key in a property list object.
+    @brief Find a property of a specific key in a property list.
 
 
-    The mplist_find_by_key () function searches property list object
+    The mplist_find_by_key () function searches property list
     $PLIST from the beginning for a property whose key is $KEY.  If
     such a property is found, a sublist of $PLIST whose first element
     is the found one is returned.  Otherwise, @c NULL is returned.
 
     $PLIST from the beginning for a property whose key is $KEY.  If
     such a property is found, a sublist of $PLIST whose first element
     is the found one is returned.  Otherwise, @c NULL is returned.
 
-    If $KEY is Mnil, it returns the last a sublist of $PLIST whose
+    If $KEY is @c Mnil, it returns a sublist of $PLIST whose
     first element is the last one of $PLIST.  */
     first element is the last one of $PLIST.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃ椫¤é»ØÄê¤Î¥­¡¼¤ò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤òõ¤¹.
+
+    ´Ø¿ô mplist_find_by_key () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
+    ¤ò»Ï¤á¤«¤éõ ¤·¤Æ¡¢¥­¡¼¤¬ $KEY 
+    ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤«¤é»Ï¤Þ¤ë
+    $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
+
+    $KEY ¤¬ @c Mnil ¤Ê¤é¤Ð¡¢$PLIST ¤ÎºÇ¸å¤ÎÍ×ÁǤ«¤é»Ï¤Þ¤ëÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£  */
 
 MPlist *
 mplist_find_by_key (MPlist *plist, MSymbol key)
 
 MPlist *
 mplist_find_by_key (MPlist *plist, MSymbol key)
@@ -986,12 +1402,19 @@ mplist_find_by_key (MPlist *plist, MSymbol key)
 
 /*=*/
 /***en
 
 /*=*/
 /***en
-    @brief Find a property of a specific value in a property list object.
+    @brief Find a property of a specific value in a property list.
 
 
-    The mplist_find_by_value () function searches property list object
-    $PLIST from the beginning for a property whose value is $VAL.  If
-    such a property is found, a sublist of $PLIST whose first element
-    is the found one is returned.  Otherwise, @c NULL is returned.  */
+    The mplist_find_by_value () function searches property list $PLIST
+    from the beginning for a property whose value is $VAL.  If such a
+    property is found, a sublist of $PLIST whose first element is the
+    found one is returned.  Otherwise, @c NULL is returned.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃ椫¤é»ØÄê¤ÎÃͤò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤òõ¤¹.
+
+    ´Ø¿ô mplist_find_by_value () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
+    ¤ò»Ï¤á¤«¤éõ¤·¤Æ¡¢Ãͤ¬ $VAL 
+    ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤«¤é»Ï¤Þ¤ë
+    $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£ */
 
 MPlist *
 mplist_find_by_value (MPlist *plist, void *val)
 
 MPlist *
 mplist_find_by_value (MPlist *plist, void *val)
@@ -1007,11 +1430,17 @@ mplist_find_by_value (MPlist *plist, void *val)
 /*=*/
 
 /***en
 /*=*/
 
 /***en
-    @brief Return the next sublist of a plist.
+    @brief Return the next sublist of a property list.
 
     The mplist_next () function returns a pointer to the sublist of
 
     The mplist_next () function returns a pointer to the sublist of
-    $PLIST, which begins at the second element in $PLIST.  If the
+    property list $PLIST, which begins at the second element in $PLIST.  If the
     length of $PLIST is zero, it returns @c NULL.  */
     length of $PLIST is zero, it returns @c NULL.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Î¼¡¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹.
+
+    ´Ø¿ô mplist_next () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤Î 2 
+    ÈÖÌܤÎÍ×ÁǤ«¤é»Ï¤Þ¤ëÉôʬ¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$PLIST ¤ÎŤµ¤¬ 0 
+    ¤Ê¤é¤Ð @c NULL ¤òÊÖ¤¹¡£  */
 
 MPlist *
 mplist_next (MPlist *plist)
 
 MPlist *
 mplist_next (MPlist *plist)
@@ -1022,16 +1451,25 @@ mplist_next (MPlist *plist)
 /*=*/
 
 /***en
 /*=*/
 
 /***en
-    @brief Set the first property in a property list object.
+    @brief Set the first property in a property list.
 
 
-    The mplist_set () function sets the key and value of the first
-    property in property list object $PLIST to $KEY and $VALUE,
-    respectively.  See the documentation of mplist_add () for the
-    restriction on $KEY and $VAL.
+    The mplist_set () function sets the key and the value of the first
+    property in property list $PLIST to $KEY and $VALUE, respectively.
+    See the documentation of mplist_add () for the restriction on $KEY
+    and $VAL.
 
     @return
     If the operation was successful, mplist_set () returns $PLIST.
     Otherwise, it returns @c NULL.  */
 
     @return
     If the operation was successful, mplist_set () returns $PLIST.
     Otherwise, it returns @c NULL.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤òÀßÄꤹ¤ë.
+
+    ´Ø¿ô mplist_set () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
+    ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤ÈÃͤò¤½¤ì¤¾¤ì $KEY ¤È $VALUE ¤ËÀßÄꤹ¤ë¡£
+    $KEY ¤È $VAL ¤ËÂФ¹¤ëÀ©¸Â¤Ë¤Ä¤¤¤Æ¤Ï¡¢mplist_add () ¤ÎÀâÌÀ¤ò»²¾È¡£
+
+    @return
+    ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mplist_set () ¤Ï $PLIST ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£  */
 
 MPlist *
 mplist_set (MPlist *plist, MSymbol key, void * val)
 
 MPlist *
 mplist_set (MPlist *plist, MSymbol key, void * val)
@@ -1043,19 +1481,18 @@ mplist_set (MPlist *plist, MSymbol key, void * val)
          key = MPLIST_KEY (plist);
          M17N_OBJECT_UNREF (MPLIST_NEXT (plist));
          MPLIST_KEY (plist) = Mnil;
          key = MPLIST_KEY (plist);
          M17N_OBJECT_UNREF (MPLIST_NEXT (plist));
          MPLIST_KEY (plist) = Mnil;
-         if (key->managing_key && MPLIST_VAL (plist))
+         if (key->managing_key)
            M17N_OBJECT_UNREF (MPLIST_VAL (plist));
          plist->next = NULL;
        }
     }
   else
     {
            M17N_OBJECT_UNREF (MPLIST_VAL (plist));
          plist->next = NULL;
        }
     }
   else
     {
+      if (val && key->managing_key)
+       M17N_OBJECT_REF (val);
       if (! MPLIST_TAIL_P (plist)
       if (! MPLIST_TAIL_P (plist)
-         && MPLIST_KEY (plist)->managing_key
-         && MPLIST_VAL (plist))
+         && MPLIST_KEY (plist)->managing_key)
        M17N_OBJECT_UNREF (MPLIST_VAL (plist));
        M17N_OBJECT_UNREF (MPLIST_VAL (plist));
-      if (key->managing_key)
-       M17N_OBJECT_REF (val);
       MPLIST_SET (plist, key, val);
     }
   return plist;
       MPLIST_SET (plist, key, val);
     }
   return plist;
@@ -1064,10 +1501,14 @@ mplist_set (MPlist *plist, MSymbol key, void * val)
 /*=*/
 
 /***en
 /*=*/
 
 /***en
-    @brief Return the length of a plist.
+    @brief Return the length of a property list.
 
     The mplist_length () function returns the number of properties in
 
     The mplist_length () function returns the number of properties in
-    property list object $PLIST.  */
+    property list  $PLIST.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎŤµ¤òÊÖ¤¹.
+
+    ´Ø¿ô mplist_length () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST Ãæ¤Î¥×¥í¥Ñ¥Æ¥£¤Î¿ô¤òÊÖ¤¹¡£  */
 
 int
 mplist_length (MPlist *plist)
 
 int
 mplist_length (MPlist *plist)
@@ -1081,11 +1522,17 @@ mplist_length (MPlist *plist)
 /*=*/
 
 /***en
 /*=*/
 
 /***en
-    @brief Return the key of the first property in a property list object.
+    @brief Return the key of the first property in a property list.
 
     The mplist_key () function returns the key of the first property
 
     The mplist_key () function returns the key of the first property
-    in property list object $PLIST.  If the length of $PLIST is zero,
+    in property list $PLIST.  If the length of $PLIST is zero,
     it returns @c Mnil.  */
     it returns @c Mnil.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤òÊÖ¤¹.
+
+    ´Ø¿ô mplist_key () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
+    Ãæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤òÊÖ¤¹¡£$PLIST ¤ÎŤµ¤¬ 0 ¤Ê¤é¤Ð¡¢ @c Mnil 
+    ¤òÊÖ¤¹¡£  */
 
 MSymbol
 mplist_key (MPlist *plist)
 
 MSymbol
 mplist_key (MPlist *plist)
@@ -1096,11 +1543,16 @@ mplist_key (MPlist *plist)
 /*=*/
 
 /***en
 /*=*/
 
 /***en
-    @brief Return the value of the first property in a property list object.
+    @brief Return the value of the first property in a property list.
 
     The mplist_value () function returns the value of the first
 
     The mplist_value () function returns the value of the first
-    property in property list object $PLIST.  If the length of $PLIST
+    property in property list  $PLIST.  If the length of $PLIST
     is zero, it returns @c NULL.  */
     is zero, it returns @c NULL.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹.
+
+    ´Ø¿ô mplist_value () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST Ãæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£
+    $PLIST ¤ÎŤµ¤¬ 0 ¤Ê¤é¤Ð¡¢ @c Mnil ¤òÊÖ¤¹¡£  */
 
 void *
 mplist_value (MPlist *plist)
 
 void *
 mplist_value (MPlist *plist)
@@ -1109,7 +1561,7 @@ mplist_value (MPlist *plist)
 }
 
 /***en
 }
 
 /***en
-    @brief Generate a plist by deserializaing an M-text.
+    @brief Generate a property list by deserializing an M-text.
 
     The mplist_deserialize () function parses M-text $MT and returns a
     property list.
 
     The mplist_deserialize () function parses M-text $MT and returns a
     property list.
@@ -1127,23 +1579,55 @@ mplist_value (MPlist *plist)
 
     M-TEXT ::= '"' character-sequence '"'
 
 
     M-TEXT ::= '"' character-sequence '"'
 
-    Each kind of @c ELEMENT is assigned one of these keys:
-       @c Msymbol, @c Minteger, @c Mtext, @c Mplist
+    Each alternatives of @c ELEMENT is assigned one of these keys: @c
+    Msymbol, @c Minteger, @c Mtext, @c Mplist
 
 
-    In an ascii-character-sequence, a backslush (\) is used as the escape
-    character, which means that, for instance, <tt>"abc\ def"</tt>
+    In an ascii-character-sequence, a backslash (\) is used as the escape
+    character, which means that, for instance, <tt>abc\ def</tt>
     produces a symbol whose name is of length seven with the fourth
     character being a space.  */
     produces a symbol whose name is of length seven with the fourth
     character being a space.  */
+/***ja
+    @brief M-text ¤ò¥Ç¥·¥ê¥¢¥é¥¤¥º¤·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òºî¤ë.
+
+    ´Ø¿ô mplist_deserialize () ¤Ï M-text $MT ¤ò²òÀϤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òÊÖ¤¹¡£
+
+    $MT ¤Î¥·¥ó¥¿¥Ã¥¯¥¹¤Ï°Ê²¼¤ÎÄ̤ꡣ
+
+    MT ::= '(' ELEMENT * ')'
+
+    ELEMENT ::= SYMBOL | INTEGER | M-TEXT | PLIST
+
+    SYMBOL ::= ¥¢¥¹¥­¡¼Ê¸»úÎó
+
+    INTEGER ::= '-' ? [ '0' | .. | '9' ]+
+               | '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
+
+    M-TEXT ::= '"' character-sequence '"'
+
+    @c ELEMENT ¤Î³ÆÁªÂò»è¤Ï¥­¡¼¡§@c Msymbol, @c Minteger, @c Mtext,
+    @c Mplist ¤Î¤¤¤º¤ì¤«¤ò³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¡£
+
+    ¥¢¥¹¥­¡¼Ê¸»úÎóÆâ¤Ç¤Ï¡¢¥Ð¥Ã¥¯¥¹¥é¥Ã¥·¥å (\) ¤¬¥¨¥¹¥±¡¼¥×ʸ»ú¤È¤·¤ÆÍѤ¤¤é¤ì¤ë¡£¤¿¤È¤¨¤Ð
+    <tt>abc\ def</tt> ¤Ï 4 Ê¸»úÌܤ¬¶õÇòʸ»ú¤Ç¤¢¤êŤµ¤¬ 7 
+    ¤Ç¤¢¤ë»ý¤Ä̾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë¤òÀ¸À®¤¹¤ë¡£   */
 
 MPlist *
 mplist_deserialize (MText *mt)
 {
 
 MPlist *
 mplist_deserialize (MText *mt)
 {
+  MPlist *plist;
+  MText *tmp = NULL;
+
   if (mt->format > MTEXT_FORMAT_UTF_8)
     {
   if (mt->format > MTEXT_FORMAT_UTF_8)
     {
-      if (mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8) < 0)
-       MERROR (MERROR_PLIST, NULL);
+      if (MTEXT_READ_ONLY_P (mt))
+       mt = tmp = mtext_cpy (mtext (), mt);
+      else
+       mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
     }
     }
-  return mplist__from_string (MTEXT_DATA (mt), mtext_nbytes (mt));
+  plist = mplist__from_string (MTEXT_DATA (mt), mtext_nbytes (mt));
+  if (tmp)
+    M17N_OBJECT_UNREF (tmp);
+  return plist;
 }
 
 /*** @}  */
 }
 
 /*** @}  */
@@ -1153,35 +1637,41 @@ mplist_deserialize (MText *mt)
 /*** @{  */
 
 /***en
 /*** @{  */
 
 /***en
-    @brief Dump a plist.
+    @brief Dump a property list.
 
 
-    The mdebug_dump_plist () function prints $PLIST in a human
-    readable way to the stderr.  $INDENT specifies how many columns to
-    indent the lines but the first one.
+    The mdebug_dump_plist () function prints a property list $PLIST in
+    a 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 $PLIST.  */
 
     @return
     This function returns $PLIST.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò¥À¥ó¥×¤¹¤ë.
+
+    ´Ø¿ô mdebug_dump_plist () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤òɸ½à¥¨¥é¡¼½Ð
+    ÎϤ⤷¤¯¤Ï´Ä¶­ÊÑ¿ô MDEBUG_DUMP_FONT ¤Ç»ØÄꤵ¤ì¤¿¥Õ¥¡¥¤¥ë¤Ë¿Í´Ö¤Ë²Ä
+    ÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
 
 
+    @return
+    ¤³¤Î´Ø¿ô¤Ï $PLIST ¤òÊÖ¤¹¡£  */
 MPlist *
 mdebug_dump_plist (MPlist *plist, int indent)
 {
   char *prefix = (char *) alloca (indent + 1);
   MPlist *pl;
 MPlist *
 mdebug_dump_plist (MPlist *plist, int indent)
 {
   char *prefix = (char *) alloca (indent + 1);
   MPlist *pl;
-  int first = 1;
 
   memset (prefix, 32, indent);
   prefix[indent] = 0;
 
 
   memset (prefix, 32, indent);
   prefix[indent] = 0;
 
-  fprintf (stderr, "(");
+  fprintf (mdebug__output, "(");
   MPLIST_DO (pl, plist)
     {
   MPLIST_DO (pl, plist)
     {
-      if (first)
-       first = 0;
-      else
-       fprintf (stderr, "\n%s ", prefix);
-      dump_plist_element (pl, indent + 2);
+      if (pl != plist)
+       fprintf (mdebug__output, "\n%s ", prefix);
+      write_element (NULL, pl, indent + 1);
     }
     }
-  fprintf (stderr, ")");
+  fprintf (mdebug__output, ")");
   return plist;
 }
 
   return plist;
 }