*** 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 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 
789     ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϠplist ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£  */
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 
806     ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ÎÃͤϠM-text ¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£      */
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     @returns
828     ¤³¤Î´Ø¿ô¤Ï¿·¤·¤¯ºî¤é¤ì¤¿¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
829
830     @errors
831     ¤³¤Î´Ø¿ô¤Ï·è¤·¤Æ¼ºÇÔ¤·¤Ê¤¤¡£     */
832
833 MPlist *
834 mplist ()
835 {
836   MPlist *plist;
837
838   MPLIST_NEW (plist);
839   return plist;
840 }  
841
842 /*=*/
843 /***en
844     @brief Copy a property list.
845
846     The mplist_copy () function copies property list $PLIST.  In the
847     copy, the values are the same as those of $PLIST.
848
849     @return
850     This function returns a newly created plist which is a copy of
851     $PLIST.  
852
853     @errors
854     This function never fails.  */ 
855 /***ja
856     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò¥³¥Ô¡¼¤¹¤ë.
857
858     ´Ø¿ô mplist_copy () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
859     ¤ò¥³¥Ô¡¼¤¹¤ë¡£¥³¥Ô¡¼¤Î¤¹¤Ù¤Æ¤ÎÃͤϥ³¥Ô¡¼¸µ $PLIST ¤ÎÃͤÈƱ¤¸¤Ç¤¢¤ë¡£
860
861     @return
862     ¤³¤Î´Ø¿ô¤Ï¿·¤·¤¯ºî¤é¤ì¤¿¡¢$PLIST ¤Î¥³¥Ô¡¼¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òÊÖ¤¹¡£    
863
864     @errors
865     ¤³¤Î´Ø¿ô¤Ï·è¤·¤Æ¼ºÇÔ¤·¤Ê¤¤¡£     */
866
867 MPlist *
868 mplist_copy (MPlist *plist)
869 {
870   MPlist *copy = mplist (), *pl = copy;
871
872   MPLIST_DO (plist, plist)
873     pl = mplist_add (pl, MPLIST_KEY (plist), MPLIST_VAL (plist));
874   return copy;
875 }
876
877 /*=*/
878
879 /***en
880     @brief Set the value of a property in a property list.
881
882     The mplist_put () function searches property list $PLIST
883     from the beginning for a property whose key is $KEY.  If such a
884     property is found, its value is changed to $VALUE.  Otherwise, a
885     new property whose key is $KEY and value is $VALUE is appended at
886     the end of $PLIST.  See the documentation of mplist_add () for
887     the restriction on $KEY and $VAL.
888
889     If $KEY is a managing key, $VAL must be a managed object.  In this
890     case, the reference count of the old value, if not @c NULL, is
891     decremented by one, and that of $VAL is incremented by one.
892
893     @return
894     If the operation was successful, mplist_put () returns a sublist of
895     $PLIST whose first element is the just modified or added one.
896     Otherwise, it returns @c NULL.  */
897 /***ja
898     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÀßÄꤹ¤ë.
899
900     ´Ø¿ô mplist_put () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ò»Ï¤á¤«¤éõ¤·¤Æ¡¢¥­¡¼¤¬
901     $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤ÎÃͤò $VALUE 
902     ¤ËÊѹ¹¤¹¤ë¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð¡¢¥­¡¼¤¬ $KEY ¤ÇÃͤ¬ $VALUE 
903     ¤Ç¤¢¤ë¿·¤·¤¤¥×¥í¥Ñ¥Æ¥£¤¬ $PLIST ¤ÎËöÈø¤ËÄɲ䵤ì¤ë¡£$KEY ¤È $VAL
904     ¤ËÂФ¹¤ëÀ©¸Â¤Ë¤Ä¤¤¤Æ¤Ï¡¢mplist_add () ¤ÎÀâÌÀ¤ò»²¾È¡£
905
906     $KEY ¤¬´ÉÍý¥­¡¼¤Ê¤é¤Ð¡¢
907     $VAL ¤Ï´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç¡¢¸Å¤¤Ãͤλ²¾È¿ô¤Ï 
908     @c NULL ¤Ç¤Ê¤±¤ì¤Ð 1 ¸º¤é¤µ¤ì¡¢$VAL ¤Î»²¾È¿ô¤Ï 1 Áý¤ä¤µ¤ì¤ë¡£
909
910     @return 
911     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mplist_put () ¤ÏÊѹ¹¤µ¤ì¤¿¤«Äɲ䵤줿Í×ÁǤ«¤é»Ï¤Þ¤ë
912     $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£   */
913
914 MPlist *
915 mplist_put (MPlist *plist, MSymbol key, void *val)
916 {
917   if (key == Mnil)
918     MERROR (MERROR_PLIST, NULL);
919   MPLIST_FIND (plist, key);
920   if (key->managing_key)
921     {
922       if (! MPLIST_TAIL_P (plist))
923         M17N_OBJECT_UNREF (MPLIST_VAL (plist));
924       if (val)
925         M17N_OBJECT_REF (val);
926     }
927   MPLIST_SET (plist, key, val);
928   return plist;
929 }
930
931 /*=*/
932
933 /***en
934     @brief Get the value of a property in a property list.
935
936     The mplist_get () function searches property list $PLIST
937     from the beginning for a property whose key is $KEY.  If such a
938     property is found, a pointer to its value is returned as the type
939     of <tt>(void *)</tt>.  If not found, @c NULL is returned.
940
941     When @c NULL is returned, there are two possibilities: one is the
942     case where no property is found (see above); the other is the case
943     where a property is found and its value is @c NULL.  In case that
944     these two cases must be distinguished, use the mplist_find_by_key ()
945     function.  */
946 /***ja
947     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÆÀ¤ë.
948
949     ´Ø¿ô mplist_get () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ò»Ï¤á¤«¤éõ¤·¤Æ¡¢¥­¡¼¤¬
950     $KEY ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤ÎÃͤؤΥݥ¤¥ó¥¿¤ò
951     <tt>(void *)</tt> ·¿¤ÇÊÖ¤¹¡£¸«¤Ä¤«¤é¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
952
953     @c NULL ¤¬Ê֤俺ݤˤÏÆó¤Ä¤Î²ÄǽÀ­¤¬¤¢¤ë: 
954     ¾åµ­¤Î¤è¤¦¤Ë¥×¥í¥Ñ¥Æ¥£¤¬¸«¤Ä¤«¤é¤Ê¤«¤Ã¤¿¾ì¹ç¤È¡¢¥×¥í¥Ñ¥Æ¥£¤¬¸«¤Ä¤«¤ê¡¢¤½¤ÎÃͤ¬
955     @c NULL ¤Ç¤¢¤ë¾ì¹ç¤Ç¤¢¤ë¡£¤³¤ì¤é¤ò¶èÊ̤¹¤ëɬÍפ¬¤¢¤ë¾ì¹ç¤Ë¤Ï´Ø¿ô 
956     mplist_find_by_key () ¤ò»È¤¦¤³¤È¡£  */
957
958 /***
959     @seealso
960     mplist_find_by_key () */
961
962 void *
963 mplist_get (MPlist *plist, MSymbol key)
964 {
965   MPLIST_FIND (plist, key);
966   return (MPLIST_TAIL_P (plist) ? NULL : MPLIST_VAL (plist));
967 }
968
969 /*=*/
970
971 /***en
972     @brief Add a property at the end of a property list.
973
974     The mplist_add () function appends at the end of property list
975     $PLIST a property whose key is $KEY and value is $VAL.  $KEY can
976     be any symbol other than @c Mnil.
977
978     If $KEY is a managing key, $VAL must be a managed object.  In this
979     case, the reference count of $VAL is incremented by one.
980
981     @return
982     If the operation was successful, mplist_add () returns a sublist of
983     $PLIST whose first element is the just added one.  Otherwise, it
984     returns @c NULL.  */
985 /***ja
986     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈËöÈø¤Ë¥×¥í¥Ñ¥Æ¥£¤òÄɲ乤ë.
987
988     ´Ø¿ô mplist_add () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ÎËöÈø¤Ë¥­¡¼¤¬ $KEY 
989     ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤òÄɲ乤롣$KEY ¤Ï¡¢@c Mnil °Ê³°¤ÎǤ°Õ¤Î¥·¥ó¥Ü¥ë¤Ç¤è¤¤¡£
990
991     $KEY ¤¬´ÉÍý¥­¡¼¤Ê¤é¤Ð¡¢$VAL ¤Ï´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç¡¢
992     $VAL ¤Î»²¾È¿ô¤Ï 1 Áý¤ä¤µ¤ì¤ë¡£
993
994     @return
995     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð mplist_add () ¤ÏÄɲ䵤줿Í×ÁǤ«¤é»Ï¤Þ¤ë $PLIST 
996     ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£  */
997
998 MPlist *
999 mplist_add (MPlist *plist, MSymbol key, void *val)
1000 {
1001   if (key == Mnil)
1002     MERROR (MERROR_PLIST, NULL);
1003   MPLIST_FIND (plist, Mnil);
1004   if (val && key->managing_key)
1005     M17N_OBJECT_REF (val);
1006   MPLIST_KEY (plist) = key;
1007   MPLIST_VAL (plist) = val;
1008   MPLIST_NEW (plist->next);
1009   return plist;
1010 }
1011
1012 /*=*/
1013
1014 /***en
1015     @brief Add a property at the beginning of a property list.
1016
1017     The mplist_push () function inserts at the beginning of property
1018     list $PLIST a property whose key is $KEY and value is $VAL.
1019
1020     If $KEY is a managing key, $VAL must be a managed object.  In this
1021     case, the reference count of $VAL is incremented by one.
1022
1023     @return
1024     If the operation was successful, this function returns $PLIST.
1025     Otherwise, it returns @c NULL.  */
1026 /***ja
1027     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎÀèƬ¤Ë¥×¥í¥Ñ¥Æ¥£¤òÁÞÆþ¤¹¤ë.
1028
1029     ´Ø¿ô mplist_push () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ÎÀèƬ¤Ë¥­¡¼¤¬ $KEY 
1030     ¤ÇÃͤ¬ $VAL ¤Ç¤¢¤ë¥ª¥Ö¥¸¥§¥¯¥È¤òÁÞÆþ¤¹¤ë¡£
1031
1032     $KEY ¤¬´ÉÍý¥­¡¼¤Ê¤é¤Ð¡¢$VAL ¤Ï´ÉÍý²¼¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç¡¢
1033     $VAL ¤Î»²¾È¿ô¤Ï 1 Áý¤ä¤µ¤ì¤ë¡£
1034
1035     @return
1036     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¤³¤Î´Ø¿ô¤Ï $PLIST ¤òÊÖ¤·¡¢¤½¤¦¤Ç¤Ê¤±¤ì¤Ð@c NULL 
1037     ¤òÊÖ¤¹¡£  */
1038
1039 MPlist *
1040 mplist_push (MPlist *plist, MSymbol key, void *val)
1041 {
1042   MPlist *pl;
1043
1044   if (key == Mnil)
1045     MERROR (MERROR_PLIST, NULL);
1046   MPLIST_NEW (pl);
1047   MPLIST_KEY (pl) = MPLIST_KEY (plist);
1048   MPLIST_VAL (pl) = MPLIST_VAL (plist);
1049   MPLIST_NEXT (pl) = MPLIST_NEXT (plist);
1050   plist->next = pl;
1051   if (val && key->managing_key)
1052     M17N_OBJECT_REF (val);
1053   MPLIST_KEY (plist) = key;
1054   MPLIST_VAL (plist) = val;
1055   return plist;
1056 }
1057
1058 /*=*/
1059
1060 /***en
1061     @brief Remove a property at the beginning of a property list.
1062
1063     The mplist_pop () function removes a property at the beginning of
1064     property list $PLIST.  As a result, the second key and value of
1065     the original $PLIST become the first of those of the new $PLIST.
1066
1067     @return
1068     If the operation was successful, this function return the value of
1069     the just popped property.  Otherwise, it returns @c NULL.  */
1070 /***ja
1071     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎÀèƬ¤«¤é¥×¥í¥Ñ¥Æ¥£¤òºï½ü¤¹¤ë.
1072
1073     ´Ø¿ô mplist_pop () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1074     ¤ÎÀèƬ¤Î¥×¥í¥Ñ¥Æ¥£¤òºï½ü¤¹¤ë¡£·ë²Ì¤È¤·¤Æ¡¢¸µ¤Î $PLIST ¤Î2ÈÖÌܤΥ­¡¼¤ÈÃͤ¬¡¢¿·¤·¤¤ 
1075     $PLIST ¤ÎÀèƬ¤Î¥­¡¼¤ÈÃͤˤʤ롣
1076
1077     @return 
1078     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ïºï½ü¤µ¤ì¤¿¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð
1079     @c NULL ¤òÊÖ¤¹¡£  */
1080
1081 void *
1082 mplist_pop (MPlist *plist)
1083 {
1084   void *val;
1085   MPlist *next;
1086
1087   if (MPLIST_TAIL_P (plist))
1088     return NULL;
1089   val = MPLIST_VAL (plist);
1090   next = MPLIST_NEXT (plist);
1091   MPLIST_KEY (plist) = MPLIST_KEY (next);
1092   MPLIST_VAL (plist) = MPLIST_VAL (next);
1093   if (MPLIST_KEY (plist) != Mnil
1094       && MPLIST_KEY (plist)->managing_key
1095       && MPLIST_VAL (plist))
1096     M17N_OBJECT_REF (MPLIST_VAL (plist));
1097   MPLIST_NEXT (plist) = MPLIST_NEXT (next);
1098   if (plist->next)
1099     M17N_OBJECT_REF (plist->next);
1100   M17N_OBJECT_UNREF (next);
1101   return val;
1102 }
1103
1104 /*=*/
1105 /***en
1106     @brief Find a property of a specific key in a property list.
1107
1108     The mplist_find_by_key () function searches property list
1109     $PLIST from the beginning for a property whose key is $KEY.  If
1110     such a property is found, a sublist of $PLIST whose first element
1111     is the found one is returned.  Otherwise, @c NULL is returned.
1112
1113     If $KEY is @c Mnil, it returns a sublist of $PLIST whose
1114     first element is the last one of $PLIST.  */
1115 /***ja
1116     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃ椫¤é»ØÄê¤Î¥­¡¼¤ò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤òõ¤¹.
1117
1118     ´Ø¿ô mplist_find_by_key () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1119     ¤ò»Ï¤á¤«¤éõ ¤·¤Æ¡¢¥­¡¼¤¬ $KEY 
1120     ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤«¤é»Ï¤Þ¤ë
1121     $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£
1122
1123     $KEY ¤¬ @c Mnil ¤Ê¤é¤Ð¡¢$PLIST ¤ÎºÇ¸å¤ÎÍ×ÁǤ«¤é»Ï¤Þ¤ëÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£  */
1124
1125 MPlist *
1126 mplist_find_by_key (MPlist *plist, MSymbol key)
1127 {
1128   MPLIST_FIND (plist, key);
1129   return (MPLIST_TAIL_P (plist)
1130           ? (key == Mnil ? plist : NULL)
1131           : plist);
1132 }
1133
1134 /*=*/
1135 /***en
1136     @brief Find a property of a specific value in a property list.
1137
1138     The mplist_find_by_value () function searches property list $PLIST
1139     from the beginning for a property whose value is $VAL.  If such a
1140     property is found, a sublist of $PLIST whose first element is the
1141     found one is returned.  Otherwise, @c NULL is returned.  */
1142 /***ja
1143     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃ椫¤é»ØÄê¤ÎÃͤò»ý¤Ä¥×¥í¥Ñ¥Æ¥£¤òõ¤¹.
1144
1145     ´Ø¿ô mplist_find_by_value () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1146     ¤ò»Ï¤á¤«¤éõ¤·¤Æ¡¢Ãͤ¬ $VAL 
1147     ¤Ç¤¢¤ë¥×¥í¥Ñ¥Æ¥£¤ò¸«¤Ä¤±¤ë¡£¸«¤Ä¤«¤ì¤Ð¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤«¤é»Ï¤Þ¤ë
1148     $PLIST ¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£ */
1149
1150 MPlist *
1151 mplist_find_by_value (MPlist *plist, void *val)
1152 {
1153   MPLIST_DO (plist, plist)
1154     {
1155       if (MPLIST_VAL (plist) == val)
1156         return plist;
1157     }
1158   return NULL;
1159 }
1160
1161 /*=*/
1162
1163 /***en
1164     @brief Return the next sublist of a property list.
1165
1166     The mplist_next () function returns a pointer to the sublist of
1167     property list $PLIST, which begins at the second element in $PLIST.  If the
1168     length of $PLIST is zero, it returns @c NULL.  */
1169 /***ja
1170     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Î¼¡¤ÎÉôʬ¥ê¥¹¥È¤òÊÖ¤¹.
1171
1172     ´Ø¿ô mplist_next () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤Î 2 
1173     ÈÖÌܤÎÍ×ÁǤ«¤é»Ï¤Þ¤ëÉôʬ¥ê¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$PLIST ¤ÎŤµ¤¬ 0 
1174     ¤Ê¤é¤Ð @c NULL ¤òÊÖ¤¹¡£  */
1175
1176 MPlist *
1177 mplist_next (MPlist *plist)
1178 {
1179   return (MPLIST_TAIL_P (plist) ? NULL : plist->next);
1180 }
1181
1182 /*=*/
1183
1184 /***en
1185     @brief Set the first property in a property list.
1186
1187     The mplist_set () function sets the key and the value of the first
1188     property in property list $PLIST to $KEY and $VALUE, respectively.
1189     See the documentation of mplist_add () for the restriction on $KEY
1190     and $VAL.
1191
1192     @return
1193     If the operation was successful, mplist_set () returns $PLIST.
1194     Otherwise, it returns @c NULL.  */
1195 /***ja
1196     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤òÀßÄꤹ¤ë.
1197
1198     ´Ø¿ô mplist_set () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1199     ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤ÈÃͤò¤½¤ì¤¾¤ì $KEY ¤È $VALUE ¤ËÀßÄꤹ¤ë¡£
1200     $KEY ¤È $VAL ¤ËÂФ¹¤ëÀ©¸Â¤Ë¤Ä¤¤¤Æ¤Ï¡¢mplist_add () ¤ÎÀâÌÀ¤ò»²¾È¡£
1201
1202     @return
1203     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mplist_set () ¤Ï $PLIST ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤¹¡£  */
1204
1205 MPlist *
1206 mplist_set (MPlist *plist, MSymbol key, void * val)
1207 {
1208   if (key == Mnil)
1209     {
1210       if (! MPLIST_TAIL_P (plist))
1211         {
1212           key = MPLIST_KEY (plist);
1213           M17N_OBJECT_UNREF (MPLIST_NEXT (plist));
1214           MPLIST_KEY (plist) = Mnil;
1215           if (key->managing_key)
1216             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1217           plist->next = NULL;
1218         }
1219     }
1220   else
1221     {
1222       if (! MPLIST_TAIL_P (plist)
1223           && MPLIST_KEY (plist)->managing_key)
1224         M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1225       if (val && key->managing_key)
1226         M17N_OBJECT_REF (val);
1227       MPLIST_SET (plist, key, val);
1228     }
1229   return plist;
1230 }
1231
1232 /*=*/
1233
1234 /***en
1235     @brief Return the length of a property list.
1236
1237     The mplist_length () function returns the number of properties in
1238     property list  $PLIST.  */
1239 /***ja
1240     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ÎŤµ¤òÊÖ¤¹.
1241
1242     ´Ø¿ô mplist_length () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST Ãæ¤Î¥×¥í¥Ñ¥Æ¥£¤Î¿ô¤òÊÖ¤¹¡£  */
1243
1244 int
1245 mplist_length (MPlist *plist)
1246 {
1247   int n;
1248
1249   for (n = 0; ! (MPLIST_TAIL_P (plist)); n++, plist = plist->next);
1250   return n;
1251 }
1252
1253 /*=*/
1254
1255 /***en
1256     @brief Return the key of the first property in a property list.
1257
1258     The mplist_key () function returns the key of the first property
1259     in property list $PLIST.  If the length of $PLIST is zero,
1260     it returns @c Mnil.  */
1261 /***ja
1262     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤òÊÖ¤¹.
1263
1264     ´Ø¿ô mplist_key () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST 
1265     Ãæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤Î¥­¡¼¤òÊÖ¤¹¡£$PLIST ¤ÎŤµ¤¬ 0 ¤Ê¤é¤Ð¡¢ @c Mnil 
1266     ¤òÊÖ¤¹¡£  */
1267
1268 MSymbol
1269 mplist_key (MPlist *plist)
1270 {
1271   return MPLIST_KEY (plist);
1272 }
1273
1274 /*=*/
1275
1276 /***en
1277     @brief Return the value of the first property in a property list.
1278
1279     The mplist_value () function returns the value of the first
1280     property in property list  $PLIST.  If the length of $PLIST
1281     is zero, it returns @c NULL.  */
1282 /***ja
1283     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥ÈÃæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹.
1284
1285     ´Ø¿ô mplist_value () ¤Ï¡¢¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST Ãæ¤ÎºÇ½é¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤòÊÖ¤¹¡£
1286     $PLIST ¤ÎŤµ¤¬ 0 ¤Ê¤é¤Ð¡¢ @c Mnil ¤òÊÖ¤¹¡£  */
1287
1288 void *
1289 mplist_value (MPlist *plist)
1290 {
1291   return MPLIST_VAL (plist);
1292 }
1293
1294 /***en
1295     @brief Generate a property list by deserializaing an M-text.
1296
1297     The mplist_deserialize () function parses M-text $MT and returns a
1298     property list.
1299
1300     The syntax of $MT is as follows.
1301
1302     MT ::= '(' ELEMENT * ')'
1303
1304     ELEMENT ::= SYMBOL | INTEGER | M-TEXT | PLIST
1305
1306     SYMBOL ::= ascii-character-sequence
1307
1308     INTEGER ::= '-' ? [ '0' | .. | '9' ]+
1309                 | '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
1310
1311     M-TEXT ::= '"' character-sequence '"'
1312
1313     Each alternatives of @c ELEMENT is assigned one of these keys: @c
1314     Msymbol, @c Minteger, @c Mtext, @c Mplist
1315
1316     In an ascii-character-sequence, a backslash (\) is used as the escape
1317     character, which means that, for instance, <tt>"abc\ def"</tt>
1318     produces a symbol whose name is of length seven with the fourth
1319     character being a space.  */
1320 /***ja
1321     @brief M-text ¤ò¥Ç¥·¥ê¥¢¥é¥¤¥º¤·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òºî¤ë.
1322
1323     ´Ø¿ô mplist_deserialize () ¤Ï M-text $MT ¤ò²òÀϤ·¤Æ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤òÊÖ¤¹¡£
1324
1325     $MT ¤Î¥·¥ó¥¿¥Ã¥¯¥¹¤Ï°Ê²¼¤ÎÄ̤ꡣ
1326
1327     MT ::= '(' ELEMENT * ')'
1328
1329     ELEMENT ::= SYMBOL | INTEGER | M-TEXT | PLIST
1330
1331     SYMBOL ::= ¥¢¥¹¥­¡¼Ê¸»úÎó
1332
1333     INTEGER ::= '-' ? [ '0' | .. | '9' ]+
1334                 | '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
1335
1336     M-TEXT ::= '"' character-sequence '"'
1337
1338     @c ELEMENT ¤Î³ÆÁªÂò»è¤Ï¥­¡¼¡§@c Msymbol, @c Minteger, @c Mtext,
1339     @c Mplist ¤Î¤¤¤º¤ì¤«¤ò³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¡£
1340
1341     ¥¢¥¹¥­¡¼Ê¸»úÎóÆâ¤Ç¤Ï¡¢¥Ð¥Ã¥¯¥¹¥é¥Ã¥·¥å (\) ¤¬¥¨¥¹¥±¡¼¥×ʸ»ú¤È¤·¤ÆÍѤ¤¤é¤ì¤ë¡£¤¿¤È¤¨¤Ð
1342     <tt>"abc\ def"</tt> ¤Ï 4 Ê¸»úÌܤ¬¶õÇòʸ»ú¤Ç¤¢¤êŤµ¤¬ 7 
1343     ¤Ç¤¢¤ë»ý¤Ä̾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë¤òÀ¸À®¤¹¤ë¡£   */
1344
1345 MPlist *
1346 mplist_deserialize (MText *mt)
1347 {
1348   MPlist *plist;
1349   MText *tmp = NULL;
1350
1351   if (mt->format > MTEXT_FORMAT_UTF_8)
1352     {
1353       if (MTEXT_READ_ONLY_P (mt))
1354         mt = tmp = mtext_cpy (mtext (), mt);
1355       else
1356         mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
1357     }
1358   plist = mplist__from_string (MTEXT_DATA (mt), mtext_nbytes (mt));
1359   if (tmp)
1360     M17N_OBJECT_UNREF (tmp);
1361   return plist;
1362 }
1363
1364 /*** @}  */
1365
1366 /*** @addtogroup m17nDebug */
1367 /*=*/
1368 /*** @{  */
1369
1370 /***en
1371     @brief Dump a property list.
1372
1373     The mdebug_dump_plist () function prints a property list $PLIST in
1374     a human readable way to the stderr.  $INDENT specifies how many
1375     columns to indent the lines but the first one.
1376
1377     @return
1378     This function returns $PLIST.  */
1379 /***ja
1380     @brief ¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤ò¥À¥ó¥×¤¹¤ë.
1381
1382     ´Ø¿ô mdebug_dump_plist () ¤Ï¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È $PLIST ¤ò stderr 
1383     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
1384
1385     @return
1386     ¤³¤Î´Ø¿ô¤Ï $PLIST ¤òÊÖ¤¹¡£  */
1387 MPlist *
1388 mdebug_dump_plist (MPlist *plist, int indent)
1389 {
1390   char *prefix = (char *) alloca (indent + 1);
1391   MPlist *pl;
1392   int first = 1;
1393
1394   memset (prefix, 32, indent);
1395   prefix[indent] = 0;
1396
1397   fprintf (stderr, "(");
1398   MPLIST_DO (pl, plist)
1399     {
1400       if (first)
1401         first = 0;
1402       else
1403         fprintf (stderr, "\n%s ", prefix);
1404       dump_plist_element (pl, indent + 2);
1405     }
1406   fprintf (stderr, ")");
1407   return plist;
1408 }
1409
1410 /*** @} */
1411
1412 /*
1413   Local Variables:
1414   coding: euc-japan
1415   End:
1416 */