Update copyright years
[m17n/m17n-lib.git] / src / plist.c
index 4feaaf9..1e449db 100644 (file)
@@ -1,5 +1,5 @@
 /* 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
 
@@ -17,7 +17,7 @@
 
    You should have received a copy of the GNU Lesser General Public
    License along with the m17n library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    02111-1307, USA.  */
 
 /***en
 
     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 <ctype.h>
 
+#include "config.h"
 #include "m17n.h"
 #include "m17n-misc.h"
 #include "internal.h"
@@ -94,7 +129,8 @@ free_plist (void *object)
   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);
@@ -137,12 +173,9 @@ get_byte (MStream *st)
   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.
@@ -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.  */
 
+#define READ_MTEXT_BUF_SIZE 256
+
 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 != '"')
     {
-      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 == 'x')
+         if (c == '\n')
+           continue;
+         if (c == 'x' || c == 'u')
            {
              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);
+             if (c >= 0x80)
+               is_char = 1;
            }
          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;
 }
 
@@ -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_integer_element (MPlist *plist, MStream *st, int c)
+read_integer_element (MPlist *plist, MStream *st, int c, int skip)
 {
   int num;
 
-  if (c == '0' || c == '#')
+  if (c == '#')
     {
       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 == '?')
     {
@@ -311,57 +422,20 @@ read_integer_element (MPlist *plist, MStream *st, int 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;
 }
 
@@ -373,10 +447,14 @@ read_symbol_element (MPlist *plist, MStream *st)
        '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 *
-read_element (MPlist *plist, MStream *st)
+read_element (MPlist *plist, MStream *st, MPlist *keys)
 {
   int c;
 
@@ -397,45 +475,99 @@ read_element (MPlist *plist, MStream *st)
 
       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 read_mtext_element (plist, st);
+    return (read_mtext_element (plist, st, keys ? 1 : 0));
   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;
-  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))
     {
@@ -443,91 +575,122 @@ write_element (MText *mt, MPlist *plist)
       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;
+      int newline = 0;
 
+      if (MPLIST_NESTED_P (plist))
+       {
+         write_symbol (mt, MPLIST_KEY (plist));
+         PUTC (mt, ':');
+       }
       plist = MPLIST_PLIST (plist);
-      mtext_cat_char (mt, '(');
+      PUTC (mt, '(');
+      if (indent >= 0)
+       indent++;
       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))
     {
-      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
-       *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
@@ -537,7 +700,7 @@ mplist__init ()
 {
   int i;
 
-  plist_table.count = 0;
+  M17N_OBJECT_ADD_ARRAY (plist_table, "Plist");
 
   Minteger = msymbol ("integer");
   Mplist = msymbol_as_managing_key ("plist");
@@ -567,7 +730,6 @@ mplist__init ()
 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);
-      if (type->managing_key)
+      if (type->managing_key && 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);
     }
@@ -622,6 +786,7 @@ mplist__from_alist (MPlist *plist)
       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));
     }
@@ -630,7 +795,7 @@ mplist__from_alist (MPlist *plist)
 
 
 MPlist *
-mplist__from_file (FILE *fp)
+mplist__from_file (FILE *fp, MPlist *keys)
 {
   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;
-  while ((pl = read_element (pl, &st)));
+  while ((pl = read_element (pl, &st, keys)));
   return plist;
 }
 
@@ -689,24 +854,106 @@ mplist__from_string (unsigned char *str, int n)
   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
-mplist__serialize (MText *mt, MPlist *plist)
+mplist__serialize (MText *mt, MPlist *plist, int pretty)
 {
   MPlist *pl;
+  int separator = pretty ? '\n' : ' ';
 
   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;
 }
 
+/**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 */
 
@@ -720,8 +967,13 @@ mplist__serialize (MText *mt, MPlist *plist)
 /***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;
 /*=*/
@@ -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
-    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;
 /*=*/
@@ -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
-    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
-    @brief "text" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë
+    @brief "mtext" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë.
 
-    ÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë @c Mtext ¤Ï <tt>"text"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä´ÉÍý
-    ¥­¡¼¤Ç¤¢¤ë¡£ */
+    ¥·¥ó¥Ü¥ë @c Mtext ¤Ï <tt>"mtext"</tt>
+    ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä´ÉÍý¥­¡¼¤Ç¤¢¤ë¡£¥­¡¼¤¬ @c Mtext 
+    ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϠM-text ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£      */
 
 MSymbol Mtext;
 
-
 /*=*/
 /***en
     @brief Create a property list object.
@@ -764,9 +1022,19 @@ MSymbol Mtext;
 
     @errors
     This function never fails.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òºî¤ë.
+
+    ´Ø¿ô mplist () ¤ÏŤµ 0 ¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤ò¿·¤·¤¯ºî¤Ã¤ÆÊÖ¤¹¡£
+
+    @returns
+    ¤³¤Î´Ø¿ô¤Ï¿·¤·¤¯ºî¤é¤ì¤¿¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
+
+    @errors
+    ¤³¤Î´Ø¿ô¤Ï·è¤·¤Æ¼ºÇÔ¤·¤Ê¤¤¡£     */
 
 MPlist *
