*** empty log message ***
[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., 51 Franklin Street, Fifth Floor,
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 $PLIST become the first ones.
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     ½ü¤¹¤ë¡£·ë²Ì¤È¤·¤Æ¡¢¸µ¤Î2ÈÖÌܤΥ­¡¼¤ÈÃͤ¬ÀèƬ¤Î¥­¡¼¤ÈÃͤˤʤ롣
1308
1309     @return 
1310     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ïºï½ü¤µ¤ì¤¿¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð
1311     @c NULL ¤òÊÖ¤¹¡£  */
1312
1313 void *
1314 mplist_pop (MPlist *plist)
1315 {
1316   void *val;
1317   MPlist *next;
1318
1319   if (MPLIST_TAIL_P (plist))
1320     return NULL;
1321   val = MPLIST_VAL (plist);
1322   next = MPLIST_NEXT (plist);
1323   MPLIST_KEY (plist) = MPLIST_KEY (next);
1324   MPLIST_VAL (plist) = MPLIST_VAL (next);
1325   if (MPLIST_KEY (plist) != Mnil
1326       && MPLIST_KEY (plist)->managing_key
1327       && MPLIST_VAL (plist))
1328     M17N_OBJECT_REF (MPLIST_VAL (plist));
1329   MPLIST_NEXT (plist) = MPLIST_NEXT (next);
1330   if (plist->next)
1331     M17N_OBJECT_REF (plist->next);
1332   M17N_OBJECT_UNREF (next);
1333   return val;
1334 }
1335
1336 /*=*/
1337 /***en
1338     @brief Find a property of a specific key in a property list.
1339
1340     The mplist_find_by_key () function searches property list
1341     $PLIST from the beginning for a property whose key is $KEY.  If
1342     such a property is found, a sublist of $PLIST whose first element
1343     is the found one is returned.  Otherwise, @c NULL is returned.
1344
1345     If $KEY is @c Mnil, it returns a sublist of $PLIST whose
1346     first element is the last one of $PLIST.  */
1347 /***ja
1348     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃ椫¤é»ØÄê¤Î¥­¡¼¤ò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤òõ¤¹.
1349
1350     ´Ø¿ô mplist_find_by_key () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1351     ¤ò»Ï¤á¤«¤éõ ¤·¤Æ¡¢¥­¡¼¤¬ $KEY 
1352     ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤«¤é»Ï¤Þ¤ë
1353     $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
1354
1355     $KEY ¤¬ @c Mnil ¤Ê¤é¤Ð¡¢$PLIST ¤ÎºÇ¸å¤ÎÍ×ÁǤ«¤é»Ï¤Þ¤ëÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£  */
1356
1357 MPlist *
1358 mplist_find_by_key (MPlist *plist, MSymbol key)
1359 {
1360   MPLIST_FIND (plist, key);
1361   return (MPLIST_TAIL_P (plist)
1362           ? (key == Mnil ? plist : NULL)
1363           : plist);
1364 }
1365
1366 /*=*/
1367 /***en
1368     @brief Find a property of a specific value in a property list.
1369
1370     The mplist_find_by_value () function searches property list $PLIST
1371     from the beginning for a property whose value is $VAL.  If such a
1372     property is found, a sublist of $PLIST whose first element is the
1373     found one is returned.  Otherwise, @c NULL is returned.  */
1374 /***ja
1375     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃ椫¤é»ØÄê¤ÎÃͤò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤òõ¤¹.
1376
1377     ´Ø¿ô mplist_find_by_value () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1378     ¤ò»Ï¤á¤«¤éõ¤·¤Æ¡¢Ãͤ¬ $VAL 
1379     ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤«¤é»Ï¤Þ¤ë
1380     $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£ */
1381
1382 MPlist *
1383 mplist_find_by_value (MPlist *plist, void *val)
1384 {
1385   MPLIST_DO (plist, plist)
1386     {
1387       if (MPLIST_VAL (plist) == val)
1388         return plist;
1389     }
1390   return NULL;
1391 }
1392
1393 /*=*/
1394
1395 /***en
1396     @brief Return the next sublist of a property list.
1397
1398     The mplist_next () function returns a pointer to the sublist of
1399     property list $PLIST, which begins at the second element in $PLIST.  If the
1400     length of $PLIST is zero, it returns @c NULL.  */
1401 /***ja
1402     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Î¼¡¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹.
1403
1404     ´Ø¿ô mplist_next () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤Î 2 
1405     ÈÖÌܤÎÍ×ÁǤ«¤é»Ï¤Þ¤ëÉôʬ¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$PLIST ¤ÎŤµ¤¬ 0 
1406     ¤Ê¤é¤Ð @c NULL ¤òÊÖ¤¹¡£  */
1407
1408 MPlist *
1409 mplist_next (MPlist *plist)
1410 {
1411   return (MPLIST_TAIL_P (plist) ? NULL : plist->next);
1412 }
1413
1414 /*=*/
1415
1416 /***en
1417     @brief Set the first property in a property list.
1418
1419     The mplist_set () function sets the key and the value of the first
1420     property in property list $PLIST to $KEY and $VALUE, respectively.
1421     See the documentation of mplist_add () for the restriction on $KEY
1422     and $VAL.
1423
1424     @return
1425     If the operation was successful, mplist_set () returns $PLIST.
1426     Otherwise, it returns @c NULL.  */
1427 /***ja
1428     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤òÀßÄꤹ¤ë.
1429
1430     ´Ø¿ô mplist_set () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1431     ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤ÈÃͤò¤½¤ì¤¾¤ì $KEY ¤È $VALUE ¤ËÀßÄꤹ¤ë¡£
1432     $KEY ¤È $VAL ¤ËÂФ¹¤ëÀ©¸Â¤Ë¤Ä¤¤¤Æ¤Ï¡¢mplist_add () ¤ÎÀâÌÀ¤ò»²¾È¡£
1433
1434     @return
1435     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mplist_set () ¤Ï $PLIST ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£  */
1436
1437 MPlist *
1438 mplist_set (MPlist *plist, MSymbol key, void * val)
1439 {
1440   if (key == Mnil)
1441     {
1442       if (! MPLIST_TAIL_P (plist))
1443         {
1444           key = MPLIST_KEY (plist);
1445           M17N_OBJECT_UNREF (MPLIST_NEXT (plist));
1446           MPLIST_KEY (plist) = Mnil;
1447           if (key->managing_key)
1448             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1449           plist->next = NULL;
1450         }
1451     }
1452   else
1453     {
1454       if (val && key->managing_key)
1455         M17N_OBJECT_REF (val);
1456       if (! MPLIST_TAIL_P (plist)
1457           && MPLIST_KEY (plist)->managing_key)
1458         M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1459       MPLIST_SET (plist, key, val);
1460     }
1461   return plist;
1462 }
1463
1464 /*=*/
1465
1466 /***en
1467     @brief Return the length of a property list.
1468
1469     The mplist_length () function returns the number of properties in
1470     property list  $PLIST.  */
1471 /***ja
1472     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎŤµ¤òÊÖ¤¹.
1473
1474     ´Ø¿ô mplist_length () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST Ãæ¤Î¥×¥í¥Ñ¥Æ¥£¤Î¿ô¤òÊÖ¤¹¡£  */
1475
1476 int
1477 mplist_length (MPlist *plist)
1478 {
1479   int n;
1480
1481   for (n = 0; ! (MPLIST_TAIL_P (plist)); n++, plist = plist->next);
1482   return n;
1483 }
1484
1485 /*=*/
1486
1487 /***en
1488     @brief Return the key of the first property in a property list.
1489
1490     The mplist_key () function returns the key of the first property
1491     in property list $PLIST.  If the length of $PLIST is zero,
1492     it returns @c Mnil.  */
1493 /***ja
1494     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤òÊÖ¤¹.
1495
1496     ´Ø¿ô mplist_key () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1497     Ãæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤òÊÖ¤¹¡£$PLIST ¤ÎŤµ¤¬ 0 ¤Ê¤é¤Ð¡¢ @c Mnil 
1498     ¤òÊÖ¤¹¡£  */
1499
1500 MSymbol
1501 mplist_key (MPlist *plist)
1502 {
1503   return MPLIST_KEY (plist);
1504 }
1505
1506 /*=*/
1507
1508 /***en
1509     @brief Return the value of the first property in a property list.
1510
1511     The mplist_value () function returns the value of the first
1512     property in property list  $PLIST.  If the length of $PLIST
1513     is zero, it returns @c NULL.  */
1514 /***ja
1515     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹.
1516
1517     ´Ø¿ô mplist_value () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST Ãæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£
1518     $PLIST ¤ÎŤµ¤¬ 0 ¤Ê¤é¤Ð¡¢ @c Mnil ¤òÊÖ¤¹¡£  */
1519
1520 void *
1521 mplist_value (MPlist *plist)
1522 {
1523   return MPLIST_VAL (plist);
1524 }
1525
1526 /***en
1527     @brief Generate a property list by deserializing an M-text.
1528
1529     The mplist_deserialize () function parses M-text $MT and returns a
1530     property list.
1531
1532     The syntax of $MT is as follows.
1533
1534     MT ::= '(' ELEMENT * ')'
1535
1536     ELEMENT ::= SYMBOL | INTEGER | M-TEXT | PLIST
1537
1538     SYMBOL ::= ascii-character-sequence
1539
1540     INTEGER ::= '-' ? [ '0' | .. | '9' ]+
1541                 | '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
1542
1543     M-TEXT ::= '"' character-sequence '"'
1544
1545     Each alternatives of @c ELEMENT is assigned one of these keys: @c
1546     Msymbol, @c Minteger, @c Mtext, @c Mplist
1547
1548     In an ascii-character-sequence, a backslash (\) is used as the escape
1549     character, which means that, for instance, <tt>"abc\ def"</tt>
1550     produces a symbol whose name is of length seven with the fourth
1551     character being a space.  */
1552 /***ja
1553     @brief M-text ¤ò¥Ç¥·¥ê¥¢¥é¥¤¥º¤·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òºî¤ë.
1554
1555     ´Ø¿ô mplist_deserialize () ¤Ï M-text $MT ¤ò²òÀϤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òÊÖ¤¹¡£
1556
1557     $MT ¤Î¥·¥ó¥¿¥Ã¥¯¥¹¤Ï°Ê²¼¤ÎÄ̤ꡣ
1558
1559     MT ::= '(' ELEMENT * ')'
1560
1561     ELEMENT ::= SYMBOL | INTEGER | M-TEXT | PLIST
1562
1563     SYMBOL ::= ¥¢¥¹¥­¡¼Ê¸»úÎó
1564
1565     INTEGER ::= '-' ? [ '0' | .. | '9' ]+
1566                 | '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
1567
1568     M-TEXT ::= '"' character-sequence '"'
1569
1570     @c ELEMENT ¤Î³ÆÁªÂò»è¤Ï¥­¡¼¡§@c Msymbol, @c Minteger, @c Mtext,
1571     @c Mplist ¤Î¤¤¤º¤ì¤«¤ò³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¡£
1572
1573     ¥¢¥¹¥­¡¼Ê¸»úÎóÆâ¤Ç¤Ï¡¢¥Ð¥Ã¥¯¥¹¥é¥Ã¥·¥å (\) ¤¬¥¨¥¹¥±¡¼¥×ʸ»ú¤È¤·¤ÆÍѤ¤¤é¤ì¤ë¡£¤¿¤È¤¨¤Ð
1574     <tt>"abc\ def"</tt> ¤Ï 4 Ê¸»úÌܤ¬¶õÇòʸ»ú¤Ç¤¢¤êŤµ¤¬ 7 
1575     ¤Ç¤¢¤ë»ý¤Ä̾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë¤òÀ¸À®¤¹¤ë¡£   */
1576
1577 MPlist *
1578 mplist_deserialize (MText *mt)
1579 {
1580   MPlist *plist;
1581   MText *tmp = NULL;
1582
1583   if (mt->format > MTEXT_FORMAT_UTF_8)
1584     {
1585       if (MTEXT_READ_ONLY_P (mt))
1586         mt = tmp = mtext_cpy (mtext (), mt);
1587       else
1588         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
1589     }
1590   plist = mplist__from_string (MTEXT_DATA (mt), mtext_nbytes (mt));
1591   if (tmp)
1592     M17N_OBJECT_UNREF (tmp);
1593   return plist;
1594 }
1595
1596 /*** @}  */
1597
1598 /*** @addtogroup m17nDebug */
1599 /*=*/
1600 /*** @{  */
1601
1602 /***en
1603     @brief Dump a property list.
1604
1605     The mdebug_dump_plist () function prints a property list $PLIST in
1606     a human readable way to the stderr.  $INDENT specifies how many
1607     columns to indent the lines but the first one.
1608
1609     @return
1610     This function returns $PLIST.  */
1611 /***ja
1612     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò¥À¥ó¥×¤¹¤ë.
1613
1614     ´Ø¿ô mdebug_dump_plist () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ò stderr 
1615     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
1616
1617     @return
1618     ¤³¤Î´Ø¿ô¤Ï $PLIST ¤òÊÖ¤¹¡£  */
1619 MPlist *
1620 mdebug_dump_plist (MPlist *plist, int indent)
1621 {
1622   char *prefix = (char *) alloca (indent + 1);
1623   MPlist *pl;
1624
1625   memset (prefix, 32, indent);
1626   prefix[indent] = 0;
1627
1628   fprintf (stderr, "(");
1629   MPLIST_DO (pl, plist)
1630     {
1631       if (pl != plist)
1632         fprintf (stderr, "\n%s ", prefix);
1633       write_element (NULL, pl, indent + 1);
1634     }
1635   fprintf (stderr, ")");
1636   return plist;
1637 }
1638
1639 /*** @} */
1640
1641 /*
1642   Local Variables:
1643   coding: euc-japan
1644   End:
1645 */