(read_mtext_element): Handle \uXXXX notation.
[m17n/m17n-lib.git] / src / plist.c
1 /* plist.c -- plist module.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nPlist
25
26     @brief Property List objects and API for them.
27
28     A @e property @e list (or @e plist for short) is a list of zero or
29     more properties.  A property consists of a @e key and a @e value,
30     where key is a symbol and value is anything that can be cast to
31     <tt>(void *)</tt>.
32
33     If the key of a property is a @e managing @e key, its @e value is
34     a @e managed @e object.  A property list itself is a managed
35     objects.  */
36 /***ja
37     @addtogroup m17nPlist
38
39     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤È¤½¤ì¤Ë´Ø¤¹¤ë API.
40
41     @e ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È (¤Þ¤¿¤Ï @e plist) ¤Ï 0 
42     ¸Ä°Ê¾å¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥ê¥¹¥È¤Ç¤¢¤ë¡£¥×¥í¥Ñ¥Æ¥£¤Ï @e ¥­¡¼ ¤È @e ÃÍ 
43     ¤«¤é¤Ê¤ë¡£¥­¡¼¤Ï¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢ÃͤϠ<tt>(void *)</tt> 
44     ¤Ë¥­¥ã¥¹¥È¤Ç¤­¤ë¤â¤Î¤Ê¤é¤Ð²¿¤Ç¤âÎɤ¤¡£
45
46     ¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤¬ @e ´ÉÍý¥­¡¼ ¤Ê¤é¤Ð¡¢¤½¤Î @e ÃÍ ¤Ï @e ´ÉÍý²¼
47     @e ¥ª¥Ö¥¸¥§¥¯¥È 
48     ¤Ç¤¢¤ë¡£¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¼«ÂΤâ´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë¡£  */
49
50 /*=*/
51
52 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
53 /*** @addtogroup m17nInternal
54      @{ */
55
56 #include <stdio.h>
57 #include <string.h>
58
59 #include "config.h"
60 #include "m17n.h"
61 #include "m17n-misc.h"
62 #include "internal.h"
63 #include "character.h"
64 #include "mtext.h"
65 #include "symbol.h"
66 #include "plist.h"
67
68 static M17NObjectArray plist_table;
69
70 /** Set PLIST to a newly allocated plist object.  */
71
72 #define MPLIST_NEW(plist)                               \
73   do {                                                  \
74     M17N_OBJECT (plist, free_plist, MERROR_PLIST);      \
75     M17N_OBJECT_REGISTER (plist_table, plist);          \
76   } while (0)
77
78
79 /** Set the element of PLIST to KEY and VAL.  If PLIST is an anchor,
80     append a new anchor.  */
81
82 #define MPLIST_SET(plist, key, val)     \
83   do {                                  \
84     MPLIST_KEY (plist) = (key);         \
85     MPLIST_VAL (plist) = (val);         \
86     if (! (plist)->next)                \
87       MPLIST_NEW ((plist)->next);       \
88   } while (0)
89
90
91 /** Set the element of PLIST to KEY and VAL.  PLIST must be an anchor.
92     Append a new anchor and set PLIST to that anchor.  */
93
94 #define MPLIST_SET_ADVANCE(plist, key, val)     \
95   do {                                          \
96     MPLIST_KEY (plist) = (key);                 \
97     MPLIST_VAL (plist) = (val);                 \
98     MPLIST_NEW ((plist)->next);                 \
99     plist = (plist)->next;                      \
100   } while (0)
101
102
103 static void
104 free_plist (void *object)
105 {
106   MPlist *plist = (MPlist *) object;
107
108   do {
109     MPlist *next = plist->next;
110
111     if (MPLIST_KEY (plist) != Mnil && MPLIST_KEY (plist)->managing_key)
112       M17N_OBJECT_UNREF (MPLIST_VAL (plist));
113     M17N_OBJECT_UNREGISTER (plist_table, plist);
114     free (plist);
115     plist = next;
116   } while (plist && plist->control.ref_count == 1);
117   M17N_OBJECT_UNREF (plist);
118 }
119
120 \f
121
122 /* Load a plist from a string.  */
123
124 #define READ_CHUNK 0x10000
125
126 typedef struct
127 {
128   /* File pointer if the stream is associated with a file.  Otherwise
129      NULL.  */
130   FILE *fp;
131   int eof;
132   unsigned char buffer[READ_CHUNK];
133   unsigned char *p, *pend;
134 } MStream;
135
136 static int
137 get_byte (MStream *st)
138 {
139   int n;
140
141   if (! st->fp || st->eof)
142     return EOF;
143   n = fread (st->buffer, 1, READ_CHUNK, st->fp);
144   if (n <= 0)
145     {
146       st->eof = 1;
147       return EOF;
148     }
149   st->p = st->buffer + 1;
150   st->pend = st->buffer + n;
151   return st->buffer[0];
152 }
153
154 #define GETC(st) ((st)->p < (st)->pend ? *(st)->p++ : get_byte (st))
155
156 #define UNGETC(c, st) (--((st)->p))
157
158 /** Mapping table for reading a number.  Hexadecimal chars
159     (0..9,A..F,a..F) are mapped to the corresponding numbers.
160     Apostrophe (code 39) is mapped to 254.  All the other bytes are
161     mapped to 255.  */
162 unsigned char hex_mnemonic[256];
163
164 /** Mapping table for escaped characters.  Mnemonic characters (e, b,
165     f, n, r, or t) that follows '\' are mapped to the corresponding
166     character code.  All the other bytes are mapped to themselves.  */
167 unsigned char escape_mnemonic[256];
168
169
170 /** Read an integer from the stream ST.  It is assumed that we have
171     already read one character C.  */
172
173 static int
174 read_decimal (MStream *st, int c)
175 {
176   int num = 0;
177
178   while (c >= '0' && c <= '9')
179     {
180       num = (num * 10) + (c - '0');
181       c = GETC (st);
182     }
183
184   if (c != EOF)
185     UNGETC (c, st);
186   return num;
187 }
188
189 /** Read an unsigned from the stream ST.  */
190
191 static unsigned
192 read_hexadesimal (MStream *st)
193 {
194   int c;
195   unsigned num = 0, n;
196
197   while ((c = GETC (st)) != EOF
198          && (n = hex_mnemonic[c]) < 16)
199     num = (num << 4) | n;
200   if (c != EOF)
201     UNGETC (c, st);
202   return num;
203 }
204
205
206 /** Read an M-text element from ST, and add it to LIST.  Return a list
207     for the next element.  */
208
209 #define READ_MTEXT_BUF_SIZE 256
210
211 static MPlist *
212 read_mtext_element (MPlist *plist, MStream *st, int skip)
213 {
214   union {
215     int chars[READ_MTEXT_BUF_SIZE];
216     unsigned char bytes[sizeof (int) * READ_MTEXT_BUF_SIZE];
217   } buffer;
218   unsigned char *bytes = buffer.bytes;
219   int nbytes = sizeof (int) * READ_MTEXT_BUF_SIZE;
220   int *chars = NULL;
221   int nchars = 0;
222   int c, i, j;
223
224   i = 0;
225   while ((c = GETC (st)) != EOF && c != '"')
226     {
227       if (c == '\\')
228         {
229           c = GETC (st);
230           if (c == EOF)
231             break;
232           if (c == 'x' || c == 'u')
233             {
234               int next_c;
235
236               c = read_hexadesimal (st);
237               next_c = GETC (st);
238               if (next_c != ' ')
239                 UNGETC (next_c, st);
240             }
241           else
242             c = escape_mnemonic[c];
243         }
244
245       if (! skip)
246         {
247           if (c >= 0x80 && ! chars)
248             {
249               chars = buffer.chars;
250               for (j = i - 1; j >= 0; j--)
251                 chars[j] = bytes[j];
252               nchars = i;
253               if (bytes != buffer.bytes)
254                 free (bytes);
255             }
256
257           if (chars)
258             {
259               if (i + 1 >= nchars)
260                 {
261                   nchars *= 2;
262                   if (chars == buffer.chars)
263                     {
264                       MTABLE_MALLOC (chars, nchars, MERROR_PLIST);
265                       memcpy (chars, buffer.chars, sizeof (int) * i);
266                     }
267                   else
268                     MTABLE_REALLOC (chars, nchars, MERROR_PLIST);
269                 }
270               chars[i++] = c;
271             }
272           else
273             {
274               if (i + MAX_UTF8_CHAR_BYTES >= nbytes)
275                 {
276                   nbytes *= 2;
277                   if (bytes == buffer.bytes)
278                     {
279                       MTABLE_MALLOC (bytes, nbytes, MERROR_PLIST);
280                       memcpy (bytes, buffer.bytes, i);
281                     }
282                   else
283                     MTABLE_REALLOC (bytes, nbytes, MERROR_PLIST);
284                 }
285               bytes[i++] = c;
286             }
287         }
288     }
289
290   if (! skip)
291     {
292       MText *mt;
293
294       if (chars)
295         {
296           mt = mtext__from_data (chars, i, MTEXT_FORMAT_UTF_32, 1);
297           if (chars != buffer.chars)
298             free (chars);
299         }         
300       else
301         {
302           mt = mtext__from_data (bytes, i, MTEXT_FORMAT_UTF_8, 1);
303           if (bytes != buffer.bytes)
304             free (bytes);
305         }
306       MPLIST_SET_ADVANCE (plist, Mtext, mt);
307     }
308   return plist;
309 }
310
311 static int
312 read_character (MStream *st, int c)
313 {
314   unsigned char buf[MAX_UTF8_CHAR_BYTES + 1];
315   int len = CHAR_BYTES_BY_HEAD (c);
316   int i;
317
318   buf[0] = c;
319   for (i = 1; i < len; i++)
320     {
321       c = GETC (st);
322       if (c == EOF
323           || (c & 0xC0) != 0x80)
324         break;
325       buf[i] = c;
326     }
327   if (i == len)
328     c = STRING_CHAR_UTF8 (buf);
329   else
330     c = buf[0];
331   return c;
332 }
333
334
335 /** Read an integer element from ST, and add it to LIST.  Return a
336     list for the next element.  It is assumed that we have already
337     read the character C. */
338
339 static MPlist *
340 read_integer_element (MPlist *plist, MStream *st, int c, int skip)
341 {
342   int num;
343
344   if (c == '0' || c == '#')
345     {
346       c = GETC (st);
347       if (c == 'x')
348         num = read_hexadesimal (st);
349       else
350         num = read_decimal (st, c);
351     }
352   else if (c == '?')
353     {
354       c = GETC (st);
355       if (c == EOF)
356         num = 0;
357       else if (c != '\\')
358         {
359           if (c < 128 || ! CHAR_UNITS_BY_HEAD_UTF8 (c))
360             num = c;
361           else
362             num = read_character (st, c);
363         }
364       else
365         {
366           c = GETC (st);
367           if (c == EOF)
368             num = '\\';
369           else if (c < 128 || ! CHAR_UNITS_BY_HEAD_UTF8 (c))
370             num = escape_mnemonic[c];
371           else
372             num = read_character (st, c);
373         }
374     }
375   else if (c == '-')
376     num = - read_decimal (st, GETC (st));
377   else
378     num = read_decimal (st, c);
379
380   if (! skip)
381     MPLIST_SET_ADVANCE (plist, Minteger, (void *) num);
382   return plist;
383 }
384
385 /** Read a symbol element from ST, and add it to LIST.  Return a list
386     for the next element.  */
387
388 static MPlist *
389 read_symbol_element (MPlist *plist, MStream *st, int skip)
390 {
391   unsigned char buffer[1024];
392   int bufsize = 1024;
393   unsigned char *buf = buffer;
394   int c, i;
395
396   i = 0;
397   while ((c = GETC (st)) != EOF
398          && c > ' '
399          && c != ')' && c != '(' && c != '"')
400     {
401       if (i >= bufsize)
402         {
403           bufsize *= 2;
404           if (buf == buffer)
405             {
406               MTABLE_MALLOC (buf, bufsize, MERROR_PLIST);
407               memcpy (buf, buffer, i);
408             }
409           else
410             MTABLE_REALLOC (buf, bufsize, MERROR_PLIST);
411         }
412       if (c == '\\')
413         {
414           c = GETC (st);
415           if (c == EOF)
416             break;
417           c = escape_mnemonic[c];
418         }
419       if (! skip)
420         buf[i++] = c;
421     }
422
423   if (c > ' ')
424     UNGETC (c, st);
425   if (! skip)
426     {
427       buf[i] = 0;
428       MPLIST_SET_ADVANCE (plist, Msymbol, msymbol ((char *) buf));
429       if (buf != buffer)
430         free (buf);
431     }
432   return plist;
433 }
434
435 /* Read an element of various type from stream ST, and add it to LIST.
436    Return a list for the next element.  The element type is decided by
437    the first token character found as below:
438         '(': plist
439         '"': mtext
440         '0'..'9', '-': integer
441         '?': integer representing character code
442         the other ASCII letters: symbol
443
444    If KEYS is not NULL, it is a plist contains target keys and stop
445    keys.  In this caes, read only a plist whose key has value 1 in
446    KEYS, and return NULL when we encounter a plist whose key has value
447    0 in KEYS while skipping any other elements.  */
448
449 static MPlist *
450 read_element (MPlist *plist, MStream *st, MPlist *keys)
451 {
452   int c;
453
454   /* Skip separators and comments.  */
455   while (1)
456     {
457       while ((c = GETC (st)) != EOF && c <= ' ');
458       if (c != ';')
459         break;
460       while ((c = GETC (st)) != EOF && c != '\n');
461       if (c == EOF)
462         break;
463     }
464
465   if (c == '(')
466     {
467       MPlist *pl, *p;
468
469       MPLIST_NEW (pl);
470       p = pl;
471       p = read_element (p, st, NULL);
472       if (keys && p && MPLIST_SYMBOL_P (pl))
473         {
474           MPlist *p0 = keys;
475           MPLIST_FIND (p0, MPLIST_SYMBOL (pl));
476           if (! MPLIST_TAIL_P (p0) && ! MPLIST_VAL (p0))
477             {
478               M17N_OBJECT_UNREF (pl);
479               return NULL;
480             }
481           while ((p = read_element (p, st, NULL)));
482           if (! MPLIST_TAIL_P (p0))
483             MPLIST_SET_ADVANCE (plist, Mplist, pl);
484           else
485             M17N_OBJECT_UNREF (pl);
486         }
487       else
488         {
489           if (p)
490             while ((p = read_element (p, st, NULL)));
491           MPLIST_SET_ADVANCE (plist, Mplist, pl);
492         }
493       return plist;
494     }
495   if (c == '"')
496     return (read_mtext_element (plist, st, keys ? 1 : 0));
497   if ((c >= '0' && c <= '9') || c == '-' || c == '?' || c == '#')
498     return (read_integer_element (plist, st, c, keys ? 1 : 0));
499   if (c == EOF || c == ')')
500     return NULL;
501   UNGETC (c, st);
502   return (read_symbol_element (plist, st, keys ? 1 : 0));
503 }
504
505 void
506 write_element (MText *mt, MPlist *plist)
507 {
508   if (MPLIST_SYMBOL_P (plist))
509     {
510       MSymbol sym = MPLIST_SYMBOL (plist);
511
512       if (sym == Mnil)
513         {
514           MTEXT_CAT_ASCII (mt, "nil");
515         }
516       else
517         {
518           char *name = MSYMBOL_NAME (sym);
519           char *buf = alloca (MSYMBOL_NAMELEN (sym) * 2 + 1), *p = buf;
520
521           while (*name)
522             {
523               if (*name <= ' ' || *name == '"' || *name == ')' || *name == ')')
524                 *p++ = '\\';
525               *p++ = *name++;
526             }
527           *p = '\0';
528           MTEXT_CAT_ASCII (mt, buf);
529         }
530     }
531   else if (MPLIST_INTEGER_P (plist))
532     {
533       int num = MPLIST_INTEGER (plist);
534       char buf[128];
535
536       sprintf (buf, "%d", num);
537       MTEXT_CAT_ASCII (mt, buf);
538     }
539   else if (MPLIST_PLIST_P (plist))
540     {
541       MPlist *pl;
542
543       plist = MPLIST_PLIST (plist);
544       mtext_cat_char (mt, '(');
545       MPLIST_DO (pl, plist)
546         {
547           if (pl != plist)
548             mtext_cat_char (mt, ' ');
549           write_element (mt, pl);
550         }
551       mtext_cat_char (mt, ')');
552     }
553   else if (MPLIST_MTEXT_P (plist))
554     {
555       mtext_cat_char (mt, '"');
556       /* Not yet implemnted */
557       mtext_cat_char (mt, '"');
558     }
559 }
560
561 /* Support functions for mdebug_dump_plist.  */
562
563 static void
564 dump_string (char *str)
565 {
566   char *p = str, *pend = p + strlen (p), *new, *p1;
567
568   new = p1 = alloca ((pend - p) * 4 + 1);
569   while (p < pend)
570     {
571       if (*p < 0)
572         {
573           sprintf (p1, "\\x%02X", (unsigned char) *p);
574           p1 += 4;
575         }
576       else if (*p < ' ')
577         {
578           *p1++ = '^';
579           *p1++ = *p + '@';
580         }
581       else if (*p == ' ')
582         {
583           *p1++ = '\\';
584           *p1++ = ' ';
585         }
586       else
587         *p1++ = *p;
588       p++;
589     }
590   *p1 = '\0';
591   fprintf (stderr, "%s", new);
592 }
593
594 static void
595 dump_plist_element (MPlist *plist, int indent)
596 {
597   char *prefix = (char *) alloca (indent + 1);
598   MSymbol key;
599
600   memset (prefix, 32, indent);
601   prefix[indent] = 0;
602
603   key = MPLIST_KEY (plist);
604   fprintf (stderr, "(%s(#%d) ", msymbol_name (MPLIST_KEY (plist)),
605            plist->control.ref_count);
606   if (key == Msymbol)
607     dump_string (msymbol_name (MPLIST_SYMBOL (plist)));
608   else if (key == Mtext)
609     mdebug_dump_mtext (MPLIST_MTEXT (plist), indent, 0);
610   else if (key == Minteger)
611     fprintf (stderr, "%x", MPLIST_INTEGER (plist));
612   else if (key == Mstring) 
613     fprintf (stderr, "\"%s\"", MPLIST_STRING (plist));
614   else if (key == Mplist)
615     {
616       fprintf (stderr, "\n%s", prefix);
617       mdebug_dump_plist (MPLIST_PLIST (plist), indent);
618     }
619   else
620     fprintf (stderr, "0x%X", (unsigned) MPLIST_VAL (plist));
621   fprintf (stderr, ")");
622 }
623
624 \f
625 /* Internal API */
626 int
627 mplist__init ()
628 {
629   int i;
630
631   M17N_OBJECT_ADD_ARRAY (plist_table, "Plist");
632
633   Minteger = msymbol ("integer");
634   Mplist = msymbol_as_managing_key ("plist");
635   Mtext = msymbol_as_managing_key ("mtext");
636
637   for (i = 0; i < 256; i++)
638     hex_mnemonic[i] = 255;
639   for (i = '0'; i <= '9'; i++)
640     hex_mnemonic[i] = i - '0';
641   for (i = 'A'; i <= 'F'; i++)
642     hex_mnemonic[i] = i - 'A' + 10;
643   for (i = 'a'; i <= 'f'; i++)
644     hex_mnemonic[i] = i - 'a' + 10;
645   for (i = 0; i < 256; i++)
646     escape_mnemonic[i] = i;
647   escape_mnemonic['e'] = 27;
648   escape_mnemonic['b'] = '\b';
649   escape_mnemonic['f'] = '\f';
650   escape_mnemonic['n'] = '\n';
651   escape_mnemonic['r'] = '\r';
652   escape_mnemonic['t'] = '\t';
653   escape_mnemonic['\\'] = '\\';
654
655   return 0;
656 }
657
658 void
659 mplist__fini (void)
660 {
661 }
662
663
664 /* Parse this form of PLIST:
665       (symbol:KEY1 TYPE1:VAL1 symbol:KEY2 TYPE2:VAL2 ...)
666    and return a newly created plist of this form:
667       (KEY1:VAL1 KEY2:VAL2 ...)  */
668
669 MPlist *
670 mplist__from_plist (MPlist *plist)
671 {
672   MPlist *pl, *p;
673
674   MPLIST_NEW (pl);
675   p = pl;
676   while (! MPLIST_TAIL_P (plist))
677     {
678       MSymbol key, type;
679
680       if (! MPLIST_SYMBOL_P (plist))
681         MERROR (MERROR_PLIST, NULL);
682       key = MPLIST_SYMBOL (plist);
683       plist = MPLIST_NEXT (plist);
684       type = MPLIST_KEY (plist);
685       if (type->managing_key && MPLIST_VAL (plist))
686         M17N_OBJECT_REF (MPLIST_VAL (plist));
687       MPLIST_SET_ADVANCE (p, key, MPLIST_VAL (plist));
688       plist = MPLIST_NEXT (plist);
689     }
690   return pl;
691 }
692
693 /** Parse this form of PLIST:
694       ((symbol:KEY1 ANY:VAL1 ... ) (symbol:KEY2 ANY:VAL2 ...) ...)
695     and return a newly created plist of this form:
696       (KEY1:(ANY:VAL1 ...) KEY2:(ANY:VAL2 ...) ...)
697     ANY can be any type.  */
698
699 MPlist *
700 mplist__from_alist (MPlist *plist)
701 {
702   MPlist *pl, *p;
703
704   MPLIST_NEW (pl);
705   p = pl;
706   MPLIST_DO (plist, plist)
707     {
708       MPlist *elt;
709
710       if (! MPLIST_PLIST_P (plist))
711         MERROR (MERROR_PLIST, NULL);
712       elt = MPLIST_PLIST (plist);
713       if (! MPLIST_SYMBOL_P (elt))
714         MERROR (MERROR_PLIST, NULL);
715       MPLIST_SET_ADVANCE (p, MPLIST_SYMBOL (elt), MPLIST_NEXT (elt));
716       M17N_OBJECT_REF (MPLIST_NEXT (elt));
717     }
718   return pl;
719 }
720
721
722 MPlist *
723 mplist__from_file (FILE *fp, MPlist *keys)
724 {
725   MPlist *plist, *pl;
726   MStream st;
727
728   st.fp = fp;
729   st.eof = 0;
730   st.p = st.pend = st.buffer;
731   MPLIST_NEW (plist);
732   pl = plist;
733   while ((pl = read_element (pl, &st, keys)));
734   return plist;
735 }
736
737
738 /** Parse $STR of $N bytes and return a property list object.  $FORMAT
739     must be either @c MTEXT_FORMAT_US_ASCII or @c MTEXT_FORMAT_UTF_8,
740     and controls how to produce @c STRING or @c M-TEXT in the
741     following definition.
742
743     The syntax of $STR is as follows.
744
745     PLIST ::= '(' ELEMENT * ')'
746
747     ELEMENT ::= SYMBOL | INTEGER | UNSIGNED | STRING | M-TEXT | PLIST
748
749     SYMBOL ::= ascii-character-sequence
750
751     INTEGER ::= '-' ? [ '0' | .. | '9' ]+
752
753     UNSIGNED ::= '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
754
755     M-TEXT ::= '"' byte-sequence '"'
756
757     Each kind of @c ELEMENT is assigned one of these keys:
758         @c Msymbol, @c Mint, @c Munsigned, @c Mtext, @c Mplist
759
760     In an ascii-character-sequence, a backslush (\) is used as the escape
761     character, which means that, for instance, <tt>"abc\ def"</tt>
762     produces a symbol whose name is of length seven with the fourth
763     character being a space.
764
765     In a byte-sequence, "\r", "\n", "\e", and "\t" are replaced by CR,
766     NL, ESC, and TAB character respectively, "\xXX" are replaced by
767     byte 0xXX.  After this replacement, the byte-sequence is decoded
768     into M-TEXT by $CODING.  */
769
770 MPlist *
771 mplist__from_string (unsigned char *str, int n)
772 {
773   MPlist *plist, *pl;
774   MStream st;
775
776   st.fp = NULL;
777   st.eof = 0;
778   st.p = str;
779   st.pend = str + n;
780   MPLIST_NEW (plist);
781   pl = plist;
782   while ((pl = read_element (pl, &st, NULL)));
783   return plist;
784 }
785
786 int
787 mplist__serialize (MText *mt, MPlist *plist)
788 {
789   MPlist *pl;
790
791   MPLIST_DO (pl, plist)
792     {
793       if (pl != plist)
794         mtext_cat_char (mt, ' ');
795       write_element (mt, pl);
796     }
797   return 0;
798 }
799
800 /*** @} */
801 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
802
803 \f
804 /* External API */
805
806 /*** @addtogroup m17nPlist */
807 /*** @{ */
808 /*=*/
809
810 /***en
811     @brief Symbol whose name is "integer".
812
813     The symbol @c Minteger has the name <tt>"integer"</tt>.  The value
814     of a property whose key is @c Minteger must be an integer.  */
815 /***ja
816     @brief "integer" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë.
817
818     ¥·¥ó¥Ü¥ë @c Minteger ¤Ï <tt>"integer"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¡£¥­¡¼¤¬
819     @c Minteger ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ÎÃͤÏÀ°¿ôÃͤǤʤ¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */
820
821 MSymbol Minteger;
822 /*=*/
823
824 /***en
825     @brief Symbol whose name is "plist".
826
827     The symbol @c Mplist has the name <tt>"plist"</tt>.  It is a
828     managing key.  A value of a property whose key is @c Mplist must
829     be a plist.  */
830 /***ja
831     @brief "plist" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë.
832
833     ¥·¥ó¥Ü¥ë @c Mplist ¤Ï <tt>"plist"</tt> 
834     ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¡£¤³¤ì¤Ï´ÉÍý¥­¡¼¤Ç¤¢¤ë¡£¥­¡¼¤¬ @c Mplist 
835     ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϠplist ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */
836
837 MSymbol Mplist;
838 /*=*/
839
840 /***en
841     @brief Symbol whose name is "mtext".
842
843     The symbol @c Mtext has the name <tt>"mtext"</tt>.  It is a
844     managing key.  A value of a property whose key is @c Mtext must be an
845     M-text.  */
846
847 /***ja
848     @brief "mtext" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë.
849
850     ¥·¥ó¥Ü¥ë @c Mtext ¤Ï <tt>"mtext"</tt>
851     ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä´ÉÍý¥­¡¼¤Ç¤¢¤ë¡£¥­¡¼¤¬ @c Mtext 
852     ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϠM-text ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£      */
853
854 MSymbol Mtext;
855
856 /*=*/
857 /***en
858     @brief Create a property list object.
859
860     The mplist () function returns a newly created property list
861     object of length zero.
862
863     @returns
864     This function returns a newly created property list.
865
866     @errors
867     This function never fails.  */
868 /***ja
869     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òºî¤ë.
870
871     ´Ø¿ô mplist () ¤ÏŤµ 0 ¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤ò¿·¤·¤¯ºî¤Ã¤ÆÊÖ¤¹¡£
872
873     @returns
874     ¤³¤Î´Ø¿ô¤Ï¿·¤·¤¯ºî¤é¤ì¤¿¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
875
876     @errors
877     ¤³¤Î´Ø¿ô¤Ï·è¤·¤Æ¼ºÇÔ¤·¤Ê¤¤¡£     */
878
879 MPlist *
880 mplist ()
881 {
882   MPlist *plist;
883
884   MPLIST_NEW (plist);
885   return plist;
886 }  
887
888 /*=*/
889 /***en
890     @brief Copy a property list.
891
892     The mplist_copy () function copies property list $PLIST.  In the
893     copy, the values are the same as those of $PLIST.
894
895     @return
896     This function returns a newly created plist which is a copy of
897     $PLIST.  
898
899     @errors
900     This function never fails.  */ 
901 /***ja
902     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò¥³¥Ô¡¼¤¹¤ë.
903
904     ´Ø¿ô mplist_copy () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
905     ¤ò¥³¥Ô¡¼¤¹¤ë¡£¥³¥Ô¡¼¤Î¤¹¤Ù¤Æ¤ÎÃͤϥ³¥Ô¡¼¸µ $PLIST ¤ÎÃͤÈƱ¤¸¤Ç¤¢¤ë¡£
906
907     @return
908     ¤³¤Î´Ø¿ô¤Ï¿·¤·¤¯ºî¤é¤ì¤¿¡¢$PLIST ¤Î¥³¥Ô¡¼¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òÊÖ¤¹¡£    
909
910     @errors
911     ¤³¤Î´Ø¿ô¤Ï·è¤·¤Æ¼ºÇÔ¤·¤Ê¤¤¡£     */
912
913 MPlist *
914 mplist_copy (MPlist *plist)
915 {
916   MPlist *copy = mplist (), *pl = copy;
917
918   MPLIST_DO (plist, plist)
919     pl = mplist_add (pl, MPLIST_KEY (plist), MPLIST_VAL (plist));
920   return copy;
921 }
922
923 /*=*/
924
925 /***en
926     @brief Set the value of a property in a property list.
927
928     The mplist_put () function searches property list $PLIST
929     from the beginning for a property whose key is $KEY.  If such a
930     property is found, its value is changed to $VALUE.  Otherwise, a
931     new property whose key is $KEY and value is $VALUE is appended at
932     the end of $PLIST.  See the documentation of mplist_add () for
933     the restriction on $KEY and $VAL.
934
935     If $KEY is a managing key, $VAL must be a managed object.  In this
936     case, the reference count of the old value, if not @c NULL, is
937     decremented by one, and that of $VAL is incremented by one.
938
939     @return
940     If the operation was successful, mplist_put () returns a sublist of
941     $PLIST whose first element is the just modified or added one.
942     Otherwise, it returns @c NULL.  */
943 /***ja
944     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÀßÄꤹ¤ë.
945
946     ´Ø¿ô mplist_put () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ò»Ï¤á¤«¤éõ¤·¤Æ¡¢¥­¡¼¤¬
947     $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤ÎÃͤò $VALUE 
948     ¤ËÊѹ¹¤¹¤ë¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¥­¡¼¤¬ $KEY ¤ÇÃͤ¬ $VALUE 
949     ¤Ç¤¢¤ë¿·¤·¤¤¥×¥í¥Ñ¥Æ¥£¤¬ $PLIST ¤ÎËöÈø¤ËÄɲ䵤ì¤ë¡£$KEY ¤È $VAL
950     ¤ËÂФ¹¤ëÀ©¸Â¤Ë¤Ä¤¤¤Æ¤Ï¡¢mplist_add () ¤ÎÀâÌÀ¤ò»²¾È¡£
951
952     $KEY ¤¬´ÉÍý¥­¡¼¤Ê¤é¤Ð¡¢
953     $VAL ¤Ï´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç¡¢¸Å¤¤Ãͤλ²¾È¿ô¤Ï 
954     @c NULL ¤Ç¤Ê¤±¤ì¤Ð 1 ¸º¤é¤µ¤ì¡¢$VAL ¤Î»²¾È¿ô¤Ï 1 Áý¤ä¤µ¤ì¤ë¡£
955
956     @return 
957     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mplist_put () ¤ÏÊѹ¹¤µ¤ì¤¿¤«Äɲ䵤줿Í×ÁǤ«¤é»Ï¤Þ¤ë
958     $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£   */
959
960 MPlist *
961 mplist_put (MPlist *plist, MSymbol key, void *val)
962 {
963   if (key == Mnil)
964     MERROR (MERROR_PLIST, NULL);
965   MPLIST_FIND (plist, key);
966   if (key->managing_key)
967     {
968       if (! MPLIST_TAIL_P (plist))
969         M17N_OBJECT_UNREF (MPLIST_VAL (plist));
970       if (val)
971         M17N_OBJECT_REF (val);
972     }
973   MPLIST_SET (plist, key, val);
974   return plist;
975 }
976
977 /*=*/
978
979 /***en
980     @brief Get the value of a property in a property list.
981
982     The mplist_get () function searches property list $PLIST
983     from the beginning for a property whose key is $KEY.  If such a
984     property is found, a pointer to its value is returned as the type
985     of <tt>(void *)</tt>.  If not found, @c NULL is returned.
986
987     When @c NULL is returned, there are two possibilities: one is the
988     case where no property is found (see above); the other is the case
989     where a property is found and its value is @c NULL.  In case that
990     these two cases must be distinguished, use the mplist_find_by_key ()
991     function.  */
992 /***ja
993     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÆÀ¤ë.
994
995     ´Ø¿ô mplist_get () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ò»Ï¤á¤«¤éõ¤·¤Æ¡¢¥­¡¼¤¬
996     $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤ÎÃͤؤΥݥ¤¥ó¥¿¤ò
997     <tt>(void *)</tt> ·¿¤ÇÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
998
999     @c NULL ¤¬Ê֤俺ݤˤÏÆó¤Ä¤Î²ÄǽÀ­¤¬¤¢¤ë: 
1000     ¾åµ­¤Î¤è¤¦¤Ë¥×¥í¥Ñ¥Æ¥£¤¬¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤È¡¢¥×¥í¥Ñ¥Æ¥£¤¬¸«¤Ä¤«¤ê¡¢¤½¤ÎÃͤ¬
1001     @c NULL ¤Ç¤¢¤ë¾ì¹ç¤Ç¤¢¤ë¡£¤³¤ì¤é¤ò¶èÊ̤¹¤ëɬÍפ¬¤¢¤ë¾ì¹ç¤Ë¤Ï´Ø¿ô 
1002     mplist_find_by_key () ¤ò»È¤¦¤³¤È¡£  */
1003
1004 /***
1005     @seealso
1006     mplist_find_by_key () */
1007
1008 void *
1009 mplist_get (MPlist *plist, MSymbol key)
1010 {
1011   MPLIST_FIND (plist, key);
1012   return (MPLIST_TAIL_P (plist) ? NULL : MPLIST_VAL (plist));
1013 }
1014
1015 /*=*/
1016
1017 /***en
1018     @brief Add a property at the end of a property list.
1019
1020     The mplist_add () function appends at the end of property list
1021     $PLIST a property whose key is $KEY and value is $VAL.  $KEY can
1022     be any symbol other than @c Mnil.
1023
1024     If $KEY is a managing key, $VAL must be a managed object.  In this
1025     case, the reference count of $VAL is incremented by one.
1026
1027     @return
1028     If the operation was successful, mplist_add () returns a sublist of
1029     $PLIST whose first element is the just added one.  Otherwise, it
1030     returns @c NULL.  */
1031 /***ja
1032     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈËöÈø¤Ë¥×¥í¥Ñ¥Æ¥£¤òÄɲ乤ë.
1033
1034     ´Ø¿ô mplist_add () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ÎËöÈø¤Ë¥­¡¼¤¬ $KEY 
1035     ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤òÄɲ乤롣$KEY ¤Ï¡¢@c Mnil °Ê³°¤ÎǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
1036
1037     $KEY ¤¬´ÉÍý¥­¡¼¤Ê¤é¤Ð¡¢$VAL ¤Ï´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç¡¢
1038     $VAL ¤Î»²¾È¿ô¤Ï 1 Áý¤ä¤µ¤ì¤ë¡£
1039
1040     @return
1041     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mplist_add () ¤ÏÄɲ䵤줿Í×ÁǤ«¤é»Ï¤Þ¤ë $PLIST 
1042     ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£  */
1043
1044 MPlist *
1045 mplist_add (MPlist *plist, MSymbol key, void *val)
1046 {
1047   if (key == Mnil)
1048     MERROR (MERROR_PLIST, NULL);
1049   MPLIST_FIND (plist, Mnil);
1050   if (val && key->managing_key)
1051     M17N_OBJECT_REF (val);
1052   MPLIST_KEY (plist) = key;
1053   MPLIST_VAL (plist) = val;
1054   MPLIST_NEW (plist->next);
1055   return plist;
1056 }
1057
1058 /*=*/
1059
1060 /***en
1061     @brief Add a property at the beginning of a property list.
1062
1063     The mplist_push () function inserts at the beginning of property
1064     list $PLIST a property whose key is $KEY and value is $VAL.
1065
1066     If $KEY is a managing key, $VAL must be a managed object.  In this
1067     case, the reference count of $VAL is incremented by one.
1068
1069     @return
1070     If the operation was successful, this function returns $PLIST.
1071     Otherwise, it returns @c NULL.  */
1072 /***ja
1073     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎÀèƬ¤Ë¥×¥í¥Ñ¥Æ¥£¤òÁÞÆþ¤¹¤ë.
1074
1075     ´Ø¿ô mplist_push () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ÎÀèƬ¤Ë¥­¡¼¤¬ $KEY 
1076     ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¥ª¥Ö¥¸¥§¥¯¥È¤òÁÞÆþ¤¹¤ë¡£
1077
1078     $KEY ¤¬´ÉÍý¥­¡¼¤Ê¤é¤Ð¡¢$VAL ¤Ï´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç¡¢
1079     $VAL ¤Î»²¾È¿ô¤Ï 1 Áý¤ä¤µ¤ì¤ë¡£
1080
1081     @return
1082     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¤³¤Î´Ø¿ô¤Ï $PLIST ¤òÊÖ¤·¡¢¤½¤¦¤Ç¤Ê¤±¤ì¤Ð@c NULL 
1083     ¤òÊÖ¤¹¡£  */
1084
1085 MPlist *
1086 mplist_push (MPlist *plist, MSymbol key, void *val)
1087 {
1088   MPlist *pl;
1089
1090   if (key == Mnil)
1091     MERROR (MERROR_PLIST, NULL);
1092   MPLIST_NEW (pl);
1093   MPLIST_KEY (pl) = MPLIST_KEY (plist);
1094   MPLIST_VAL (pl) = MPLIST_VAL (plist);
1095   MPLIST_NEXT (pl) = MPLIST_NEXT (plist);
1096   plist->next = pl;
1097   if (val && key->managing_key)
1098     M17N_OBJECT_REF (val);
1099   MPLIST_KEY (plist) = key;
1100   MPLIST_VAL (plist) = val;
1101   return plist;
1102 }
1103
1104 /*=*/
1105
1106 /***en
1107     @brief Remove a property at the beginning of a property list.
1108
1109     The mplist_pop () function removes a property at the beginning of
1110     property list $PLIST.  As a result, the second key and value of
1111     the original $PLIST become the first of those of the new $PLIST.
1112
1113     @return
1114     If the operation was successful, this function return the value of
1115     the just popped property.  Otherwise, it returns @c NULL.  */
1116 /***ja
1117     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎÀèƬ¤«¤é¥×¥í¥Ñ¥Æ¥£¤òºï½ü¤¹¤ë.
1118
1119     ´Ø¿ô mplist_pop () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1120     ¤ÎÀèƬ¤Î¥×¥í¥Ñ¥Æ¥£¤òºï½ü¤¹¤ë¡£·ë²Ì¤È¤·¤Æ¡¢¸µ¤Î $PLIST ¤Î2ÈÖÌܤΥ­¡¼¤ÈÃͤ¬¡¢¿·¤·¤¤ 
1121     $PLIST ¤ÎÀèƬ¤Î¥­¡¼¤ÈÃͤˤʤ롣
1122
1123     @return 
1124     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ïºï½ü¤µ¤ì¤¿¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð
1125     @c NULL ¤òÊÖ¤¹¡£  */
1126
1127 void *
1128 mplist_pop (MPlist *plist)
1129 {
1130   void *val;
1131   MPlist *next;
1132
1133   if (MPLIST_TAIL_P (plist))
1134     return NULL;
1135   val = MPLIST_VAL (plist);
1136   next = MPLIST_NEXT (plist);
1137   MPLIST_KEY (plist) = MPLIST_KEY (next);
1138   MPLIST_VAL (plist) = MPLIST_VAL (next);
1139   if (MPLIST_KEY (plist) != Mnil
1140       && MPLIST_KEY (plist)->managing_key
1141       && MPLIST_VAL (plist))
1142     M17N_OBJECT_REF (MPLIST_VAL (plist));
1143   MPLIST_NEXT (plist) = MPLIST_NEXT (next);
1144   if (plist->next)
1145     M17N_OBJECT_REF (plist->next);
1146   M17N_OBJECT_UNREF (next);
1147   return val;
1148 }
1149
1150 /*=*/
1151 /***en
1152     @brief Find a property of a specific key in a property list.
1153
1154     The mplist_find_by_key () function searches property list
1155     $PLIST from the beginning for a property whose key is $KEY.  If
1156     such a property is found, a sublist of $PLIST whose first element
1157     is the found one is returned.  Otherwise, @c NULL is returned.
1158
1159     If $KEY is @c Mnil, it returns a sublist of $PLIST whose
1160     first element is the last one of $PLIST.  */
1161 /***ja
1162     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃ椫¤é»ØÄê¤Î¥­¡¼¤ò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤òõ¤¹.
1163
1164     ´Ø¿ô mplist_find_by_key () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1165     ¤ò»Ï¤á¤«¤éõ ¤·¤Æ¡¢¥­¡¼¤¬ $KEY 
1166     ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤«¤é»Ï¤Þ¤ë
1167     $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
1168
1169     $KEY ¤¬ @c Mnil ¤Ê¤é¤Ð¡¢$PLIST ¤ÎºÇ¸å¤ÎÍ×ÁǤ«¤é»Ï¤Þ¤ëÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£  */
1170
1171 MPlist *
1172 mplist_find_by_key (MPlist *plist, MSymbol key)
1173 {
1174   MPLIST_FIND (plist, key);
1175   return (MPLIST_TAIL_P (plist)
1176           ? (key == Mnil ? plist : NULL)
1177           : plist);
1178 }
1179
1180 /*=*/
1181 /***en
1182     @brief Find a property of a specific value in a property list.
1183
1184     The mplist_find_by_value () function searches property list $PLIST
1185     from the beginning for a property whose value is $VAL.  If such a
1186     property is found, a sublist of $PLIST whose first element is the
1187     found one is returned.  Otherwise, @c NULL is returned.  */
1188 /***ja
1189     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃ椫¤é»ØÄê¤ÎÃͤò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤òõ¤¹.
1190
1191     ´Ø¿ô mplist_find_by_value () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1192     ¤ò»Ï¤á¤«¤éõ¤·¤Æ¡¢Ãͤ¬ $VAL 
1193     ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤«¤é»Ï¤Þ¤ë
1194     $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£ */
1195
1196 MPlist *
1197 mplist_find_by_value (MPlist *plist, void *val)
1198 {
1199   MPLIST_DO (plist, plist)
1200     {
1201       if (MPLIST_VAL (plist) == val)
1202         return plist;
1203     }
1204   return NULL;
1205 }
1206
1207 /*=*/
1208
1209 /***en
1210     @brief Return the next sublist of a property list.
1211
1212     The mplist_next () function returns a pointer to the sublist of
1213     property list $PLIST, which begins at the second element in $PLIST.  If the
1214     length of $PLIST is zero, it returns @c NULL.  */
1215 /***ja
1216     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Î¼¡¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹.
1217
1218     ´Ø¿ô mplist_next () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤Î 2 
1219     ÈÖÌܤÎÍ×ÁǤ«¤é»Ï¤Þ¤ëÉôʬ¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$PLIST ¤ÎŤµ¤¬ 0 
1220     ¤Ê¤é¤Ð @c NULL ¤òÊÖ¤¹¡£  */
1221
1222 MPlist *
1223 mplist_next (MPlist *plist)
1224 {
1225   return (MPLIST_TAIL_P (plist) ? NULL : plist->next);
1226 }
1227
1228 /*=*/
1229
1230 /***en
1231     @brief Set the first property in a property list.
1232
1233     The mplist_set () function sets the key and the value of the first
1234     property in property list $PLIST to $KEY and $VALUE, respectively.
1235     See the documentation of mplist_add () for the restriction on $KEY
1236     and $VAL.
1237
1238     @return
1239     If the operation was successful, mplist_set () returns $PLIST.
1240     Otherwise, it returns @c NULL.  */
1241 /***ja
1242     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤òÀßÄꤹ¤ë.
1243
1244     ´Ø¿ô mplist_set () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1245     ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤ÈÃͤò¤½¤ì¤¾¤ì $KEY ¤È $VALUE ¤ËÀßÄꤹ¤ë¡£
1246     $KEY ¤È $VAL ¤ËÂФ¹¤ëÀ©¸Â¤Ë¤Ä¤¤¤Æ¤Ï¡¢mplist_add () ¤ÎÀâÌÀ¤ò»²¾È¡£
1247
1248     @return
1249     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mplist_set () ¤Ï $PLIST ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£  */
1250
1251 MPlist *
1252 mplist_set (MPlist *plist, MSymbol key, void * val)
1253 {
1254   if (key == Mnil)
1255     {
1256       if (! MPLIST_TAIL_P (plist))
1257         {
1258           key = MPLIST_KEY (plist);
1259           M17N_OBJECT_UNREF (MPLIST_NEXT (plist));
1260           MPLIST_KEY (plist) = Mnil;
1261           if (key->managing_key)
1262             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1263           plist->next = NULL;
1264         }
1265     }
1266   else
1267     {
1268       if (! MPLIST_TAIL_P (plist)
1269           && MPLIST_KEY (plist)->managing_key)
1270         M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1271       if (val && key->managing_key)
1272         M17N_OBJECT_REF (val);
1273       MPLIST_SET (plist, key, val);
1274     }
1275   return plist;
1276 }
1277
1278 /*=*/
1279
1280 /***en
1281     @brief Return the length of a property list.
1282
1283     The mplist_length () function returns the number of properties in
1284     property list  $PLIST.  */
1285 /***ja
1286     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎŤµ¤òÊÖ¤¹.
1287
1288     ´Ø¿ô mplist_length () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST Ãæ¤Î¥×¥í¥Ñ¥Æ¥£¤Î¿ô¤òÊÖ¤¹¡£  */
1289
1290 int
1291 mplist_length (MPlist *plist)
1292 {
1293   int n;
1294
1295   for (n = 0; ! (MPLIST_TAIL_P (plist)); n++, plist = plist->next);
1296   return n;
1297 }
1298
1299 /*=*/
1300
1301 /***en
1302     @brief Return the key of the first property in a property list.
1303
1304     The mplist_key () function returns the key of the first property
1305     in property list $PLIST.  If the length of $PLIST is zero,
1306     it returns @c Mnil.  */
1307 /***ja
1308     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤òÊÖ¤¹.
1309
1310     ´Ø¿ô mplist_key () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1311     Ãæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤òÊÖ¤¹¡£$PLIST ¤ÎŤµ¤¬ 0 ¤Ê¤é¤Ð¡¢ @c Mnil 
1312     ¤òÊÖ¤¹¡£  */
1313
1314 MSymbol
1315 mplist_key (MPlist *plist)
1316 {
1317   return MPLIST_KEY (plist);
1318 }
1319
1320 /*=*/
1321
1322 /***en
1323     @brief Return the value of the first property in a property list.
1324
1325     The mplist_value () function returns the value of the first
1326     property in property list  $PLIST.  If the length of $PLIST
1327     is zero, it returns @c NULL.  */
1328 /***ja
1329     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹.
1330
1331     ´Ø¿ô mplist_value () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST Ãæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£
1332     $PLIST ¤ÎŤµ¤¬ 0 ¤Ê¤é¤Ð¡¢ @c Mnil ¤òÊÖ¤¹¡£  */
1333
1334 void *
1335 mplist_value (MPlist *plist)
1336 {
1337   return MPLIST_VAL (plist);
1338 }
1339
1340 /***en
1341     @brief Generate a property list by deserializaing an M-text.
1342
1343     The mplist_deserialize () function parses M-text $MT and returns a
1344     property list.
1345
1346     The syntax of $MT is as follows.
1347
1348     MT ::= '(' ELEMENT * ')'
1349
1350     ELEMENT ::= SYMBOL | INTEGER | M-TEXT | PLIST
1351
1352     SYMBOL ::= ascii-character-sequence
1353
1354     INTEGER ::= '-' ? [ '0' | .. | '9' ]+
1355                 | '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
1356
1357     M-TEXT ::= '"' character-sequence '"'
1358
1359     Each alternatives of @c ELEMENT is assigned one of these keys: @c
1360     Msymbol, @c Minteger, @c Mtext, @c Mplist
1361
1362     In an ascii-character-sequence, a backslash (\) is used as the escape
1363     character, which means that, for instance, <tt>"abc\ def"</tt>
1364     produces a symbol whose name is of length seven with the fourth
1365     character being a space.  */
1366 /***ja
1367     @brief M-text ¤ò¥Ç¥·¥ê¥¢¥é¥¤¥º¤·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òºî¤ë.
1368
1369     ´Ø¿ô mplist_deserialize () ¤Ï M-text $MT ¤ò²òÀϤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òÊÖ¤¹¡£
1370
1371     $MT ¤Î¥·¥ó¥¿¥Ã¥¯¥¹¤Ï°Ê²¼¤ÎÄ̤ꡣ
1372
1373     MT ::= '(' ELEMENT * ')'
1374
1375     ELEMENT ::= SYMBOL | INTEGER | M-TEXT | PLIST
1376
1377     SYMBOL ::= ¥¢¥¹¥­¡¼Ê¸»úÎó
1378
1379     INTEGER ::= '-' ? [ '0' | .. | '9' ]+
1380                 | '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
1381
1382     M-TEXT ::= '"' character-sequence '"'
1383
1384     @c ELEMENT ¤Î³ÆÁªÂò»è¤Ï¥­¡¼¡§@c Msymbol, @c Minteger, @c Mtext,
1385     @c Mplist ¤Î¤¤¤º¤ì¤«¤ò³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¡£
1386
1387     ¥¢¥¹¥­¡¼Ê¸»úÎóÆâ¤Ç¤Ï¡¢¥Ð¥Ã¥¯¥¹¥é¥Ã¥·¥å (\) ¤¬¥¨¥¹¥±¡¼¥×ʸ»ú¤È¤·¤ÆÍѤ¤¤é¤ì¤ë¡£¤¿¤È¤¨¤Ð
1388     <tt>"abc\ def"</tt> ¤Ï 4 Ê¸»úÌܤ¬¶õÇòʸ»ú¤Ç¤¢¤êŤµ¤¬ 7 
1389     ¤Ç¤¢¤ë»ý¤Ä̾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë¤òÀ¸À®¤¹¤ë¡£   */
1390
1391 MPlist *
1392 mplist_deserialize (MText *mt)
1393 {
1394   MPlist *plist;
1395   MText *tmp = NULL;
1396
1397   if (mt->format > MTEXT_FORMAT_UTF_8)
1398     {
1399       if (MTEXT_READ_ONLY_P (mt))
1400         mt = tmp = mtext_cpy (mtext (), mt);
1401       else
1402         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
1403     }
1404   plist = mplist__from_string (MTEXT_DATA (mt), mtext_nbytes (mt));
1405   if (tmp)
1406     M17N_OBJECT_UNREF (tmp);
1407   return plist;
1408 }
1409
1410 /*** @}  */
1411
1412 /*** @addtogroup m17nDebug */
1413 /*=*/
1414 /*** @{  */
1415
1416 /***en
1417     @brief Dump a property list.
1418
1419     The mdebug_dump_plist () function prints a property list $PLIST in
1420     a human readable way to the stderr.  $INDENT specifies how many
1421     columns to indent the lines but the first one.
1422
1423     @return
1424     This function returns $PLIST.  */
1425 /***ja
1426     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò¥À¥ó¥×¤¹¤ë.
1427
1428     ´Ø¿ô mdebug_dump_plist () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ò stderr 
1429     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
1430
1431     @return
1432     ¤³¤Î´Ø¿ô¤Ï $PLIST ¤òÊÖ¤¹¡£  */
1433 MPlist *
1434 mdebug_dump_plist (MPlist *plist, int indent)
1435 {
1436   char *prefix = (char *) alloca (indent + 1);
1437   MPlist *pl;
1438   int first = 1;
1439
1440   memset (prefix, 32, indent);
1441   prefix[indent] = 0;
1442
1443   fprintf (stderr, "(");
1444   MPLIST_DO (pl, plist)
1445     {
1446       if (first)
1447         first = 0;
1448       else
1449         fprintf (stderr, "\n%s ", prefix);
1450       dump_plist_element (pl, indent + 2);
1451     }
1452   fprintf (stderr, ")");
1453   return plist;
1454 }
1455
1456 /*** @} */
1457
1458 /*
1459   Local Variables:
1460   coding: euc-japan
1461   End:
1462 */