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