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