-mplist ()
+mplist (void)
 {
   MPlist *plist;
 
@@ -776,17 +1044,28 @@ mplist ()
 
 /*=*/
 /***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
-    $PLIST.  */
-/***
+    $PLIST.  
+
     @errors
     This function never fails.  */ 
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò¥³¥Ô¡¼¤¹¤ë.
+
+    ´Ø¿ô mplist_copy () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
+    ¤ò¥³¥Ô¡¼¤¹¤ë¡£¥³¥Ô¡¼¤Î¤¹¤Ù¤Æ¤ÎÃͤϥ³¥Ô¡¼¸µ $PLIST ¤ÎÃͤÈƱ¤¸¤Ç¤¢¤ë¡£
+
+    @return
+    ¤³¤Î´Ø¿ô¤Ï¿·¤·¤¯ºî¤é¤ì¤¿¡¢$PLIST ¤Î¥³¥Ô¡¼¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òÊÖ¤¹¡£    
+
+    @errors
+    ¤³¤Î´Ø¿ô¤Ï·è¤·¤Æ¼ºÇÔ¤·¤Ê¤¤¡£     */
 
 MPlist *
 mplist_copy (MPlist *plist)
@@ -794,16 +1073,20 @@ mplist_copy (MPlist *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
-    @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
@@ -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.  */
+/***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)
@@ -829,7 +1128,8 @@ mplist_put (MPlist *plist, MSymbol key, void *val)
     {
       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;
@@ -838,18 +1138,29 @@ mplist_put (MPlist *plist, MSymbol key, void *val)
 /*=*/
 
 /***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.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÆÀ¤ë.
+
+    ´Ø¿ô mplist_get () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ò»Ï¤á¤«¤éõ¤·¤Æ¡¢¥­¡¼
+    ¤¬ $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤ÎÃͤò
+    <tt>(void *)</tt> ·¿¤ÇÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
+
+    @c NULL ¤¬Ê֤俺ݤˤÏÆó¤Ä¤Î²ÄǽÀ­¤¬¤¢¤ë: 
+    ¾åµ­¤Î¤è¤¦¤Ë¥×¥í¥Ñ¥Æ¥£¤¬¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤È¡¢¥×¥í¥Ñ¥Æ¥£¤¬¸«¤Ä¤«¤ê¡¢¤½¤ÎÃͤ¬
+    @c NULL ¤Ç¤¢¤ë¾ì¹ç¤Ç¤¢¤ë¡£¤³¤ì¤é¤ò¶èÊ̤¹¤ëɬÍפ¬¤¢¤ë¾ì¹ç¤Ë¤Ï´Ø¿ô 
+    mplist_find_by_key () ¤ò»È¤¦¤³¤È¡£  */
 
 /***
     @seealso
@@ -865,11 +1176,72 @@ mplist_get (MPlist *plist, MSymbol key)
 /*=*/
 
 /***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.
@@ -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.  */
+/***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)
@@ -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->managing_key)
+  if (val && key->managing_key)
     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
-    @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.
@@ -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.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎÀèƬ¤Ë¥×¥í¥Ñ¥Æ¥£¤òÁÞÆþ¤¹¤ë.
+
+    ´Ø¿ô mplist_push () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ÎÀèƬ¤Ë¥­¡¼¤¬ $KEY 
+    ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¥ª¥Ö¥¸¥§¥¯¥È¤òÁÞÆþ¤¹¤ë¡£
+
+    $KEY ¤¬´ÉÍý¥­¡¼¤Ê¤é¤Ð¡¢$VAL ¤Ï´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç¡¢
+    $VAL ¤Î»²¾È¿ô¤Ï 1 Áý¤ä¤µ¤ì¤ë¡£
+
+    @return
+    ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¤³¤Î´Ø¿ô¤Ï $PLIST ¤òÊÖ¤·¡¢¤½¤¦¤Ç¤Ê¤±¤ì¤Ð@c NULL 
+    ¤òÊÖ¤¹¡£  */
 
 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);
-  pl->next = plist->next;
+  if (MPLIST_NESTED_P (plist))
+    MPLIST_SET_NESTED_P (pl);
+  MPLIST_NEXT (pl) = MPLIST_NEXT (plist);
   plist->next = pl;
-  if (key->managing_key)
+  if (val && key->managing_key)
     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
-    @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.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎÀèƬ¤«¤é¥×¥í¥Ñ¥Æ¥£¤òºï½ü¤¹¤ë.
+
+    ´Ø¿ô mplist_pop () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ÎÀèƬ¤Î¥×¥í¥Ñ¥Æ¥£¤òºï
+    ½ü¤¹¤ë¡£·ë²Ì¤È¤·¤Æ¡¢¸µ¤Î2ÈÖÌܤΥ­¡¼¤ÈÃͤ¬ÀèƬ¤Î¥­¡¼¤ÈÃͤˤʤ롣
+
+    @return 
+    ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ïºï½ü¤µ¤ì¤¿¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð
+    @c NULL ¤òÊÖ¤¹¡£  */
 
 void *
 mplist_pop (MPlist *plist)
@@ -949,14 +1356,14 @@ mplist_pop (MPlist *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));
-  plist->next = next->next;
+  MPLIST_NEXT (plist) = MPLIST_NEXT (next);
   if (plist->next)
     M17N_OBJECT_REF (plist->next);
   M17N_OBJECT_UNREF (next);
