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