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