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