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