@@ -965,15 +1372,24 @@ mplist_pop (MPlist *plist)
 
 /*=*/
 /***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.
 
-    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.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃ椫¤é»ØÄê¤Î¥­¡¼¤ò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤òõ¤¹.
+
+    ´Ø¿ô mplist_find_by_key () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
+    ¤ò»Ï¤á¤«¤éõ ¤·¤Æ¡¢¥­¡¼¤¬ $KEY 
+    ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤«¤é»Ï¤Þ¤ë
+    $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
+
+    $KEY ¤¬ @c Mnil ¤Ê¤é¤Ð¡¢$PLIST ¤ÎºÇ¸å¤ÎÍ×ÁǤ«¤é»Ï¤Þ¤ëÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£  */
 
 MPlist *
 mplist_find_by_key (MPlist *plist, MSymbol key)
@@ -986,12 +1402,19 @@ mplist_find_by_key (MPlist *plist, MSymbol key)
 
 /*=*/
 /***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)
@@ -1007,11 +1430,17 @@ mplist_find_by_value (MPlist *plist, void *val)
 /*=*/
 
 /***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
-    $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.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Î¼¡¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹.
+
+    ´Ø¿ô mplist_next () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤Î 2 
+    ÈÖÌܤÎÍ×ÁǤ«¤é»Ï¤Þ¤ëÉôʬ¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$PLIST ¤ÎŤµ¤¬ 0 
+    ¤Ê¤é¤Ð @c NULL ¤òÊÖ¤¹¡£  */
 
 MPlist *
 mplist_next (MPlist *plist)
@@ -1022,16 +1451,25 @@ mplist_next (MPlist *plist)
 /*=*/
 
 /***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.  */
+/***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)
@@ -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;
-         if (key->managing_key && MPLIST_VAL (plist))
+         if (key->managing_key)
            M17N_OBJECT_UNREF (MPLIST_VAL (plist));
          plist->next = NULL;
        }
     }
   else
     {
+      if (val && key->managing_key)
+       M17N_OBJECT_REF (val);
       if (! MPLIST_TAIL_P (plist)
-         && MPLIST_KEY (plist)->managing_key
-         && MPLIST_VAL (plist))
+         && MPLIST_KEY (plist)->managing_key)
        M17N_OBJECT_UNREF (MPLIST_VAL (plist));
-      if (key->managing_key)
-       M17N_OBJECT_REF (val);
       MPLIST_SET (plist, key, val);
     }
   return plist;
@@ -1064,10 +1501,14 @@ mplist_set (MPlist *plist, MSymbol key, void * val)
 /*=*/
 
 /***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
-    property list object $PLIST.  */
+    property list  $PLIST.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎŤµ¤òÊÖ¤¹.
+
+    ´Ø¿ô mplist_length () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST Ãæ¤Î¥×¥í¥Ñ¥Æ¥£¤Î¿ô¤òÊÖ¤¹¡£  */
 
 int
 mplist_length (MPlist *plist)
@@ -1081,11 +1522,17 @@ mplist_length (MPlist *plist)
 /*=*/
 
 /***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
-    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.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤òÊÖ¤¹.
+
+    ´Ø¿ô mplist_key () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
+    Ãæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤òÊÖ¤¹¡£$PLIST ¤ÎŤµ¤¬ 0 ¤Ê¤é¤Ð¡¢ @c Mnil 
+    ¤òÊÖ¤¹¡£  */
 
 MSymbol
 mplist_key (MPlist *plist)
@@ -1096,11 +1543,16 @@ mplist_key (MPlist *plist)
 /*=*/
 
 /***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
-    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.  */
+/***ja
+    @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹.
+
+    ´Ø¿ô mplist_value () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST Ãæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£
+    $PLIST ¤ÎŤµ¤¬ 0 ¤Ê¤é¤Ð¡¢ @c Mnil ¤òÊÖ¤¹¡£  */
 
 void *
 mplist_value (MPlist *plist)
@@ -1109,7 +1561,7 @@ mplist_value (MPlist *plist)
 }
 
 /***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.
@@ -1127,23 +1579,55 @@ mplist_value (MPlist *plist)
 
     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.  */
+/***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 *plist;
+  MText *tmp = NULL;
+
   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
-    @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.  */
+/***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;
-  int first = 1;
 
   memset (prefix, 32, indent);
   prefix[indent] = 0;
 
-  fprintf (stderr, "(");
+  fprintf (mdebug__output, "(");
   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;
 }