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