(mplist_deserialize): Renamed from mplist__deserialize.
[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
37 /*=*/
38
39 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
40 /*** @addtogroup m17nInternal
41      @{ */
42
43 #include <stdio.h>
44 #include <string.h>
45
46 #include "m17n.h"
47 #include "m17n-misc.h"
48 #include "internal.h"
49 #include "character.h"
50 #include "mtext.h"
51 #include "symbol.h"
52 #include "plist.h"
53
54 static M17NObjectArray plist_table;
55
56 /** Set PLIST to a newly allocated plist object.  */
57
58 #define MPLIST_NEW(plist)                               \
59   do {                                                  \
60     M17N_OBJECT (plist, free_plist, MERROR_PLIST);      \
61     M17N_OBJECT_REGISTER (plist_table, plist);          \
62   } while (0)
63
64
65 /** Set the element of PLIST to KEY and VAL.  If PLIST is an anchor,
66     append a new anchor.  */
67
68 #define MPLIST_SET(plist, key, val)     \
69   do {                                  \
70     MPLIST_KEY (plist) = (key);         \
71     MPLIST_VAL (plist) = (val);         \
72     if (! (plist)->next)                \
73       MPLIST_NEW ((plist)->next);       \
74   } while (0)
75
76
77 /** Set the element of PLIST to KEY and VAL.  PLIST must be an anchor.
78     Append a new anchor and set PLIST to that anchor.  */
79
80 #define MPLIST_SET_ADVANCE(plist, key, val)     \
81   do {                                          \
82     MPLIST_KEY (plist) = (key);                 \
83     MPLIST_VAL (plist) = (val);                 \
84     MPLIST_NEW ((plist)->next);                 \
85     plist = (plist)->next;                      \
86   } while (0)
87
88
89 static void
90 free_plist (void *object)
91 {
92   MPlist *plist = (MPlist *) object;
93
94   do {
95     MPlist *next = plist->next;
96
97     if (MPLIST_KEY (plist) != Mnil && MPLIST_KEY (plist)->managing_key)
98       M17N_OBJECT_UNREF (MPLIST_VAL (plist));
99     M17N_OBJECT_UNREGISTER (plist_table, plist);
100     free (plist);
101     plist = next;
102   } while (plist && plist->control.ref_count == 1);
103   M17N_OBJECT_UNREF (plist);
104 }
105
106 \f
107
108 /* Load a plist from a string.  */
109
110 #define READ_CHUNK 0x10000
111
112 typedef struct
113 {
114   /* File pointer if the stream is associated with a file.  Otherwise
115      NULL.  */
116   FILE *fp;
117   int eof;
118   unsigned char buffer[READ_CHUNK];
119   unsigned char *p, *pend;
120 } MStream;
121
122 static int
123 get_byte (MStream *st)
124 {
125   int n;
126
127   if (! st->fp || st->eof)
128     return EOF;
129   n = fread (st->buffer, 1, READ_CHUNK, st->fp);
130   if (n <= 0)
131     {
132       st->eof = 1;
133       return EOF;
134     }
135   st->p = st->buffer + 1;
136   st->pend = st->buffer + n;
137   return st->buffer[0];
138 }
139
140 #define GETC(st)        \
141   ((st)->p < (st)->pend ? *(st)->p++ : get_byte (st))
142
143
144 #define UNGETC(c, st)   \
145   (*--(st)->p = (c))
146
147 /** Mapping table for reading a number.  Hexadecimal chars
148     (0..9,A..F,a..F) are mapped to the corresponding numbers.
149     Apostrophe (code 39) is mapped to 254.  All the other bytes are
150     mapped to 255.  */
151 unsigned char hex_mnemonic[256];
152
153 /** Mapping table for escaped characters.  Mnemonic characters (e, b,
154     f, n, r, or t) that follows '\' are mapped to the corresponding
155     character code.  All the other bytes are mapped to themselves.  */
156 unsigned char escape_mnemonic[256];
157
158
159 /** Read an integer from the stream ST.  It is assumed that we have
160     already read one character C.  */
161
162 static int
163 read_decimal (MStream *st, int c)
164 {
165   int num = 0;
166
167   while (c >= '0' && c <= '9')
168     {
169       num = (num * 10) + (c - '0');
170       c = GETC (st);
171     }
172
173   if (c != EOF)
174     UNGETC (c, st);
175   return num;
176 }
177
178 /** Read an unsigned from the stream ST.  */
179
180 static unsigned
181 read_hexadesimal (MStream *st)
182 {
183   int c;
184   unsigned num = 0, n;
185
186   while ((c = GETC (st)) != EOF
187          && (n = hex_mnemonic[c]) < 16)
188     num = (num << 4) | n;
189   if (c != EOF)
190     UNGETC (c, st);
191   return num;
192 }
193
194
195 /** Read an M-text element from ST, and add it to LIST.  Return a list
196     for the next element.  */
197
198 static MPlist *
199 read_mtext_element (MPlist *plist, MStream *st)
200 {
201   unsigned char buffer[1024];
202   int bufsize = 1024;
203   unsigned char *buf = buffer;
204   int c, i;
205
206   i = 0;
207   while ((c = GETC (st)) != EOF && c != '"')
208     {
209       if (i + MAX_UTF8_CHAR_BYTES >= bufsize)
210         {
211           bufsize *= 2;
212           if (buf == buffer)
213             {
214               MTABLE_MALLOC (buf, bufsize, MERROR_PLIST);
215               memcpy (buf, buffer, i);
216             }
217           else
218             MTABLE_REALLOC (buf, bufsize, MERROR_PLIST);
219         }
220
221       if (c == '\\')
222         {
223           c = GETC (st);
224           if (c == EOF)
225             break;
226           if (c == 'x')
227             {
228               int next_c;
229
230               c = read_hexadesimal (st);
231               next_c = GETC (st);
232               if (next_c != ' ')
233                 UNGETC (next_c, st);
234             }
235           else
236             c = escape_mnemonic[c];
237         }
238
239       buf[i++] = c;
240     }
241
242   MPLIST_SET_ADVANCE (plist, Mtext,
243                       mtext__from_data (buf, i, MTEXT_FORMAT_UTF_8, 1));
244   if (buf != buffer)
245     free (buf);
246   return plist;
247 }
248
249 static int
250 read_character (MStream *st, int c)
251 {
252   unsigned char buf[MAX_UTF8_CHAR_BYTES + 1];
253   int len = CHAR_BYTES_BY_HEAD (c);
254   int i;
255
256   buf[0] = c;
257   for (i = 1; i < len; i++)
258     {
259       c = GETC (st);
260       if (c == EOF
261           || (c & 0xC0) != 0x80)
262         break;
263       buf[i] = c;
264     }
265   if (i == len)
266     c = STRING_CHAR_UTF8 (buf);
267   else
268     c = buf[0];
269   return c;
270 }
271
272
273 /** Read an integer element from ST, and add it to LIST.  Return a
274     list for the next element.  It is assumed that we have already
275     read the character C. */
276
277 static MPlist *
278 read_integer_element (MPlist *plist, MStream *st, int c)
279 {
280   int num;
281
282   if (c == '0' || c == '#')
283     {
284       c = GETC (st);
285       if (c == 'x')
286         num = read_hexadesimal (st);
287       else
288         num = read_decimal (st, c);
289     }
290   else if (c == '?')
291     {
292       c = GETC (st);
293       if (c == EOF)
294         num = 0;
295       else if (c != '\\')
296         {
297           if (c < 128 || ! CHAR_UNITS_BY_HEAD_UTF8 (c))
298             num = c;
299           else
300             num = read_character (st, c);
301         }
302       else
303         {
304           c = GETC (st);
305           if (c == EOF)
306             num = '\\';
307           else if (c < 128 || ! CHAR_UNITS_BY_HEAD_UTF8 (c))
308             num = escape_mnemonic[c];
309           else
310             num = read_character (st, c);
311         }
312     }
313   else if (c == '-')
314     num = - read_decimal (st, GETC (st));
315   else
316     num = read_decimal (st, c);
317
318   MPLIST_SET_ADVANCE (plist, Minteger, (void *) num);
319   return plist;
320 }
321
322 /** Read a symbol element from ST, and add it to LIST.  Return a list
323     for the next element.  */
324
325 static MPlist *
326 read_symbol_element (MPlist *plist, MStream *st)
327 {
328   unsigned char buffer[1024];
329   int bufsize = 1024;
330   unsigned char *buf = buffer;
331   int c, i;
332
333   i = 0;
334   while ((c = GETC (st)) != EOF
335          && c > ' '
336          && c != ')' && c != '(' && c != '"')
337     {
338       if (i >= bufsize)
339         {
340           bufsize *= 2;
341           if (buf == buffer)
342             {
343               MTABLE_MALLOC (buf, bufsize, MERROR_PLIST);
344               memcpy (buf, buffer, i);
345             }
346           else
347             MTABLE_REALLOC (buf, bufsize, MERROR_PLIST);
348         }
349       if (c == '\\')
350         {
351           c = GETC (st);
352           if (c == EOF)
353             break;
354           c = escape_mnemonic[c];
355         }
356       buf[i++] = c;
357     }
358
359   buf[i] = 0;
360   MPLIST_SET_ADVANCE (plist, Msymbol, msymbol ((char *) buf));
361   if (buf != buffer)
362     free (buf);
363   if (c > ' ')
364     UNGETC (c, st);
365   return plist;
366 }
367
368 /* Read an element of various type from stream ST, and add it to LIST.
369    Return a list for the next element.  The element type is decided by
370    the first token character found as below:
371         '(': plist
372         '"': mtext
373         '0'..'9', '-': integer
374         '?': integer representing character code
375         the other ASCII letters: symbol
376 */
377
378 static MPlist *
379 read_element (MPlist *plist, MStream *st)
380 {
381   int c;
382
383   /* Skip separators and comments.  */
384   while (1)
385     {
386       while ((c = GETC (st)) != EOF && c <= ' ');
387       if (c != ';')
388         break;
389       while ((c = GETC (st)) != EOF && c != '\n');
390       if (c == EOF)
391         break;
392     }
393
394   if (c == '(')
395     {
396       MPlist *pl, *p;
397
398       MPLIST_NEW (pl);
399       p = pl;
400       while ((p = read_element (p, st)));
401       MPLIST_SET_ADVANCE (plist, Mplist, pl);
402       return plist;
403     }
404   if (c == '"')
405     return read_mtext_element (plist, st);
406   if ((c >= '0' && c <= '9') || c == '-' || c == '?' || c == '#')
407     return read_integer_element (plist, st, c);
408   if (c == EOF || c == ')')
409     return NULL;
410   UNGETC (c, st);
411   return read_symbol_element (plist, st);
412 }
413
414 void
415 write_element (MText *mt, MPlist *plist)
416 {
417   if (MPLIST_SYMBOL_P (plist))
418     {
419       MSymbol sym = MPLIST_SYMBOL (plist);
420
421       if (sym == Mnil)
422         {
423           MTEXT_CAT_ASCII (mt, "nil");
424         }
425       else
426         {
427           char *name = MSYMBOL_NAME (sym);
428           char *buf = alloca (MSYMBOL_NAMELEN (sym) * 2 + 1), *p = buf;
429
430           while (*name)
431             {
432               if (*name <= ' ' || *name == '"' || *name == ')' || *name == ')')
433                 *p++ = '\\';
434               *p++ = *name++;
435             }
436           *p = '\0';
437           MTEXT_CAT_ASCII (mt, buf);
438         }
439     }
440   else if (MPLIST_INTEGER_P (plist))
441     {
442       int num = MPLIST_INTEGER (plist);
443       char buf[128];
444
445       sprintf (buf, "%d", num);
446       MTEXT_CAT_ASCII (mt, buf);
447     }
448   else if (MPLIST_PLIST_P (plist))
449     {
450       MPlist *pl;
451
452       plist = MPLIST_PLIST (plist);
453       mtext_cat_char (mt, '(');
454       MPLIST_DO (pl, plist)
455         {
456           if (pl != plist)
457             mtext_cat_char (mt, ' ');
458           write_element (mt, pl);
459         }
460       mtext_cat_char (mt, ')');
461     }
462   else if (MPLIST_MTEXT_P (plist))
463     {
464       mtext_cat_char (mt, '"');
465       /* Not yet implemnted */
466       mtext_cat_char (mt, '"');
467     }
468 }
469
470 /* Support functions for mdebug_dump_plist.  */
471
472 static void
473 dump_string (char *str)
474 {
475   char *p = str, *pend = p + strlen (p), *new, *p1;
476
477   new = p1 = alloca ((pend - p) * 4 + 1);
478   while (p < pend)
479     {
480       if (*p < 0)
481         {
482           sprintf (p1, "\\x%02X", (unsigned char) *p);
483           p1 += 4;
484         }
485       else if (*p < ' ')
486         {
487           *p1++ = '^';
488           *p1++ = *p + '@';
489         }
490       else if (*p == ' ')
491         {
492           *p1++ = '\\';
493           *p1++ = ' ';
494         }
495       else
496         *p1++ = *p;
497       p++;
498     }
499   *p1 = '\0';
500   fprintf (stderr, "%s", new);
501 }
502
503 static void
504 dump_plist_element (MPlist *plist, int indent)
505 {
506   char *prefix = (char *) alloca (indent + 1);
507   MSymbol key;
508
509   memset (prefix, 32, indent);
510   prefix[indent] = 0;
511
512   key = MPLIST_KEY (plist);
513   fprintf (stderr, "(%s(#%d) ", msymbol_name (MPLIST_KEY (plist)),
514            plist->control.ref_count);
515   if (key == Msymbol)
516     dump_string (msymbol_name (MPLIST_SYMBOL (plist)));
517   else if (key == Mtext)
518     mdebug_dump_mtext (MPLIST_MTEXT (plist), indent, 0);
519   else if (key == Minteger)
520     fprintf (stderr, "%x", MPLIST_INTEGER (plist));
521   else if (key == Mstring) 
522     fprintf (stderr, "\"%s\"", MPLIST_STRING (plist));
523   else if (key == Mplist)
524     {
525       fprintf (stderr, "\n%s", prefix);
526       mdebug_dump_plist (MPLIST_PLIST (plist), indent);
527     }
528   else
529     fprintf (stderr, "0x%X", (unsigned) MPLIST_VAL (plist));
530   fprintf (stderr, ")");
531 }
532
533 \f
534 /* Internal API */
535 int
536 mplist__init ()
537 {
538   int i;
539
540   plist_table.count = 0;
541
542   Minteger = msymbol ("integer");
543   Mplist = msymbol_as_managing_key ("plist");
544   Mtext = msymbol_as_managing_key ("mtext");
545
546   for (i = 0; i < 256; i++)
547     hex_mnemonic[i] = 255;
548   for (i = '0'; i <= '9'; i++)
549     hex_mnemonic[i] = i - '0';
550   for (i = 'A'; i <= 'F'; i++)
551     hex_mnemonic[i] = i - 'A' + 10;
552   for (i = 'a'; i <= 'f'; i++)
553     hex_mnemonic[i] = i - 'a' + 10;
554   for (i = 0; i < 256; i++)
555     escape_mnemonic[i] = i;
556   escape_mnemonic['e'] = 27;
557   escape_mnemonic['b'] = '\b';
558   escape_mnemonic['f'] = '\f';
559   escape_mnemonic['n'] = '\n';
560   escape_mnemonic['r'] = '\r';
561   escape_mnemonic['t'] = '\t';
562   escape_mnemonic['\\'] = '\\';
563
564   return 0;
565 }
566
567 void
568 mplist__fini (void)
569 {
570   mdebug__report_object ("Plist", &plist_table);
571 }
572
573
574 /* Parse this form of PLIST:
575       (symbol:KEY1 TYPE1:VAL1 symbol:KEY2 TYPE2:VAL2 ...)
576    and return a newly created plist of this form:
577       (KEY1:VAL1 KEY2:VAL2 ...)  */
578
579 MPlist *
580 mplist__from_plist (MPlist *plist)
581 {
582   MPlist *pl, *p;
583
584   MPLIST_NEW (pl);
585   p = pl;
586   while (! MPLIST_TAIL_P (plist))
587     {
588       MSymbol key, type;
589
590       if (! MPLIST_SYMBOL_P (plist))
591         MERROR (MERROR_PLIST, NULL);
592       key = MPLIST_SYMBOL (plist);
593       plist = MPLIST_NEXT (plist);
594       type = MPLIST_KEY (plist);
595       if (type->managing_key)
596         M17N_OBJECT_REF (MPLIST_VAL (plist));
597       MPLIST_SET_ADVANCE (p, key, MPLIST_VAL (plist));
598       plist = MPLIST_NEXT (plist);
599     }
600   return pl;
601 }
602
603 /** Parse this form of PLIST:
604       ((symbol:KEY1 ANY:VAL1 ... ) (symbol:KEY2 ANY:VAL2 ...) ...)
605     and return a newly created plist of this form:
606       (KEY1:(ANY:VAL1 ...) KEY2:(ANY:VAL2 ...) ...)
607     ANY can be any type.  */
608
609 MPlist *
610 mplist__from_alist (MPlist *plist)
611 {
612   MPlist *pl, *p;
613
614   MPLIST_NEW (pl);
615   p = pl;
616   MPLIST_DO (plist, plist)
617     {
618       MPlist *elt;
619
620       if (! MPLIST_PLIST_P (plist))
621         MERROR (MERROR_PLIST, NULL);
622       elt = MPLIST_PLIST (plist);
623       if (! MPLIST_SYMBOL_P (elt))
624         MERROR (MERROR_PLIST, NULL);
625       MPLIST_SET_ADVANCE (p, MPLIST_SYMBOL (elt), MPLIST_NEXT (elt));
626       M17N_OBJECT_REF (MPLIST_NEXT (elt));
627     }
628   return pl;
629 }
630
631
632 MPlist *
633 mplist__from_file (FILE *fp)
634 {
635   MPlist *plist, *pl;
636   MStream st;
637
638   st.fp = fp;
639   st.eof = 0;
640   st.p = st.pend = st.buffer;
641   MPLIST_NEW (plist);
642   pl = plist;
643   while ((pl = read_element (pl, &st)));
644   return plist;
645 }
646
647
648 /** Parse $STR of $N bytes and return a property list object.  $FORMAT
649     must be either @c MTEXT_FORMAT_US_ASCII or @c MTEXT_FORMAT_UTF_8,
650     and controls how to produce @c STRING or @c M-TEXT in the
651     following definition.
652
653     The syntax of $STR is as follows.
654
655     PLIST ::= '(' ELEMENT * ')'
656
657     ELEMENT ::= SYMBOL | INTEGER | UNSIGNED | STRING | M-TEXT | PLIST
658
659     SYMBOL ::= ascii-character-sequence
660
661     INTEGER ::= '-' ? [ '0' | .. | '9' ]+
662
663     UNSIGNED ::= '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
664
665     M-TEXT ::= '"' byte-sequence '"'
666
667     Each kind of @c ELEMENT is assigned one of these keys:
668         @c Msymbol, @c Mint, @c Munsigned, @c Mtext, @c Mplist
669
670     In an ascii-character-sequence, a backslush (\) is used as the escape
671     character, which means that, for instance, <tt>"abc\ def"</tt>
672     produces a symbol whose name is of length seven with the fourth
673     character being a space.
674
675     In a byte-sequence, "\r", "\n", "\e", and "\t" are replaced by CR,
676     NL, ESC, and TAB character respectively, "\xXX" are replaced by
677     byte 0xXX.  After this replacement, the byte-sequence is decoded
678     into M-TEXT by $CODING.  */
679
680 MPlist *
681 mplist__from_string (unsigned char *str, int n)
682 {
683   MPlist *plist, *pl;
684   MStream st;
685
686   st.fp = NULL;
687   st.eof = 0;
688   st.p = str;
689   st.pend = str + n;
690   MPLIST_NEW (plist);
691   pl = plist;
692   while ((pl = read_element (pl, &st)));
693   return plist;
694 }
695
696 int
697 mplist__serialize (MText *mt, MPlist *plist)
698 {
699   MPlist *pl;
700
701   MPLIST_DO (pl, plist)
702     {
703       if (pl != plist)
704         mtext_cat_char (mt, ' ');
705       write_element (mt, pl);
706     }
707   return 0;
708 }
709
710 /*** @} */
711 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
712
713 \f
714 /* External API */
715
716 /*** @addtogroup m17nPlist */
717 /*** @{ */
718 /*=*/
719
720 /***en
721     @brief Symbol whose name is "integer".
722
723     The symbol @c Minteger has the name <tt>"integer"</tt>.  A value
724     of a plist whose key is @c Minteger must be an integer.  */
725
726 MSymbol Minteger;
727 /*=*/
728
729 /***en
730     @brief Symbol whose name is "plist".
731
732     The symbol @c Mplist has the name <tt>"plist"</tt>.  It is a
733     managing key.  A value of a plist whose key is @c Mplist must be a
734     plist.  */
735
736 MSymbol Mplist;
737 /*=*/
738
739 /***en
740     @brief Symbol whose name is "mtext".
741
742     The symbol @c Mtext has the name <tt>"mtext"</tt>.  It is a
743     managing key.  A value of a plist whose key is @c Mtext must be an
744     M-text.  */
745
746 /***ja
747     @brief "text" ¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë
748
749     ÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë @c Mtext ¤Ï <tt>"text"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä´ÉÍý
750     ¥­¡¼¤Ç¤¢¤ë¡£ */
751
752 MSymbol Mtext;
753
754
755 /*=*/
756 /***en
757     @brief Create a property list object.
758
759     The mplist () function returns a newly created property list
760     object of length zero.
761
762     @returns
763     This function returns a newly created property list.
764
765     @errors
766     This function never fails.  */
767
768 MPlist *
769 mplist ()
770 {
771   MPlist *plist;
772
773   MPLIST_NEW (plist);
774   return plist;
775 }  
776
777 /*=*/
778 /***en
779     @brief Copy a plist.
780
781     The mplist_copy () function copies $PLIST.  In the copy, the
782     values are the same as those of $PLIST.
783
784     @return
785     This function returns a newly created plist which is a copy of
786     $PLIST.  */
787 /***
788     @errors
789     This function never fails.  */ 
790
791 MPlist *
792 mplist_copy (MPlist *plist)
793 {
794   MPlist *copy = mplist (), *pl = copy;
795
796   MPLIST_DO (plist, plist)
797     pl = mplist_add (pl, MPLIST_KEY (plist), MPLIST_VAL (plist));
798   return copy;
799 }
800
801 /*=*/
802
803 /***en
804     @brief Set the value of a property in a property list object.
805
806     The mplist_put () function searches property list object $PLIST
807     from the beginning for a property whose key is $KEY.  If such a
808     property is found, its value is changed to $VALUE.  Otherwise, a
809     new property whose key is $KEY and value is $VALUE is appended at
810     the end of $PLIST.  See the documentation of mplist_add () for
811     the restriction on $KEY and $VAL.
812
813     If $KEY is a managing key, $VAL must be a managed object.  In this
814     case, the reference count of the old value, if not @c NULL, is
815     decremented by one, and that of $VAL is incremented by one.
816
817     @return
818     If the operation was successful, mplist_put () returns a sublist of
819     $PLIST whose first element is the just modified or added one.
820     Otherwise, it returns @c NULL.  */
821
822 MPlist *
823 mplist_put (MPlist *plist, MSymbol key, void *val)
824 {
825   if (key == Mnil)
826     MERROR (MERROR_PLIST, NULL);
827   MPLIST_FIND (plist, key);
828   if (key->managing_key)
829     {
830       if (! MPLIST_TAIL_P (plist))
831         M17N_OBJECT_UNREF (MPLIST_VAL (plist));
832       M17N_OBJECT_REF (val);
833     }
834   MPLIST_SET (plist, key, val);
835   return plist;
836 }
837
838 /*=*/
839
840 /***en
841     @brief Get the value of a property in a property list object.
842
843     The mplist_get () function searches property list object $PLIST
844     from the beginning for a property whose key is $KEY.  If such a
845     property is found, a pointer to its value is returned as the type
846     of <tt>(void *)</tt>.  If not found, @c NULL is returned.
847
848     When @c NULL is returned, there are two possibilities: one is the
849     case where no property is found (see above); the other is the case
850     where a property is found and its value is @c NULL.  In case that
851     these two cases must be distinguished, use the mplist_find_by_key ()
852     function.  */
853
854 /***
855     @seealso
856     mplist_find_by_key () */
857
858 void *
859 mplist_get (MPlist *plist, MSymbol key)
860 {
861   MPLIST_FIND (plist, key);
862   return (MPLIST_TAIL_P (plist) ? NULL : MPLIST_VAL (plist));
863 }
864
865 /*=*/
866
867 /***en
868     @brief Add a property at the end of a property list object.
869
870     The mplist_add () function appends at the end of $PLIST a property
871     whose key is $KEY and value is $VAL.  $KEY can be any symbol
872     other than @c Mnil.
873
874     If $KEY is a managing key, $VAL must be a managed object.  In this
875     case, the reference count of $VAL is incremented by one.
876
877     @return
878     If the operation was successful, mplist_add () returns a sublist of
879     $PLIST whose first element is the just added one.  Otherwise, it
880     returns @c NULL.  */
881
882 MPlist *
883 mplist_add (MPlist *plist, MSymbol key, void *val)
884 {
885   if (key == Mnil)
886     MERROR (MERROR_PLIST, NULL);
887   MPLIST_FIND (plist, Mnil);
888   if (key->managing_key)
889     M17N_OBJECT_REF (val);
890   MPLIST_KEY (plist) = key;
891   MPLIST_VAL (plist) = val;
892   MPLIST_NEW (plist->next);
893   return plist;
894 }
895
896 /*=*/
897
898 /***en
899     @brief Push a property to a property list object.
900
901     The mplist_push () function pushes at the top of $PLIST a
902     property whose key is $KEY and value si $VAL.
903
904     If $KEY is a managing key, $VAL must be a managed object.  In this
905     case, the reference count of $VAL is incremented by one.
906
907     @return
908     If the operation was successful, this function returns $PLIST.
909     Otherwise, it returns @c NULL.  */
910
911 MPlist *
912 mplist_push (MPlist *plist, MSymbol key, void *val)
913 {
914   MPlist *pl;
915
916   if (key == Mnil)
917     MERROR (MERROR_PLIST, NULL);
918   MPLIST_NEW (pl);
919   MPLIST_KEY (pl) = MPLIST_KEY (plist);
920   MPLIST_VAL (pl) = MPLIST_VAL (plist);
921   pl->next = plist->next;
922   plist->next = pl;
923   if (key->managing_key)
924     M17N_OBJECT_REF (val);
925   MPLIST_KEY (plist) = key;
926   MPLIST_VAL (plist) = val;
927   return plist;
928 }
929
930 /*=*/
931
932 /***en
933     @brief Pop a property from a property list object.
934
935     The mplist_pop () function pops the topmost property from $PLIST.
936     As a result, the key and value of $PLIST becomes those of the next
937     of $PLIST.
938
939     @return
940     If the operation was successful, this function return the value of
941     the just popped property.  Otherwise, it returns @c NULL.  */
942
943 void *
944 mplist_pop (MPlist *plist)
945 {
946   void *val;
947   MPlist *next;
948
949   if (MPLIST_TAIL_P (plist))
950     return NULL;
951   val = MPLIST_VAL (plist);
952   next = plist->next;
953   MPLIST_KEY (plist) = MPLIST_KEY (next);
954   MPLIST_VAL (plist) = MPLIST_VAL (next);
955   if (MPLIST_KEY (plist) != Mnil
956       && MPLIST_KEY (plist)->managing_key
957       && MPLIST_VAL (plist))
958     M17N_OBJECT_REF (MPLIST_VAL (plist));
959   plist->next = next->next;
960   if (plist->next)
961     M17N_OBJECT_REF (plist->next);
962   M17N_OBJECT_UNREF (next);
963   return val;
964 }
965
966 /*=*/
967 /***en
968     @brief Find a property of a specific key in a property list object.
969
970     The mplist_find_by_key () function searches property list object
971     $PLIST from the beginning for a property whose key is $KEY.  If
972     such a property is found, a sublist of $PLIST whose first element
973     is the found one is returned.  Otherwise, @c NULL is returned.
974
975     If $KEY is Mnil, it returns the last a sublist of $PLIST whose
976     first element is the last one of $PLIST.  */
977
978 MPlist *
979 mplist_find_by_key (MPlist *plist, MSymbol key)
980 {
981   MPLIST_FIND (plist, key);
982   return (MPLIST_TAIL_P (plist)
983           ? (key == Mnil ? plist : NULL)
984           : plist);
985 }
986
987 /*=*/
988 /***en
989     @brief Find a property of a specific value in a property list object.
990
991     The mplist_find_by_value () function searches property list object
992     $PLIST from the beginning for a property whose value is $VAL.  If
993     such a property is found, a sublist of $PLIST whose first element
994     is the found one is returned.  Otherwise, @c NULL is returned.  */
995
996 MPlist *
997 mplist_find_by_value (MPlist *plist, void *val)
998 {
999   MPLIST_DO (plist, plist)
1000     {
1001       if (MPLIST_VAL (plist) == val)
1002         return plist;
1003     }
1004   return NULL;
1005 }
1006
1007 /*=*/
1008
1009 /***en
1010     @brief Return the next sublist of a plist.
1011
1012     The mplist_next () function returns a pointer to the sublist of
1013     $PLIST, which begins at the second element in $PLIST.  If the
1014     length of $PLIST is zero, it returns @c NULL.  */
1015
1016 MPlist *
1017 mplist_next (MPlist *plist)
1018 {
1019   return (MPLIST_TAIL_P (plist) ? NULL : plist->next);
1020 }
1021
1022 /*=*/
1023
1024 /***en
1025     @brief Set the first property in a property list object.
1026
1027     The mplist_set () function sets the key and value of the first
1028     property in property list object $PLIST to $KEY and $VALUE,
1029     respectively.  See the documentation of mplist_add () for the
1030     restriction on $KEY and $VAL.
1031
1032     @return
1033     If the operation was successful, mplist_set () returns $PLIST.
1034     Otherwise, it returns @c NULL.  */
1035
1036 MPlist *
1037 mplist_set (MPlist *plist, MSymbol key, void * val)
1038 {
1039   if (key == Mnil)
1040     {
1041       if (! MPLIST_TAIL_P (plist))
1042         {
1043           key = MPLIST_KEY (plist);
1044           M17N_OBJECT_UNREF (MPLIST_NEXT (plist));
1045           MPLIST_KEY (plist) = Mnil;
1046           if (key->managing_key && MPLIST_VAL (plist))
1047             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1048           plist->next = NULL;
1049         }
1050     }
1051   else
1052     {
1053       if (! MPLIST_TAIL_P (plist)
1054           && MPLIST_KEY (plist)->managing_key
1055           && MPLIST_VAL (plist))
1056         M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1057       if (key->managing_key)
1058         M17N_OBJECT_REF (val);
1059       MPLIST_SET (plist, key, val);
1060     }
1061   return plist;
1062 }
1063
1064 /*=*/
1065
1066 /***en
1067     @brief Return the length of a plist.
1068
1069     The mplist_length () function returns the number of properties in
1070     property list object $PLIST.  */
1071
1072 int
1073 mplist_length (MPlist *plist)
1074 {
1075   int n;
1076
1077   for (n = 0; ! (MPLIST_TAIL_P (plist)); n++, plist = plist->next);
1078   return n;
1079 }
1080
1081 /*=*/
1082
1083 /***en
1084     @brief Return the key of the first property in a property list object.
1085
1086     The mplist_key () function returns the key of the first property
1087     in property list object $PLIST.  If the length of $PLIST is zero,
1088     it returns @c Mnil.  */
1089
1090 MSymbol
1091 mplist_key (MPlist *plist)
1092 {
1093   return MPLIST_KEY (plist);
1094 }
1095
1096 /*=*/
1097
1098 /***en
1099     @brief Return the value of the first property in a property list object.
1100
1101     The mplist_value () function returns the value of the first
1102     property in property list object $PLIST.  If the length of $PLIST
1103     is zero, it returns @c NULL.  */
1104
1105 void *
1106 mplist_value (MPlist *plist)
1107 {
1108   return MPLIST_VAL (plist);
1109 }
1110
1111 /***en
1112     @brief Generate a plist by deserializaing an M-text.
1113
1114     The mplist_deserialize () function parses M-text $MT and returns a
1115     property list.
1116
1117     The syntax of $MT is as follows.
1118
1119     MT ::= '(' ELEMENT * ')'
1120
1121     ELEMENT ::= SYMBOL | INTEGER | M-TEXT | PLIST
1122
1123     SYMBOL ::= ascii-character-sequence
1124
1125     INTEGER ::= '-' ? [ '0' | .. | '9' ]+
1126                 | '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
1127
1128     M-TEXT ::= '"' character-sequence '"'
1129
1130     Each kind of @c ELEMENT is assigned one of these keys:
1131         @c Msymbol, @c Minteger, @c Mtext, @c Mplist
1132
1133     In an ascii-character-sequence, a backslush (\) is used as the escape
1134     character, which means that, for instance, <tt>"abc\ def"</tt>
1135     produces a symbol whose name is of length seven with the fourth
1136     character being a space.  */
1137
1138 MPlist *
1139 mplist_deserialize (MText *mt)
1140 {
1141   if (mt->format > MTEXT_FORMAT_UTF_8)
1142     {
1143       if (mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8) < 0)
1144         MERROR (MERROR_PLIST, NULL);
1145     }
1146   return mplist__from_string (MTEXT_DATA (mt), mtext_nbytes (mt));
1147 }
1148
1149 /*** @}  */
1150
1151 /*** @addtogroup m17nDebug */
1152 /*=*/
1153 /*** @{  */
1154
1155 /***en
1156     @brief Dump a plist.
1157
1158     The mdebug_dump_plist () function prints $PLIST in a human
1159     readable way to the stderr.  $INDENT specifies how many columns to
1160     indent the lines but the first one.
1161
1162     @return
1163     This function returns $PLIST.  */
1164
1165 MPlist *
1166 mdebug_dump_plist (MPlist *plist, int indent)
1167 {
1168   char *prefix = (char *) alloca (indent + 1);
1169   MPlist *pl;
1170   int first = 1;
1171
1172   memset (prefix, 32, indent);
1173   prefix[indent] = 0;
1174
1175   fprintf (stderr, "(");
1176   MPLIST_DO (pl, plist)
1177     {
1178       if (first)
1179         first = 0;
1180       else
1181         fprintf (stderr, "\n%s ", prefix);
1182       dump_plist_element (pl, indent + 2);
1183     }
1184   fprintf (stderr, ")");
1185   return plist;
1186 }
1187
1188 /*** @} */
1189
1190 /*
1191   Local Variables:
1192   coding: euc-japan
1193   End:
1194 */