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