*** 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 from the
1170     beginning for a property whose key is $KEY.  If such a property is
1171     found, its value is returned as the type of <tt>(void *)</tt>.  If
1172     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 Set the value (function pointer) of a property in a property list.
1206
1207     The mplist_put_func () function is similar to mplist_put () but for
1208     setting function pointer $FUNC in property list $PLIST for key
1209     $KEY.  */
1210
1211 /***ja
1212     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤Î¥×¥í¥Ñ¥Æ¥£¤Ë´Ø¿ô¥Ý¥¤¥ó¥¿¤Ç¤¢¤ëÃͤòÀßÄꤹ¤ë.
1213
1214     ´Ø¿ô mplist_put_func () ¤Ï´Ø¿ô mplist_put () Æ±ÍÍ¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST
1215     Ãæ¤Ç¥­¡¼¤¬ $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ËÃͤòÀßÄꤹ¤ë¡£Ã¢¤·¤½¤ÎÃͤϴؿô¥Ý¥¤¥ó¥¿
1216     $FUNC ¤Ç¤¢¤ë¡£ */
1217
1218
1219 /***
1220     @seealso
1221     mplist_put (), M17N_FUNC ()  */
1222
1223 MPlist *
1224 mplist_put_func (MPlist *plist, MSymbol key, M17NFunc func)
1225 {
1226   if (key == Mnil)
1227     MERROR (MERROR_PLIST, NULL);
1228   while (1)
1229     {
1230       MPLIST_FIND (plist, key);
1231       if (MPLIST_TAIL_P (plist) || MPLIST_VAL_FUNC_P (plist))
1232         break;
1233       plist = MPLIST_NEXT (plist);
1234     };
1235
1236   MPLIST_KEY (plist) = (key);
1237   MPLIST_FUNC (plist) = func;
1238   MPLIST_SET_VAL_FUNC_P (plist);
1239   if (! plist->next)
1240     MPLIST_NEW ((plist)->next);
1241   return plist;
1242 }
1243
1244 /*=*/
1245
1246 /***en
1247     @brief Get the value (function pointer) of a property in a property list.
1248
1249     The mplist_get_func () function is similar to mplist_get () but for
1250     getting a function pointer from property list $PLIST by key $KEY.  */
1251
1252 /***ja
1253     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤«¤é¥×¥í¥Ñ¥Æ¥£¤Î´Ø¿ô¥Ý¥¤¥ó¥¿¤Ç¤¢¤ëÃͤòÆÀ¤ë.
1254
1255     ´Ø¿ô mplist_get_func () ¤Ï´Ø¿ô mplist_get () ¤ÈƱÍͤˡ¢¥×¥í¥Ñ¥Æ¥£¥ê
1256     ¥¹¥È $PLIST Ãæ¤Ç¥­¡¼¤¬ $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ÎÃÍ¡¢Ã¢¤·´Ø¿ô¥Ý¥¤¥ó¥¿¡¢
1257     ¤òÆÀ¤ë¡£ */
1258
1259
1260 /***
1261     @seealso
1262     mplist_get () */
1263 M17NFunc
1264 mplist_get_func (MPlist *plist, MSymbol key)
1265 {
1266   MPLIST_FIND (plist, key);
1267   return (MPLIST_TAIL_P (plist) ? NULL : MPLIST_FUNC (plist));
1268 }
1269
1270 /*=*/
1271
1272 /***en
1273     @brief Add a property at the end of a property list.
1274
1275     The mplist_add () function appends at the end of property list
1276     $PLIST a property whose key is $KEY and value is $VAL.  $KEY can
1277     be any symbol other than @c Mnil.
1278
1279     If $KEY is a managing key, $VAL must be a managed object.  In this
1280     case, the reference count of $VAL is incremented by one.
1281
1282     @return
1283     If the operation was successful, mplist_add () returns a sublist of
1284     $PLIST whose first element is the just added one.  Otherwise, it
1285     returns @c NULL.  */
1286 /***ja
1287     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈËöÈø¤Ë¥×¥í¥Ñ¥Æ¥£¤òÄɲ乤ë.
1288
1289     ´Ø¿ô mplist_add () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ÎËöÈø¤Ë¥­¡¼¤¬ $KEY 
1290     ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤òÄɲ乤롣$KEY ¤Ï¡¢@c Mnil °Ê³°¤ÎǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
1291
1292     $KEY ¤¬´ÉÍý¥­¡¼¤Ê¤é¤Ð¡¢$VAL ¤Ï´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç¡¢
1293     $VAL ¤Î»²¾È¿ô¤Ï 1 Áý¤ä¤µ¤ì¤ë¡£
1294
1295     @return
1296     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mplist_add () ¤ÏÄɲ䵤줿Í×ÁǤ«¤é»Ï¤Þ¤ë $PLIST 
1297     ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£  */
1298
1299 MPlist *
1300 mplist_add (MPlist *plist, MSymbol key, void *val)
1301 {
1302   if (key == Mnil)
1303     MERROR (MERROR_PLIST, NULL);
1304   MPLIST_FIND (plist, Mnil);
1305   if (val && key->managing_key)
1306     M17N_OBJECT_REF (val);
1307   MPLIST_KEY (plist) = key;
1308   MPLIST_VAL (plist) = val;
1309   MPLIST_NEW (plist->next);
1310   return plist;
1311 }
1312
1313 /*=*/
1314
1315 /***en
1316     @brief Add a property at the beginning of a property list.
1317
1318     The mplist_push () function inserts at the beginning of property
1319     list $PLIST a property whose key is $KEY and value is $VAL.
1320
1321     If $KEY is a managing key, $VAL must be a managed object.  In this
1322     case, the reference count of $VAL is incremented by one.
1323
1324     @return
1325     If the operation was successful, this function returns $PLIST.
1326     Otherwise, it returns @c NULL.  */
1327 /***ja
1328     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎÀèƬ¤Ë¥×¥í¥Ñ¥Æ¥£¤òÁÞÆþ¤¹¤ë.
1329
1330     ´Ø¿ô mplist_push () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ÎÀèƬ¤Ë¥­¡¼¤¬ $KEY 
1331     ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¥ª¥Ö¥¸¥§¥¯¥È¤òÁÞÆþ¤¹¤ë¡£
1332
1333     $KEY ¤¬´ÉÍý¥­¡¼¤Ê¤é¤Ð¡¢$VAL ¤Ï´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç¡¢
1334     $VAL ¤Î»²¾È¿ô¤Ï 1 Áý¤ä¤µ¤ì¤ë¡£
1335
1336     @return
1337     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¤³¤Î´Ø¿ô¤Ï $PLIST ¤òÊÖ¤·¡¢¤½¤¦¤Ç¤Ê¤±¤ì¤Ð@c NULL 
1338     ¤òÊÖ¤¹¡£  */
1339
1340 MPlist *
1341 mplist_push (MPlist *plist, MSymbol key, void *val)
1342 {
1343   MPlist *pl;
1344
1345   if (key == Mnil)
1346     MERROR (MERROR_PLIST, NULL);
1347   MPLIST_NEW (pl);
1348   MPLIST_KEY (pl) = MPLIST_KEY (plist);
1349   MPLIST_VAL (pl) = MPLIST_VAL (plist);
1350   MPLIST_NEXT (pl) = MPLIST_NEXT (plist);
1351   plist->next = pl;
1352   if (val && key->managing_key)
1353     M17N_OBJECT_REF (val);
1354   MPLIST_KEY (plist) = key;
1355   MPLIST_VAL (plist) = val;
1356   return plist;
1357 }
1358
1359 /*=*/
1360
1361 /***en
1362     @brief Remove a property at the beginning of a property list.
1363
1364     The mplist_pop () function removes a property at the beginning of
1365     property list $PLIST.  As a result, the second key and value of
1366     the $PLIST become the first ones.
1367
1368     @return
1369     If the operation was successful, this function return the value of
1370     the just popped property.  Otherwise, it returns @c NULL.  */
1371 /***ja
1372     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎÀèƬ¤«¤é¥×¥í¥Ñ¥Æ¥£¤òºï½ü¤¹¤ë.
1373
1374     ´Ø¿ô mplist_pop () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ÎÀèƬ¤Î¥×¥í¥Ñ¥Æ¥£¤òºï
1375     ½ü¤¹¤ë¡£·ë²Ì¤È¤·¤Æ¡¢¸µ¤Î2ÈÖÌܤΥ­¡¼¤ÈÃͤ¬ÀèƬ¤Î¥­¡¼¤ÈÃͤˤʤ롣
1376
1377     @return 
1378     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ïºï½ü¤µ¤ì¤¿¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð
1379     @c NULL ¤òÊÖ¤¹¡£  */
1380
1381 void *
1382 mplist_pop (MPlist *plist)
1383 {
1384   void *val;
1385   MPlist *next;
1386
1387   if (MPLIST_TAIL_P (plist))
1388     return NULL;
1389   val = MPLIST_VAL (plist);
1390   next = MPLIST_NEXT (plist);
1391   MPLIST_KEY (plist) = MPLIST_KEY (next);
1392   MPLIST_VAL (plist) = MPLIST_VAL (next);
1393   if (MPLIST_KEY (plist) != Mnil
1394       && MPLIST_KEY (plist)->managing_key
1395       && MPLIST_VAL (plist))
1396     M17N_OBJECT_REF (MPLIST_VAL (plist));
1397   MPLIST_NEXT (plist) = MPLIST_NEXT (next);
1398   if (plist->next)
1399     M17N_OBJECT_REF (plist->next);
1400   M17N_OBJECT_UNREF (next);
1401   return val;
1402 }
1403
1404 /*=*/
1405 /***en
1406     @brief Find a property of a specific key in a property list.
1407
1408     The mplist_find_by_key () function searches property list
1409     $PLIST from the beginning for a property whose key is $KEY.  If
1410     such a property is found, a sublist of $PLIST whose first element
1411     is the found one is returned.  Otherwise, @c NULL is returned.
1412
1413     If $KEY is @c Mnil, it returns a sublist of $PLIST whose
1414     first element is the last one of $PLIST.  */
1415 /***ja
1416     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃ椫¤é»ØÄê¤Î¥­¡¼¤ò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤òõ¤¹.
1417
1418     ´Ø¿ô mplist_find_by_key () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1419     ¤ò»Ï¤á¤«¤éõ ¤·¤Æ¡¢¥­¡¼¤¬ $KEY 
1420     ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤«¤é»Ï¤Þ¤ë
1421     $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
1422
1423     $KEY ¤¬ @c Mnil ¤Ê¤é¤Ð¡¢$PLIST ¤ÎºÇ¸å¤ÎÍ×ÁǤ«¤é»Ï¤Þ¤ëÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£  */
1424
1425 MPlist *
1426 mplist_find_by_key (MPlist *plist, MSymbol key)
1427 {
1428   MPLIST_FIND (plist, key);
1429   return (MPLIST_TAIL_P (plist)
1430           ? (key == Mnil ? plist : NULL)
1431           : plist);
1432 }
1433
1434 /*=*/
1435 /***en
1436     @brief Find a property of a specific value in a property list.
1437
1438     The mplist_find_by_value () function searches property list $PLIST
1439     from the beginning for a property whose value is $VAL.  If such a
1440     property is found, a sublist of $PLIST whose first element is the
1441     found one is returned.  Otherwise, @c NULL is returned.  */
1442 /***ja
1443     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃ椫¤é»ØÄê¤ÎÃͤò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤òõ¤¹.
1444
1445     ´Ø¿ô mplist_find_by_value () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1446     ¤ò»Ï¤á¤«¤éõ¤·¤Æ¡¢Ãͤ¬ $VAL 
1447     ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤«¤é»Ï¤Þ¤ë
1448     $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£ */
1449
1450 MPlist *
1451 mplist_find_by_value (MPlist *plist, void *val)
1452 {
1453   MPLIST_DO (plist, plist)
1454     {
1455       if (MPLIST_VAL (plist) == val)
1456         return plist;
1457     }
1458   return NULL;
1459 }
1460
1461 /*=*/
1462
1463 /***en
1464     @brief Return the next sublist of a property list.
1465
1466     The mplist_next () function returns a pointer to the sublist of
1467     property list $PLIST, which begins at the second element in $PLIST.  If the
1468     length of $PLIST is zero, it returns @c NULL.  */
1469 /***ja
1470     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Î¼¡¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹.
1471
1472     ´Ø¿ô mplist_next () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤Î 2 
1473     ÈÖÌܤÎÍ×ÁǤ«¤é»Ï¤Þ¤ëÉôʬ¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$PLIST ¤ÎŤµ¤¬ 0 
1474     ¤Ê¤é¤Ð @c NULL ¤òÊÖ¤¹¡£  */
1475
1476 MPlist *
1477 mplist_next (MPlist *plist)
1478 {
1479   return (MPLIST_TAIL_P (plist) ? NULL : plist->next);
1480 }
1481
1482 /*=*/
1483
1484 /***en
1485     @brief Set the first property in a property list.
1486
1487     The mplist_set () function sets the key and the value of the first
1488     property in property list $PLIST to $KEY and $VALUE, respectively.
1489     See the documentation of mplist_add () for the restriction on $KEY
1490     and $VAL.
1491
1492     @return
1493     If the operation was successful, mplist_set () returns $PLIST.
1494     Otherwise, it returns @c NULL.  */
1495 /***ja
1496     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤òÀßÄꤹ¤ë.
1497
1498     ´Ø¿ô mplist_set () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1499     ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤ÈÃͤò¤½¤ì¤¾¤ì $KEY ¤È $VALUE ¤ËÀßÄꤹ¤ë¡£
1500     $KEY ¤È $VAL ¤ËÂФ¹¤ëÀ©¸Â¤Ë¤Ä¤¤¤Æ¤Ï¡¢mplist_add () ¤ÎÀâÌÀ¤ò»²¾È¡£
1501
1502     @return
1503     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mplist_set () ¤Ï $PLIST ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£  */
1504
1505 MPlist *
1506 mplist_set (MPlist *plist, MSymbol key, void * val)
1507 {
1508   if (key == Mnil)
1509     {
1510       if (! MPLIST_TAIL_P (plist))
1511         {
1512           key = MPLIST_KEY (plist);
1513           M17N_OBJECT_UNREF (MPLIST_NEXT (plist));
1514           MPLIST_KEY (plist) = Mnil;
1515           if (key->managing_key)
1516             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1517           plist->next = NULL;
1518         }
1519     }
1520   else
1521     {
1522       if (val && key->managing_key)
1523         M17N_OBJECT_REF (val);
1524       if (! MPLIST_TAIL_P (plist)
1525           && MPLIST_KEY (plist)->managing_key)
1526         M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1527       MPLIST_SET (plist, key, val);
1528     }
1529   return plist;
1530 }
1531
1532 /*=*/
1533
1534 /***en
1535     @brief Return the length of a property list.
1536
1537     The mplist_length () function returns the number of properties in
1538     property list  $PLIST.  */
1539 /***ja
1540     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎŤµ¤òÊÖ¤¹.
1541
1542     ´Ø¿ô mplist_length () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST Ãæ¤Î¥×¥í¥Ñ¥Æ¥£¤Î¿ô¤òÊÖ¤¹¡£  */
1543
1544 int
1545 mplist_length (MPlist *plist)
1546 {
1547   int n;
1548
1549   for (n = 0; ! (MPLIST_TAIL_P (plist)); n++, plist = plist->next);
1550   return n;
1551 }
1552
1553 /*=*/
1554
1555 /***en
1556     @brief Return the key of the first property in a property list.
1557
1558     The mplist_key () function returns the key of the first property
1559     in property list $PLIST.  If the length of $PLIST is zero,
1560     it returns @c Mnil.  */
1561 /***ja
1562     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤òÊÖ¤¹.
1563
1564     ´Ø¿ô mplist_key () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1565     Ãæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤òÊÖ¤¹¡£$PLIST ¤ÎŤµ¤¬ 0 ¤Ê¤é¤Ð¡¢ @c Mnil 
1566     ¤òÊÖ¤¹¡£  */
1567
1568 MSymbol
1569 mplist_key (MPlist *plist)
1570 {
1571   return MPLIST_KEY (plist);
1572 }
1573
1574 /*=*/
1575
1576 /***en
1577     @brief Return the value of the first property in a property list.
1578
1579     The mplist_value () function returns the value of the first
1580     property in property list  $PLIST.  If the length of $PLIST
1581     is zero, it returns @c NULL.  */
1582 /***ja
1583     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹.
1584
1585     ´Ø¿ô mplist_value () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST Ãæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£
1586     $PLIST ¤ÎŤµ¤¬ 0 ¤Ê¤é¤Ð¡¢ @c Mnil ¤òÊÖ¤¹¡£  */
1587
1588 void *
1589 mplist_value (MPlist *plist)
1590 {
1591   return MPLIST_VAL (plist);
1592 }
1593
1594 /***en
1595     @brief Generate a property list by deserializing an M-text.
1596
1597     The mplist_deserialize () function parses M-text $MT and returns a
1598     property list.
1599
1600     The syntax of $MT is as follows.
1601
1602     MT ::= '(' ELEMENT * ')'
1603
1604     ELEMENT ::= SYMBOL | INTEGER | M-TEXT | PLIST
1605
1606     SYMBOL ::= ascii-character-sequence
1607
1608     INTEGER ::= '-' ? [ '0' | .. | '9' ]+
1609                 | '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
1610
1611     M-TEXT ::= '"' character-sequence '"'
1612
1613     Each alternatives of @c ELEMENT is assigned one of these keys: @c
1614     Msymbol, @c Minteger, @c Mtext, @c Mplist
1615
1616     In an ascii-character-sequence, a backslash (\) is used as the escape
1617     character, which means that, for instance, <tt>"abc\ def"</tt>
1618     produces a symbol whose name is of length seven with the fourth
1619     character being a space.  */
1620 /***ja
1621     @brief M-text ¤ò¥Ç¥·¥ê¥¢¥é¥¤¥º¤·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òºî¤ë.
1622
1623     ´Ø¿ô mplist_deserialize () ¤Ï M-text $MT ¤ò²òÀϤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òÊÖ¤¹¡£
1624
1625     $MT ¤Î¥·¥ó¥¿¥Ã¥¯¥¹¤Ï°Ê²¼¤ÎÄ̤ꡣ
1626
1627     MT ::= '(' ELEMENT * ')'
1628
1629     ELEMENT ::= SYMBOL | INTEGER | M-TEXT | PLIST
1630
1631     SYMBOL ::= ¥¢¥¹¥­¡¼Ê¸»úÎó
1632
1633     INTEGER ::= '-' ? [ '0' | .. | '9' ]+
1634                 | '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
1635
1636     M-TEXT ::= '"' character-sequence '"'
1637
1638     @c ELEMENT ¤Î³ÆÁªÂò»è¤Ï¥­¡¼¡§@c Msymbol, @c Minteger, @c Mtext,
1639     @c Mplist ¤Î¤¤¤º¤ì¤«¤ò³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¡£
1640
1641     ¥¢¥¹¥­¡¼Ê¸»úÎóÆâ¤Ç¤Ï¡¢¥Ð¥Ã¥¯¥¹¥é¥Ã¥·¥å (\) ¤¬¥¨¥¹¥±¡¼¥×ʸ»ú¤È¤·¤ÆÍѤ¤¤é¤ì¤ë¡£¤¿¤È¤¨¤Ð
1642     <tt>"abc\ def"</tt> ¤Ï 4 Ê¸»úÌܤ¬¶õÇòʸ»ú¤Ç¤¢¤êŤµ¤¬ 7 
1643     ¤Ç¤¢¤ë»ý¤Ä̾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë¤òÀ¸À®¤¹¤ë¡£   */
1644
1645 MPlist *
1646 mplist_deserialize (MText *mt)
1647 {
1648   MPlist *plist;
1649   MText *tmp = NULL;
1650
1651   if (mt->format > MTEXT_FORMAT_UTF_8)
1652     {
1653       if (MTEXT_READ_ONLY_P (mt))
1654         mt = tmp = mtext_cpy (mtext (), mt);
1655       else
1656         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
1657     }
1658   plist = mplist__from_string (MTEXT_DATA (mt), mtext_nbytes (mt));
1659   if (tmp)
1660     M17N_OBJECT_UNREF (tmp);
1661   return plist;
1662 }
1663
1664 /*** @}  */
1665
1666 /*** @addtogroup m17nDebug */
1667 /*=*/
1668 /*** @{  */
1669
1670 /***en
1671     @brief Dump a property list.
1672
1673     The mdebug_dump_plist () function prints a property list $PLIST in
1674     a human readable way to the stderr.  $INDENT specifies how many
1675     columns to indent the lines but the first one.
1676
1677     @return
1678     This function returns $PLIST.  */
1679 /***ja
1680     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò¥À¥ó¥×¤¹¤ë.
1681
1682     ´Ø¿ô mdebug_dump_plist () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ò stderr 
1683     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
1684
1685     @return
1686     ¤³¤Î´Ø¿ô¤Ï $PLIST ¤òÊÖ¤¹¡£  */
1687 MPlist *
1688 mdebug_dump_plist (MPlist *plist, int indent)
1689 {
1690   char *prefix = (char *) alloca (indent + 1);
1691   MPlist *pl;
1692
1693   memset (prefix, 32, indent);
1694   prefix[indent] = 0;
1695
1696   fprintf (stderr, "(");
1697   MPLIST_DO (pl, plist)
1698     {
1699       if (pl != plist)
1700         fprintf (stderr, "\n%s ", prefix);
1701       write_element (NULL, pl, indent + 1);
1702     }
1703   fprintf (stderr, ")");
1704   return plist;
1705 }
1706
1707 /*** @} */
1708
1709 /*
1710   Local Variables:
1711   coding: euc-japan
1712   End:
1713 */