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