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