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