Blame src/plist.c

Packit Service a721b1
/* plist.c -- plist module.
Packit Service a721b1
   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Packit Service a721b1
     National Institute of Advanced Industrial Science and Technology (AIST)
Packit Service a721b1
     Registration Number H15PRO112
Packit Service a721b1
Packit Service a721b1
   This file is part of the m17n library.
Packit Service a721b1
Packit Service a721b1
   The m17n library is free software; you can redistribute it and/or
Packit Service a721b1
   modify it under the terms of the GNU Lesser General Public License
Packit Service a721b1
   as published by the Free Software Foundation; either version 2.1 of
Packit Service a721b1
   the License, or (at your option) any later version.
Packit Service a721b1
Packit Service a721b1
   The m17n library is distributed in the hope that it will be useful,
Packit Service a721b1
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a721b1
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service a721b1
   Lesser General Public License for more details.
Packit Service a721b1
Packit Service a721b1
   You should have received a copy of the GNU Lesser General Public
Packit Service a721b1
   License along with the m17n library; if not, write to the Free
Packit Service a721b1
   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit Service a721b1
   Boston, MA 02110-1301 USA.  */
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @addtogroup m17nPlist
Packit Service a721b1
Packit Service a721b1
    @brief Property List objects and API for them.
Packit Service a721b1
Packit Service a721b1
    A @e property @e list (or @e plist for short) is a list of zero or
Packit Service a721b1
    more properties.  A property consists of a @e key and a @e value,
Packit Service a721b1
    where key is a symbol and value is anything that can be cast to
Packit Service a721b1
    <tt>(void *)</tt>.
Packit Service a721b1
Packit Service a721b1
    If the key of a property is a @e managing @e key, its @e value is
Packit Service a721b1
    a @e managed @e object.  A property list itself is a managed
Packit Service a721b1
    objects.
Packit Service a721b1
Packit Service a721b1
    If each key of a plist is one of #Msymbol, #Mtext, #Minteger, and
Packit Service a721b1
    #Mplist, the plist is called as @e well-formed and represented by
Packit Service a721b1
    the following notation in the documentation.
Packit Service a721b1
Packit Service a721b1
@verbatim
Packit Service a721b1
      PLIST ::= '(' ELEMENT * ')'
Packit Service a721b1
Packit Service a721b1
      ELEMENT ::= INTEGER | SYMBOL | M-TEXT | PLIST
Packit Service a721b1
Packit Service a721b1
      M-TEXT ::= '"' text data ... '"'
Packit Service a721b1
@endverbatim
Packit Service a721b1
Packit Service a721b1
    For instance, if a plist has four elements; integer -20, symbol of
Packit Service a721b1
    name "sym", M-text of contents "abc", and plist of integer 10 and
Packit Service a721b1
    symbol of name "another-symbol", it is represented as this:
Packit Service a721b1
Packit Service a721b1
      (-20 sym "abc" (10 another-symbol))
Packit Service a721b1
Packit Service a721b1
  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @addtogroup m17nPlist
Packit Service a721b1
Packit Service a721b1
    @brief プロパティリストオブジェクトとそれに関する API.
Packit Service a721b1
Packit Service a721b1
    @e プロパティリスト (または @e plist) は 0 
Packit Service a721b1
    個以上のプロパティのリストである。プロパティは @e キー と @e 値 
Packit Service a721b1
    からなる。キーはシンボルであり、値は <tt>(void *)</tt> 
Packit Service a721b1
    にキャストできるものならば何でも良い。
Packit Service a721b1
Packit Service a721b1
    あるプロパティのキーが @e 管理キー ならば、その @e 値 は @e 管理下
Packit Service a721b1
    @e オブジェクト 
Packit Service a721b1
    である。プロパティリスト自体も管理下オブジェクトである。  */
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
#if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
Packit Service a721b1
/*** @addtogroup m17nInternal
Packit Service a721b1
     @{ */
Packit Service a721b1
Packit Service a721b1
#include <stdio.h>
Packit Service a721b1
#include <string.h>
Packit Service a721b1
#include <ctype.h>
Packit Service a721b1
Packit Service a721b1
#include "config.h"
Packit Service a721b1
#include "m17n.h"
Packit Service a721b1
#include "m17n-misc.h"
Packit Service a721b1
#include "internal.h"
Packit Service a721b1
#include "character.h"
Packit Service a721b1
#include "mtext.h"
Packit Service a721b1
#include "symbol.h"
Packit Service a721b1
#include "plist.h"
Packit Service a721b1
Packit Service a721b1
static M17NObjectArray plist_table;
Packit Service a721b1
Packit Service a721b1
/** Set PLIST to a newly allocated plist object.  */
Packit Service a721b1
Packit Service a721b1
#define MPLIST_NEW(plist)				\
Packit Service a721b1
  do {							\
Packit Service a721b1
    M17N_OBJECT (plist, free_plist, MERROR_PLIST);	\
Packit Service a721b1
    M17N_OBJECT_REGISTER (plist_table, plist);		\
Packit Service a721b1
  } while (0)
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/** Set the element of PLIST to KEY and VAL.  If PLIST is an anchor,
Packit Service a721b1
    append a new anchor.  */
Packit Service a721b1
Packit Service a721b1
#define MPLIST_SET(plist, key, val)	\
Packit Service a721b1
  do {					\
Packit Service a721b1
    MPLIST_KEY (plist) = (key);		\
Packit Service a721b1
    MPLIST_VAL (plist) = (val);		\
Packit Service a721b1
    if (! (plist)->next)		\
Packit Service a721b1
      MPLIST_NEW ((plist)->next);	\
Packit Service a721b1
  } while (0)
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/** Set the element of PLIST to KEY and VAL.  PLIST must be an anchor.
Packit Service a721b1
    Append a new anchor and set PLIST to that anchor.  */
Packit Service a721b1
Packit Service a721b1
#define MPLIST_SET_ADVANCE(plist, key, val)	\
Packit Service a721b1
  do {						\
Packit Service a721b1
    MPLIST_KEY (plist) = (key);			\
Packit Service a721b1
    MPLIST_VAL (plist) = (val);			\
Packit Service a721b1
    MPLIST_NEW ((plist)->next);			\
Packit Service a721b1
    plist = (plist)->next;			\
Packit Service a721b1
  } while (0)
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
static void
Packit Service a721b1
free_plist (void *object)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *plist = (MPlist *) object;
Packit Service a721b1
Packit Service a721b1
  do {
Packit Service a721b1
    MPlist *next = plist->next;
Packit Service a721b1
Packit Service a721b1
    if (MPLIST_KEY (plist) != Mnil
Packit Service a721b1
	&& MPLIST_KEY (plist)->managing_key)
Packit Service a721b1
      M17N_OBJECT_UNREF (MPLIST_VAL (plist));
Packit Service a721b1
    M17N_OBJECT_UNREGISTER (plist_table, plist);
Packit Service a721b1
    free (plist);
Packit Service a721b1
    plist = next;
Packit Service a721b1
  } while (plist && plist->control.ref_count == 1);
Packit Service a721b1
  M17N_OBJECT_UNREF (plist);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1

Packit Service a721b1
Packit Service a721b1
/* Load a plist from a string.  */
Packit Service a721b1
Packit Service a721b1
#define READ_CHUNK 0x10000
Packit Service a721b1
Packit Service a721b1
typedef struct
Packit Service a721b1
{
Packit Service a721b1
  /* File pointer if the stream is associated with a file.  Otherwise
Packit Service a721b1
     NULL.  */
Packit Service a721b1
  FILE *fp;
Packit Service a721b1
  int eof;
Packit Service a721b1
  unsigned char buffer[READ_CHUNK];
Packit Service a721b1
  unsigned char *p, *pend;
Packit Service a721b1
} MStream;
Packit Service a721b1
Packit Service a721b1
static int
Packit Service a721b1
get_byte (MStream *st)
Packit Service a721b1
{
Packit Service a721b1
  int n;
Packit Service a721b1
Packit Service a721b1
  if (! st->fp || st->eof)
Packit Service a721b1
    return EOF;
Packit Service a721b1
  n = fread (st->buffer, 1, READ_CHUNK, st->fp);
Packit Service a721b1
  if (n <= 0)
Packit Service a721b1
    {
Packit Service a721b1
      st->eof = 1;
Packit Service a721b1
      return EOF;
Packit Service a721b1
    }
Packit Service a721b1
  st->p = st->buffer + 1;
Packit Service a721b1
  st->pend = st->buffer + n;
Packit Service a721b1
  return st->buffer[0];
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
#define GETC(st) ((st)->p < (st)->pend ? *(st)->p++ : get_byte (st))
Packit Service a721b1
Packit Service a721b1
#define UNGETC(c, st) (--((st)->p))
Packit Service a721b1
Packit Service a721b1
/** Mapping table for reading a number.  Hexadecimal chars
Packit Service a721b1
    (0..9,A..F,a..F) are mapped to the corresponding numbers.
Packit Service a721b1
    Apostrophe (code 39) is mapped to 254.  All the other bytes are
Packit Service a721b1
    mapped to 255.  */
Packit Service a721b1
unsigned char hex_mnemonic[256];
Packit Service a721b1
Packit Service a721b1
/** Mapping table for escaped characters.  Mnemonic characters (e, b,
Packit Service a721b1
    f, n, r, or t) that follows '\' are mapped to the corresponding
Packit Service a721b1
    character code.  All the other bytes are mapped to themselves.  */
Packit Service a721b1
unsigned char escape_mnemonic[256];
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/** Read an integer from the stream ST.  It is assumed that we have
Packit Service a721b1
    already read one character C.  */
Packit Service a721b1
Packit Service a721b1
static int
Packit Service a721b1
read_decimal (MStream *st, int c)
Packit Service a721b1
{
Packit Service a721b1
  int num = 0;
Packit Service a721b1
Packit Service a721b1
  while (c >= '0' && c <= '9')
Packit Service a721b1
    {
Packit Service a721b1
      num = (num * 10) + (c - '0');
Packit Service a721b1
      c = GETC (st);
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  if (c != EOF)
Packit Service a721b1
    UNGETC (c, st);
Packit Service a721b1
  return num;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/** Read an unsigned from the stream ST.  */
Packit Service a721b1
Packit Service a721b1
static unsigned
Packit Service a721b1
read_hexadesimal (MStream *st)
Packit Service a721b1
{
Packit Service a721b1
  int c;
Packit Service a721b1
  unsigned num = 0, n;
Packit Service a721b1
Packit Service a721b1
  while ((c = GETC (st)) != EOF
Packit Service a721b1
	 && (n = hex_mnemonic[c]) < 16)
Packit Service a721b1
    num = (num << 4) | n;
Packit Service a721b1
  if (c != EOF)
Packit Service a721b1
    UNGETC (c, st);
Packit Service a721b1
  return num;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/** Read an M-text element from ST, and add it to LIST.  Return a list
Packit Service a721b1
    for the next element.  */
Packit Service a721b1
Packit Service a721b1
#define READ_MTEXT_BUF_SIZE 256
Packit Service a721b1
Packit Service a721b1
static MPlist *
Packit Service a721b1
read_mtext_element (MPlist *plist, MStream *st, int skip)
Packit Service a721b1
{
Packit Service a721b1
  unsigned char buffer[READ_MTEXT_BUF_SIZE], *buf = buffer;
Packit Service a721b1
  int nbytes = READ_MTEXT_BUF_SIZE;
Packit Service a721b1
  int c, i;
Packit Service a721b1
Packit Service a721b1
  i = 0;
Packit Service a721b1
  while ((c = GETC (st)) != EOF && c != '"')
Packit Service a721b1
    {
Packit Service a721b1
      int is_char = 0;
Packit Service a721b1
Packit Service a721b1
      if (c == '\\')
Packit Service a721b1
	{
Packit Service a721b1
	  c = GETC (st);
Packit Service a721b1
	  if (c == EOF)
Packit Service a721b1
	    break;
Packit Service a721b1
	  if (c == '\n')
Packit Service a721b1
	    continue;
Packit Service a721b1
	  if (c == 'x' || c == 'u')
Packit Service a721b1
	    {
Packit Service a721b1
	      int next_c;
Packit Service a721b1
Packit Service a721b1
	      c = read_hexadesimal (st);
Packit Service a721b1
	      next_c = GETC (st);
Packit Service a721b1
	      if (next_c != ' ')
Packit Service a721b1
		UNGETC (next_c, st);
Packit Service a721b1
	      if (c >= 0x80)
Packit Service a721b1
		is_char = 1;
Packit Service a721b1
	    }
Packit Service a721b1
	  else
Packit Service a721b1
	    c = escape_mnemonic[c];
Packit Service a721b1
	}
Packit Service a721b1
Packit Service a721b1
      if (! skip)
Packit Service a721b1
	{
Packit Service a721b1
	  if (i + MAX_UTF8_CHAR_BYTES + 1 >= nbytes)
Packit Service a721b1
	    {
Packit Service a721b1
	      if (buf == buffer)
Packit Service a721b1
		{
Packit Service a721b1
		  nbytes *= 2;
Packit Service a721b1
		  buf = malloc (nbytes);
Packit Service a721b1
		  memcpy (buf, buffer, i);
Packit Service a721b1
		}
Packit Service a721b1
	      else
Packit Service a721b1
		{
Packit Service a721b1
		  nbytes += READ_MTEXT_BUF_SIZE;
Packit Service a721b1
		  buf = realloc (buf, nbytes);
Packit Service a721b1
		}
Packit Service a721b1
	    }
Packit Service a721b1
Packit Service a721b1
	  if (is_char)
Packit Service a721b1
	    i += CHAR_STRING_UTF8 (c, buf);
Packit Service a721b1
	  else
Packit Service a721b1
	    buf[i++] = c;
Packit Service a721b1
	}
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  if (! skip)
Packit Service a721b1
    {
Packit Service a721b1
      MText *mt;
Packit Service a721b1
Packit Service a721b1
      buf[i] = 0;
Packit Service a721b1
      mt = mtext__from_data (buf, i, MTEXT_FORMAT_UTF_8, (buf == buffer));
Packit Service a721b1
      if (buf != buffer)
Packit Service a721b1
	mt->allocated = nbytes;
Packit Service a721b1
      MPLIST_SET_ADVANCE (plist, Mtext, mt);
Packit Service a721b1
    }
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
static int
Packit Service a721b1
read_character (MStream *st, int c)
Packit Service a721b1
{
Packit Service a721b1
  unsigned char buf[MAX_UTF8_CHAR_BYTES + 1];
Packit Service a721b1
  int len = CHAR_BYTES_BY_HEAD (c);
Packit Service a721b1
  int i;
Packit Service a721b1
Packit Service a721b1
  buf[0] = c;
Packit Service a721b1
  for (i = 1; i < len; i++)
Packit Service a721b1
    {
Packit Service a721b1
      c = GETC (st);
Packit Service a721b1
      if (c == EOF
Packit Service a721b1
	  || (c & 0xC0) != 0x80)
Packit Service a721b1
	break;
Packit Service a721b1
      buf[i] = c;
Packit Service a721b1
    }
Packit Service a721b1
  if (i == len)
Packit Service a721b1
    c = STRING_CHAR_UTF8 (buf);
Packit Service a721b1
  else
Packit Service a721b1
    c = buf[0];
Packit Service a721b1
  return c;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/** Read a symbol element from ST, and add it to LIST.  Return a list
Packit Service a721b1
    for the next element.  */
Packit Service a721b1
Packit Service a721b1
static MPlist *
Packit Service a721b1
read_symbol_element (MPlist *plist, MStream *st, int c, int skip)
Packit Service a721b1
{
Packit Service a721b1
  unsigned char buffer[1024];
Packit Service a721b1
  int bufsize = 1024;
Packit Service a721b1
  unsigned char *buf = buffer;
Packit Service a721b1
  int i;
Packit Service a721b1
Packit Service a721b1
  i = 0;
Packit Service a721b1
  while (c != EOF
Packit Service a721b1
	 && c > ' '
Packit Service a721b1
	 && c != ')' && c != '(' && c != '"')
Packit Service a721b1
    {
Packit Service a721b1
      if (i >= bufsize)
Packit Service a721b1
	{
Packit Service a721b1
	  bufsize *= 2;
Packit Service a721b1
	  if (buf == buffer)
Packit Service a721b1
	    {
Packit Service a721b1
	      MTABLE_MALLOC (buf, bufsize, MERROR_PLIST);
Packit Service a721b1
	      memcpy (buf, buffer, i);
Packit Service a721b1
	    }
Packit Service a721b1
	  else
Packit Service a721b1
	    MTABLE_REALLOC (buf, bufsize, MERROR_PLIST);
Packit Service a721b1
	}
Packit Service a721b1
      if (c == '\\')
Packit Service a721b1
	{
Packit Service a721b1
	  c = GETC (st);
Packit Service a721b1
	  if (c == EOF)
Packit Service a721b1
	    break;
Packit Service a721b1
	  c = escape_mnemonic[c];
Packit Service a721b1
	}
Packit Service a721b1
      if (! skip)
Packit Service a721b1
	buf[i++] = c;
Packit Service a721b1
      c = GETC (st);
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  if (c > ' ')
Packit Service a721b1
    UNGETC (c, st);
Packit Service a721b1
  if (! skip)
Packit Service a721b1
    {
Packit Service a721b1
      buf[i] = 0;
Packit Service a721b1
      MPLIST_SET_ADVANCE (plist, Msymbol, msymbol ((char *) buf));
Packit Service a721b1
      if (buf != buffer)
Packit Service a721b1
	free (buf);
Packit Service a721b1
    }
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/** Read an integer element from ST, and add it to LIST.  Return a
Packit Service a721b1
    list for the next element.  It is assumed that we have already
Packit Service a721b1
    read the character C. */
Packit Service a721b1
Packit Service a721b1
static MPlist *
Packit Service a721b1
read_integer_element (MPlist *plist, MStream *st, int c, int skip)
Packit Service a721b1
{
Packit Service a721b1
  int num;
Packit Service a721b1
Packit Service a721b1
  if (c == '#')
Packit Service a721b1
    {
Packit Service a721b1
      c = GETC (st);
Packit Service a721b1
      if (c != 'x')
Packit Service a721b1
	{
Packit Service a721b1
	  UNGETC (c, st);
Packit Service a721b1
	  return read_symbol_element (plist, st, '#', skip);
Packit Service a721b1
	}
Packit Service a721b1
      num = read_hexadesimal (st);
Packit Service a721b1
    }
Packit Service a721b1
  else if (c == '0')
Packit Service a721b1
    {
Packit Service a721b1
      c = GETC (st);
Packit Service a721b1
      num = (c == 'x' ? read_hexadesimal (st) : read_decimal (st, c));
Packit Service a721b1
    }
Packit Service a721b1
  else if (c == '?')
Packit Service a721b1
    {
Packit Service a721b1
      c = GETC (st);
Packit Service a721b1
      if (c == EOF)
Packit Service a721b1
	num = 0;
Packit Service a721b1
      else if (c != '\\')
Packit Service a721b1
	{
Packit Service a721b1
	  if (c < 128 || ! CHAR_UNITS_BY_HEAD_UTF8 (c))
Packit Service a721b1
	    num = c;
Packit Service a721b1
	  else
Packit Service a721b1
	    num = read_character (st, c);
Packit Service a721b1
	}
Packit Service a721b1
      else
Packit Service a721b1
	{
Packit Service a721b1
	  c = GETC (st);
Packit Service a721b1
	  if (c == EOF)
Packit Service a721b1
	    num = '\\';
Packit Service a721b1
	  else if (c < 128 || ! CHAR_UNITS_BY_HEAD_UTF8 (c))
Packit Service a721b1
	    num = escape_mnemonic[c];
Packit Service a721b1
	  else
Packit Service a721b1
	    num = read_character (st, c);
Packit Service a721b1
	}
Packit Service a721b1
    }
Packit Service a721b1
  else if (c == '-')
Packit Service a721b1
    {
Packit Service a721b1
      c = GETC (st);
Packit Service a721b1
      if (c < '0' || c > '9')
Packit Service a721b1
	{
Packit Service a721b1
	  UNGETC (c, st);
Packit Service a721b1
	  return read_symbol_element (plist, st, '-', skip);
Packit Service a721b1
	}
Packit Service a721b1
      num = - read_decimal (st, c);
Packit Service a721b1
    }
Packit Service a721b1
  else
Packit Service a721b1
    num = read_decimal (st, c);
Packit Service a721b1
Packit Service a721b1
  if (! skip)
Packit Service a721b1
    MPLIST_SET_ADVANCE (plist, Minteger, (void *) num);
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/* Read an element of various type from stream ST, and add it to LIST.
Packit Service a721b1
   Return a list for the next element.  The element type is decided by
Packit Service a721b1
   the first token character found as below:
Packit Service a721b1
	'(': plist
Packit Service a721b1
	'"': mtext
Packit Service a721b1
	'0'..'9', '-': integer
Packit Service a721b1
	'?': integer representing character code
Packit Service a721b1
	the other ASCII letters: symbol
Packit Service a721b1
Packit Service a721b1
   If KEYS is not NULL, it is a plist contains target keys and stop
Packit Service a721b1
   keys.  In this caes, read only a plist whose key has value 1 in
Packit Service a721b1
   KEYS, and return NULL when we encounter a plist whose key has value
Packit Service a721b1
   0 in KEYS while skipping any other elements.  */
Packit Service a721b1
Packit Service a721b1
static MPlist *
Packit Service a721b1
read_element (MPlist *plist, MStream *st, MPlist *keys)
Packit Service a721b1
{
Packit Service a721b1
  int c;
Packit Service a721b1
Packit Service a721b1
  /* Skip separators and comments.  */
Packit Service a721b1
  while (1)
Packit Service a721b1
    {
Packit Service a721b1
      while ((c = GETC (st)) != EOF && c <= ' ');
Packit Service a721b1
      if (c != ';')
Packit Service a721b1
	break;
Packit Service a721b1
      while ((c = GETC (st)) != EOF && c != '\n');
Packit Service a721b1
      if (c == EOF)
Packit Service a721b1
	break;
Packit Service a721b1
    }
Packit Service a721b1
Packit Service a721b1
  if (c == '(')
Packit Service a721b1
    {
Packit Service a721b1
      MPlist *pl, *p;
Packit Service a721b1
Packit Service a721b1
      MPLIST_NEW (pl);
Packit Service a721b1
      p = pl;
Packit Service a721b1
      p = read_element (p, st, NULL);
Packit Service a721b1
      if (keys && p && MPLIST_SYMBOL_P (pl))
Packit Service a721b1
	{
Packit Service a721b1
	  if (MPLIST_TAIL_P (keys))
Packit Service a721b1
	    {
Packit Service a721b1
	      while ((p = read_element (p, st, NULL)));
Packit Service a721b1
	      MPLIST_SET_ADVANCE (plist, Mplist, pl);
Packit Service a721b1
	      return NULL;
Packit Service a721b1
	    }
Packit Service a721b1
	  else
Packit Service a721b1
	    {
Packit Service a721b1
	      MPlist *p0 = keys;
Packit Service a721b1
Packit Service a721b1
	      MPLIST_FIND (p0, MPLIST_SYMBOL (pl));
Packit Service a721b1
	      if (! MPLIST_TAIL_P (p0) && ! MPLIST_VAL (p0))
Packit Service a721b1
		{
Packit Service a721b1
		  M17N_OBJECT_UNREF (pl);
Packit Service a721b1
		  return NULL;
Packit Service a721b1
		}
Packit Service a721b1
	      while ((p = read_element (p, st, NULL)));
Packit Service a721b1
	      if (! MPLIST_TAIL_P (p0))
Packit Service a721b1
		{
Packit Service a721b1
		  MPLIST_SET_ADVANCE (plist, Mplist, pl);
Packit Service a721b1
		  return NULL;
Packit Service a721b1
		}
Packit Service a721b1
	      else
Packit Service a721b1
		M17N_OBJECT_UNREF (pl);
Packit Service a721b1
	    }
Packit Service a721b1
	}
Packit Service a721b1
      else
Packit Service a721b1
	{
Packit Service a721b1
	  if (p)
Packit Service a721b1
	    while ((p = read_element (p, st, NULL)));
Packit Service a721b1
	  MPLIST_SET_ADVANCE (plist, Mplist, pl);
Packit Service a721b1
	}
Packit Service a721b1
      return plist;
Packit Service a721b1
    }
Packit Service a721b1
  if (c == '"')
Packit Service a721b1
    return (read_mtext_element (plist, st, keys ? 1 : 0));
Packit Service a721b1
  if ((c >= '0' && c <= '9') || c == '-' || c == '?' || c == '#')
Packit Service a721b1
    return (read_integer_element (plist, st, c, keys ? 1 : 0));
Packit Service a721b1
  if (c == EOF || c == ')')
Packit Service a721b1
    return NULL;
Packit Service a721b1
  return (read_symbol_element (plist, st, c, keys ? 1 : 0));
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
#define PUTC(MT, C)			\
Packit Service a721b1
  do {					\
Packit Service a721b1
    if (MT)				\
Packit Service a721b1
      mtext_cat_char ((MT), (C));	\
Packit Service a721b1
    else				\
Packit Service a721b1
      putc ((C), mdebug__output);	\
Packit Service a721b1
  } while (0);
Packit Service a721b1
Packit Service a721b1
#define PUTS(MT, STR)			\
Packit Service a721b1
  do {					\
Packit Service a721b1
    if (MT)				\
Packit Service a721b1
      MTEXT_CAT_ASCII ((MT), (STR));	\
Packit Service a721b1
    else				\
Packit Service a721b1
      fputs ((STR), mdebug__output);	\
Packit Service a721b1
  } while (0)
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
static void 
Packit Service a721b1
write_symbol (MText *mt, MSymbol sym)
Packit Service a721b1
{
Packit Service a721b1
  if (sym == Mnil)
Packit Service a721b1
    {
Packit Service a721b1
      PUTS (mt, "nil");
Packit Service a721b1
    }
Packit Service a721b1
  else
Packit Service a721b1
    {
Packit Service a721b1
      char *name = MSYMBOL_NAME (sym);
Packit Service a721b1
Packit Service a721b1
      if (isdigit (*name))
Packit Service a721b1
	PUTC (mt, '\\');
Packit Service a721b1
      while (*name)
Packit Service a721b1
	{
Packit Service a721b1
	  if (*name <= ' ' || *name == '\\' || *name == '"'
Packit Service a721b1
	      || *name == '(' || *name == ')')
Packit Service a721b1
	    PUTC (mt, '\\');
Packit Service a721b1
	  PUTC (mt, *name); 
Packit Service a721b1
	  name++;
Packit Service a721b1
	}
Packit Service a721b1
    }
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
static void
Packit Service a721b1
write_element (MText *mt, MPlist *plist, int indent)
Packit Service a721b1
{
Packit Service a721b1
  if (MPLIST_SYMBOL_P (plist))
Packit Service a721b1
    {
Packit Service a721b1
      write_symbol (mt, MPLIST_SYMBOL (plist));
Packit Service a721b1
    }
Packit Service a721b1
  else if (MPLIST_INTEGER_P (plist))
Packit Service a721b1
    {
Packit Service a721b1
      int num = MPLIST_INTEGER (plist);
Packit Service a721b1
      char buf[128];
Packit Service a721b1
Packit Service a721b1
      sprintf (buf, "%d", num);
Packit Service a721b1
      PUTS (mt, buf);
Packit Service a721b1
    }
Packit Service a721b1
  else if (MPLIST_PLIST_P (plist)
Packit Service a721b1
	   || MPLIST_NESTED_P (plist))
Packit Service a721b1
    {
Packit Service a721b1
      MPlist *pl;
Packit Service a721b1
      int newline = 0;
Packit Service a721b1
Packit Service a721b1
      if (MPLIST_NESTED_P (plist))
Packit Service a721b1
	{
Packit Service a721b1
	  write_symbol (mt, MPLIST_KEY (plist));
Packit Service a721b1
	  PUTC (mt, ':');
Packit Service a721b1
	}
Packit Service a721b1
      plist = MPLIST_PLIST (plist);
Packit Service a721b1
      PUTC (mt, '(');
Packit Service a721b1
      if (indent >= 0)
Packit Service a721b1
	indent++;
Packit Service a721b1
      MPLIST_DO (pl, plist)
Packit Service a721b1
	{
Packit Service a721b1
	  if (pl != plist)
Packit Service a721b1
	    {
Packit Service a721b1
	      if (indent > 0 && (MPLIST_PLIST_P (pl) || MPLIST_MTEXT_P (pl)))
Packit Service a721b1
		newline = 1;
Packit Service a721b1
	      if (newline)
Packit Service a721b1
		{
Packit Service a721b1
		  int i;
Packit Service a721b1
Packit Service a721b1
		  PUTC (mt, '\n');
Packit Service a721b1
		  for (i = 1; i < indent; i++)
Packit Service a721b1
		    PUTC (mt, ' ');
Packit Service a721b1
		}
Packit Service a721b1
	      PUTC (mt, ' ');
Packit Service a721b1
	    }
Packit Service a721b1
	  write_element (mt, pl, indent);
Packit Service a721b1
	  if (indent >= 0)
Packit Service a721b1
	    newline = (MPLIST_PLIST_P (pl) || MPLIST_MTEXT_P (pl));
Packit Service a721b1
	}
Packit Service a721b1
      PUTC (mt, ')');
Packit Service a721b1
    }
Packit Service a721b1
  else if (MPLIST_MTEXT_P (plist))
Packit Service a721b1
    {
Packit Service a721b1
      MText *this_mt = MPLIST_MTEXT (plist);
Packit Service a721b1
      int from = 0, to = mtext_nchars (this_mt);
Packit Service a721b1
      int stop1 = 0, stop2 = 0;
Packit Service a721b1
Packit Service a721b1
      if (! mt && this_mt->format > MTEXT_FORMAT_UTF_8)
Packit Service a721b1
	{
Packit Service a721b1
	  this_mt = mtext_dup (this_mt);
Packit Service a721b1
	  mtext__adjust_format (this_mt, MTEXT_FORMAT_UTF_8);
Packit Service a721b1
	}
Packit Service a721b1
Packit Service a721b1
      PUTC (mt, '"');
Packit Service a721b1
      while (1)
Packit Service a721b1
	{
Packit Service a721b1
	  int stop, escaped;
Packit Service a721b1
Packit Service a721b1
	  if (from == stop1)
Packit Service a721b1
	    {
Packit Service a721b1
	      if ((stop1 = mtext_character (this_mt, from, to, '"')) < 0)
Packit Service a721b1
		stop1 = to;
Packit Service a721b1
	    }
Packit Service a721b1
	  if (from == stop2)
Packit Service a721b1
	    {
Packit Service a721b1
	      if ((stop2 = mtext_character (this_mt, from, to, '\\')) < 0)
Packit Service a721b1
		stop2 = to;
Packit Service a721b1
	    }
Packit Service a721b1
	  if (stop1 < stop2)
Packit Service a721b1
	    stop = stop1++, escaped = '"';
Packit Service a721b1
	  else
Packit Service a721b1
	    stop = stop2++, escaped = '\\';
Packit Service a721b1
	  if (mt)
Packit Service a721b1
	    mtext_copy (mt, mtext_nchars (mt), this_mt, from, stop);
Packit Service a721b1
	  else
Packit Service a721b1
	    {
Packit Service a721b1
	      unsigned char *data = MTEXT_DATA (this_mt);
Packit Service a721b1
	      unsigned char *beg = data + mtext__char_to_byte (this_mt, from);
Packit Service a721b1
	      unsigned char *end = data + mtext__char_to_byte (this_mt, stop);
Packit Service a721b1
Packit Service a721b1
	      while (beg < end)
Packit Service a721b1
		putc (*beg, mdebug__output), beg++;
Packit Service a721b1
	    }
Packit Service a721b1
	  if (stop == to)
Packit Service a721b1
	    break;
Packit Service a721b1
	  PUTC (mt, '\\');
Packit Service a721b1
	  PUTC (mt, escaped);
Packit Service a721b1
	  from = stop + 1;
Packit Service a721b1
	}
Packit Service a721b1
      PUTC (mt, '"');
Packit Service a721b1
      if (this_mt != MPLIST_MTEXT (plist))
Packit Service a721b1
	M17N_OBJECT_UNREF (this_mt);
Packit Service a721b1
    }
Packit Service a721b1
  else if (MPLIST_STRING_P (plist))
Packit Service a721b1
    {
Packit Service a721b1
      char *str = MPLIST_STRING (plist);
Packit Service a721b1
Packit Service a721b1
      if (mt)
Packit Service a721b1
	{
Packit Service a721b1
	  MText *this_mt = mtext__from_data (str, strlen (str),
Packit Service a721b1
					     MTEXT_FORMAT_UTF_8, 0);
Packit Service a721b1
Packit Service a721b1
	  mtext_copy (mt, mtext_nchars (mt),
Packit Service a721b1
		      this_mt, 0, mtext_nchars (this_mt));
Packit Service a721b1
	  M17N_OBJECT_UNREF (this_mt);
Packit Service a721b1
	}
Packit Service a721b1
      else
Packit Service a721b1
	fprintf (mdebug__output, "%s", str);
Packit Service a721b1
    }
Packit Service a721b1
  else 
Packit Service a721b1
    {
Packit Service a721b1
      char buf[128];
Packit Service a721b1
Packit Service a721b1
      write_symbol (mt, MPLIST_KEY (plist));
Packit Service a721b1
      PUTC (mt, ':');
Packit Service a721b1
      sprintf (buf, "%04X", (unsigned) MPLIST_VAL (plist));
Packit Service a721b1
      PUTS (mt, buf);
Packit Service a721b1
    }
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1

Packit Service a721b1
/* Internal API */
Packit Service a721b1
int
Packit Service a721b1
mplist__init ()
Packit Service a721b1
{
Packit Service a721b1
  int i;
Packit Service a721b1
Packit Service a721b1
  M17N_OBJECT_ADD_ARRAY (plist_table, "Plist");
Packit Service a721b1
Packit Service a721b1
  Minteger = msymbol ("integer");
Packit Service a721b1
  Mplist = msymbol_as_managing_key ("plist");
Packit Service a721b1
  Mtext = msymbol_as_managing_key ("mtext");
Packit Service a721b1
Packit Service a721b1
  for (i = 0; i < 256; i++)
Packit Service a721b1
    hex_mnemonic[i] = 255;
Packit Service a721b1
  for (i = '0'; i <= '9'; i++)
Packit Service a721b1
    hex_mnemonic[i] = i - '0';
Packit Service a721b1
  for (i = 'A'; i <= 'F'; i++)
Packit Service a721b1
    hex_mnemonic[i] = i - 'A' + 10;
Packit Service a721b1
  for (i = 'a'; i <= 'f'; i++)
Packit Service a721b1
    hex_mnemonic[i] = i - 'a' + 10;
Packit Service a721b1
  for (i = 0; i < 256; i++)
Packit Service a721b1
    escape_mnemonic[i] = i;
Packit Service a721b1
  escape_mnemonic['e'] = 27;
Packit Service a721b1
  escape_mnemonic['b'] = '\b';
Packit Service a721b1
  escape_mnemonic['f'] = '\f';
Packit Service a721b1
  escape_mnemonic['n'] = '\n';
Packit Service a721b1
  escape_mnemonic['r'] = '\r';
Packit Service a721b1
  escape_mnemonic['t'] = '\t';
Packit Service a721b1
  escape_mnemonic['\\'] = '\\';
Packit Service a721b1
Packit Service a721b1
  return 0;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
void
Packit Service a721b1
mplist__fini (void)
Packit Service a721b1
{
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/* Parse this form of PLIST:
Packit Service a721b1
      (symbol:KEY1 TYPE1:VAL1 symbol:KEY2 TYPE2:VAL2 ...)
Packit Service a721b1
   and return a newly created plist of this form:
Packit Service a721b1
      (KEY1:VAL1 KEY2:VAL2 ...)  */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist__from_plist (MPlist *plist)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *pl, *p;
Packit Service a721b1
Packit Service a721b1
  MPLIST_NEW (pl);
Packit Service a721b1
  p = pl;
Packit Service a721b1
  while (! MPLIST_TAIL_P (plist))
Packit Service a721b1
    {
Packit Service a721b1
      MSymbol key, type;
Packit Service a721b1
Packit Service a721b1
      if (! MPLIST_SYMBOL_P (plist))
Packit Service a721b1
	MERROR (MERROR_PLIST, NULL);
Packit Service a721b1
      key = MPLIST_SYMBOL (plist);
Packit Service a721b1
      plist = MPLIST_NEXT (plist);
Packit Service a721b1
      type = MPLIST_KEY (plist);
Packit Service a721b1
      if (type->managing_key && MPLIST_VAL (plist))
Packit Service a721b1
	M17N_OBJECT_REF (MPLIST_VAL (plist));
Packit Service a721b1
      if (type == Mplist)
Packit Service a721b1
	MPLIST_SET_NESTED_P (p);
Packit Service a721b1
      MPLIST_SET_ADVANCE (p, key, MPLIST_VAL (plist));
Packit Service a721b1
      plist = MPLIST_NEXT (plist);
Packit Service a721b1
    }
Packit Service a721b1
  return pl;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/** Parse this form of PLIST:
Packit Service a721b1
      ((symbol:KEY1 ANY:VAL1 ... ) (symbol:KEY2 ANY:VAL2 ...) ...)
Packit Service a721b1
    and return a newly created plist of this form:
Packit Service a721b1
      (KEY1:(ANY:VAL1 ...) KEY2:(ANY:VAL2 ...) ...)
Packit Service a721b1
    ANY can be any type.  */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist__from_alist (MPlist *plist)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *pl, *p;
Packit Service a721b1
Packit Service a721b1
  MPLIST_NEW (pl);
Packit Service a721b1
  p = pl;
Packit Service a721b1
  MPLIST_DO (plist, plist)
Packit Service a721b1
    {
Packit Service a721b1
      MPlist *elt;
Packit Service a721b1
Packit Service a721b1
      if (! MPLIST_PLIST_P (plist))
Packit Service a721b1
	MERROR (MERROR_PLIST, NULL);
Packit Service a721b1
      elt = MPLIST_PLIST (plist);
Packit Service a721b1
      if (! MPLIST_SYMBOL_P (elt))
Packit Service a721b1
	MERROR (MERROR_PLIST, NULL);
Packit Service a721b1
      MPLIST_SET_NESTED_P (p);
Packit Service a721b1
      MPLIST_SET_ADVANCE (p, MPLIST_SYMBOL (elt), MPLIST_NEXT (elt));
Packit Service a721b1
      M17N_OBJECT_REF (MPLIST_NEXT (elt));
Packit Service a721b1
    }
Packit Service a721b1
  return pl;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist__from_file (FILE *fp, MPlist *keys)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *plist, *pl;
Packit Service a721b1
  MStream st;
Packit Service a721b1
Packit Service a721b1
  st.fp = fp;
Packit Service a721b1
  st.eof = 0;
Packit Service a721b1
  st.p = st.pend = st.buffer;
Packit Service a721b1
  MPLIST_NEW (plist);
Packit Service a721b1
  pl = plist;
Packit Service a721b1
  while ((pl = read_element (pl, &st, keys)));
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/** Parse $STR of $N bytes and return a property list object.  $FORMAT
Packit Service a721b1
    must be either @c MTEXT_FORMAT_US_ASCII or @c MTEXT_FORMAT_UTF_8,
Packit Service a721b1
    and controls how to produce @c STRING or @c M-TEXT in the
Packit Service a721b1
    following definition.
Packit Service a721b1
Packit Service a721b1
    The syntax of $STR is as follows.
Packit Service a721b1
Packit Service a721b1
    PLIST ::= '(' ELEMENT * ')'
Packit Service a721b1
Packit Service a721b1
    ELEMENT ::= SYMBOL | INTEGER | UNSIGNED | STRING | M-TEXT | PLIST
Packit Service a721b1
Packit Service a721b1
    SYMBOL ::= ascii-character-sequence
Packit Service a721b1
Packit Service a721b1
    INTEGER ::= '-' ? [ '0' | .. | '9' ]+
Packit Service a721b1
Packit Service a721b1
    UNSIGNED ::= '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
Packit Service a721b1
Packit Service a721b1
    M-TEXT ::= '"' byte-sequence '"'
Packit Service a721b1
Packit Service a721b1
    Each kind of @c ELEMENT is assigned one of these keys:
Packit Service a721b1
	@c Msymbol, @c Mint, @c Munsigned, @c Mtext, @c Mplist
Packit Service a721b1
Packit Service a721b1
    In an ascii-character-sequence, a backslush (\) is used as the escape
Packit Service a721b1
    character, which means that, for instance, <tt>"abc\ def"</tt>
Packit Service a721b1
    produces a symbol whose name is of length seven with the fourth
Packit Service a721b1
    character being a space.
Packit Service a721b1
Packit Service a721b1
    In a byte-sequence, "\r", "\n", "\e", and "\t" are replaced by CR,
Packit Service a721b1
    NL, ESC, and TAB character respectively, "\xXX" are replaced by
Packit Service a721b1
    byte 0xXX.  After this replacement, the byte-sequence is decoded
Packit Service a721b1
    into M-TEXT by $CODING.  */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist__from_string (unsigned char *str, int n)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *plist, *pl;
Packit Service a721b1
  MStream st;
Packit Service a721b1
Packit Service a721b1
  st.fp = NULL;
Packit Service a721b1
  st.eof = 0;
Packit Service a721b1
  st.p = str;
Packit Service a721b1
  st.pend = str + n;
Packit Service a721b1
  MPLIST_NEW (plist);
Packit Service a721b1
  pl = plist;
Packit Service a721b1
  while ((pl = read_element (pl, &st, NULL)));
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
int
Packit Service a721b1
mplist__serialize (MText *mt, MPlist *plist, int pretty)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *pl;
Packit Service a721b1
  int separator = pretty ? '\n' : ' ';
Packit Service a721b1
Packit Service a721b1
  MPLIST_DO (pl, plist)
Packit Service a721b1
    {
Packit Service a721b1
      if (pl != plist)
Packit Service a721b1
	mtext_cat_char (mt, separator);
Packit Service a721b1
      write_element (mt, pl, pretty ? 0 : -1);
Packit Service a721b1
    }
Packit Service a721b1
  if (pretty)
Packit Service a721b1
    mtext_cat_char (mt, separator);
Packit Service a721b1
  return 0;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/**en
Packit Service a721b1
    @brief Concatenate two plists.
Packit Service a721b1
Packit Service a721b1
    The mplist__conc () function concatenates plist $TAIL at the end of
Packit Service a721b1
    plist $PLIST and return $PLIST.  If $TAIL is empty, return $PLIST
Packit Service a721b1
    without modifying it.  */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist__conc (MPlist *plist, MPlist *tail)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *pl;
Packit Service a721b1
Packit Service a721b1
  if (MPLIST_TAIL_P (tail))
Packit Service a721b1
    return plist;
Packit Service a721b1
  MPLIST_DO (pl, plist);
Packit Service a721b1
  MPLIST_KEY (pl) = MPLIST_KEY (tail);
Packit Service a721b1
  MPLIST_VAL (pl) = MPLIST_VAL (tail);
Packit Service a721b1
  if (MPLIST_KEY (pl)->managing_key && MPLIST_VAL (pl))
Packit Service a721b1
    M17N_OBJECT_REF (MPLIST_VAL (pl));
Packit Service a721b1
  if (MPLIST_NESTED_P (tail))
Packit Service a721b1
    MPLIST_SET_NESTED_P (pl);
Packit Service a721b1
  tail = MPLIST_NEXT (tail);
Packit Service a721b1
  MPLIST_NEXT (pl) = tail;
Packit Service a721b1
  M17N_OBJECT_REF (tail);
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
/**en
Packit Service a721b1
    @brief Discard a property at the beginning of a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist__pop_unref () function removes a property at the
Packit Service a721b1
    beginning of property list $PLIST, and if the property value is a
Packit Service a721b1
    managed object, unref it.  As a result, the second key and value
Packit Service a721b1
    of the original $PLIST become the first of those of the new
Packit Service a721b1
    $PLIST.  */
Packit Service a721b1
Packit Service a721b1
void
Packit Service a721b1
mplist__pop_unref (MPlist *plist)
Packit Service a721b1
{
Packit Service a721b1
  MSymbol key;
Packit Service a721b1
  void *val;
Packit Service a721b1
Packit Service a721b1
  if (MPLIST_TAIL_P (plist))
Packit Service a721b1
    return;
Packit Service a721b1
  key = MPLIST_KEY (plist);
Packit Service a721b1
  val = mplist_pop (plist);
Packit Service a721b1
  if (key->managing_key)
Packit Service a721b1
    M17N_OBJECT_UNREF (val);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/**en
Packit Service a721b1
    @brief Search for an element of an alist represented by a plist.
Packit Service a721b1
Packit Service a721b1
    The mplist__assq () function treats $PLIST as an association list
Packit Service a721b1
    (elements are plists (key is #Mplist) whose first element is a
Packit Service a721b1
    symbol (key is #Msymbol)), and find an element whose first element
Packit Service a721b1
    has key #Msymbol and value $KEY.
Packit Service a721b1
Packit Service a721b1
    Non-plist elements of $PLIST are ignored.
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    This function returns a found element or NULL if no element
Packit Service a721b1
    matches with $KEY.  */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist__assq (MPlist *plist, MSymbol key)
Packit Service a721b1
{
Packit Service a721b1
  MPLIST_DO (plist, plist)
Packit Service a721b1
    if (MPLIST_PLIST_P (plist))
Packit Service a721b1
      {
Packit Service a721b1
	MPlist *pl = MPLIST_PLIST (plist);
Packit Service a721b1
Packit Service a721b1
	if (MPLIST_SYMBOL_P (pl) && MPLIST_SYMBOL (pl) == key)
Packit Service a721b1
	  return plist;
Packit Service a721b1
      }
Packit Service a721b1
  return NULL;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*** @} */
Packit Service a721b1
#endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
Packit Service a721b1
Packit Service a721b1

Packit Service a721b1
/* External API */
Packit Service a721b1
Packit Service a721b1
/*** @addtogroup m17nPlist */
Packit Service a721b1
/*** @{ */
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Symbol whose name is "integer".
Packit Service a721b1
Packit Service a721b1
    The symbol @c Minteger has the name <tt>"integer"</tt>.  The value
Packit Service a721b1
    of a property whose key is @c Minteger must be an integer.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief "integer" を名前として持つシンボル.
Packit Service a721b1
Packit Service a721b1
    シンボル @c Minteger は <tt>"integer"</tt> という名前を持つ。キーが
Packit Service a721b1
    @c Minteger であるプロパティの値は整数値でなくてはならない。  */
Packit Service a721b1
Packit Service a721b1
MSymbol Minteger;
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Symbol whose name is "plist".
Packit Service a721b1
Packit Service a721b1
    The symbol @c Mplist has the name <tt>"plist"</tt>.  It is a
Packit Service a721b1
    managing key.  A value of a property whose key is @c Mplist must
Packit Service a721b1
    be a plist.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief "plist" を名前として持つシンボル.
Packit Service a721b1
Packit Service a721b1
    シンボル @c Mplist は <tt>"plist"</tt> 
Packit Service a721b1
    という名前を持つ。これは管理キーである。キーが @c Mplist 
Packit Service a721b1
    であるプロパティの値は plist でなくてはならない。  */
Packit Service a721b1
Packit Service a721b1
MSymbol Mplist;
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Symbol whose name is "mtext".
Packit Service a721b1
Packit Service a721b1
    The symbol @c Mtext has the name <tt>"mtext"</tt>.  It is a
Packit Service a721b1
    managing key.  A value of a property whose key is @c Mtext must be an
Packit Service a721b1
    M-text.  */
Packit Service a721b1
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief "mtext" を名前として持つシンボル.
Packit Service a721b1
Packit Service a721b1
    シンボル @c Mtext は <tt>"mtext"</tt>
Packit Service a721b1
    という名前を持つ管理キーである。キーが @c Mtext 
Packit Service a721b1
    であるプロパティの値は M-text でなくてはならない。      */
Packit Service a721b1
Packit Service a721b1
MSymbol Mtext;
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Create a property list object.
Packit Service a721b1
Packit Service a721b1
    The mplist () function returns a newly created property list
Packit Service a721b1
    object of length zero.
Packit Service a721b1
Packit Service a721b1
    @returns
Packit Service a721b1
    This function returns a newly created property list.
Packit Service a721b1
Packit Service a721b1
    @errors
Packit Service a721b1
    This function never fails.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリストオブジェクトを作る.
Packit Service a721b1
Packit Service a721b1
    関数 mplist () は長さ 0 のプロパティリストオブジェクトを新しく作って返す。
Packit Service a721b1
Packit Service a721b1
    @returns
Packit Service a721b1
    この関数は新しく作られたプロパティリストオブジェクトを返す。
Packit Service a721b1
Packit Service a721b1
    @errors
Packit Service a721b1
    この関数は決して失敗しない。     */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist (void)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *plist;
Packit Service a721b1
Packit Service a721b1
  MPLIST_NEW (plist);
Packit Service a721b1
  return plist;
Packit Service a721b1
}  
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Copy a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_copy () function copies property list $PLIST.  In the
Packit Service a721b1
    copy, the values are the same as those of $PLIST.
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    This function returns a newly created plist which is a copy of
Packit Service a721b1
    $PLIST.  
Packit Service a721b1
Packit Service a721b1
    @errors
Packit Service a721b1
    This function never fails.  */ 
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリストをコピーする.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_copy () はプロパティリスト $PLIST 
Packit Service a721b1
    をコピーする。コピーのすべての値はコピー元 $PLIST の値と同じである。
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    この関数は新しく作られた、$PLIST のコピーであるプロパティリストを返す。    
Packit Service a721b1
Packit Service a721b1
    @errors
Packit Service a721b1
    この関数は決して失敗しない。     */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist_copy (MPlist *plist)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *copy = mplist (), *pl = copy;
Packit Service a721b1
Packit Service a721b1
  MPLIST_DO (plist, plist)
Packit Service a721b1
    {
Packit Service a721b1
      if (MPLIST_NESTED_P (plist))
Packit Service a721b1
	MPLIST_SET_NESTED_P (pl);
Packit Service a721b1
      pl = mplist_add (pl, MPLIST_KEY (plist), MPLIST_VAL (plist));
Packit Service a721b1
    }
Packit Service a721b1
  return copy;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Set the value of a property in a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_put () function searches property list $PLIST
Packit Service a721b1
    from the beginning for a property whose key is $KEY.  If such a
Packit Service a721b1
    property is found, its value is changed to $VALUE.  Otherwise, a
Packit Service a721b1
    new property whose key is $KEY and value is $VALUE is appended at
Packit Service a721b1
    the end of $PLIST.  See the documentation of mplist_add () for
Packit Service a721b1
    the restriction on $KEY and $VAL.
Packit Service a721b1
Packit Service a721b1
    If $KEY is a managing key, $VAL must be a managed object.  In this
Packit Service a721b1
    case, the reference count of the old value, if not @c NULL, is
Packit Service a721b1
    decremented by one, and that of $VAL is incremented by one.
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    If the operation was successful, mplist_put () returns a sublist of
Packit Service a721b1
    $PLIST whose first element is the just modified or added one.
Packit Service a721b1
    Otherwise, it returns @c NULL.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリスト中のプロパティの値を設定する.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_put () はプロパティリスト $PLIST を始めから探して、キーが
Packit Service a721b1
    $KEY であるプロパティを見つける。見つかれば、その値を $VALUE 
Packit Service a721b1
    に変更する。見つからなければ、キーが $KEY で値が $VALUE 
Packit Service a721b1
    である新しいプロパティが $PLIST の末尾に追加される。$KEY と $VAL
Packit Service a721b1
    に対する制限については、mplist_add () の説明を参照。
Packit Service a721b1
Packit Service a721b1
    $KEY が管理キーならば、
Packit Service a721b1
    $VAL は管理下オブジェクトでなくてはならない。この場合、古い値の参照数は 
Packit Service a721b1
    @c NULL でなければ 1 減らされ、$VAL の参照数は 1 増やされる。
Packit Service a721b1
Packit Service a721b1
    @return 
Packit Service a721b1
    処理が成功すれば mplist_put () は変更されたか追加された要素から始まる
Packit Service a721b1
    $PLIST の部分リストを返す。そうでなければ @c NULL を返す。   */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist_put (MPlist *plist, MSymbol key, void *val)
Packit Service a721b1
{
Packit Service a721b1
  if (key == Mnil)
Packit Service a721b1
    MERROR (MERROR_PLIST, NULL);
Packit Service a721b1
  MPLIST_FIND (plist, key);
Packit Service a721b1
  if (key->managing_key)
Packit Service a721b1
    {
Packit Service a721b1
      if (! MPLIST_TAIL_P (plist))
Packit Service a721b1
	M17N_OBJECT_UNREF (MPLIST_VAL (plist));
Packit Service a721b1
      if (val)
Packit Service a721b1
	M17N_OBJECT_REF (val);
Packit Service a721b1
    }
Packit Service a721b1
  MPLIST_SET (plist, key, val);
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Get the value of a property in a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_get () function searches property list $PLIST from the
Packit Service a721b1
    beginning for a property whose key is $KEY.  If such a property is
Packit Service a721b1
    found, its value is returned as the type of <tt>(void *)</tt>.  If
Packit Service a721b1
    not found, @c NULL is returned.
Packit Service a721b1
Packit Service a721b1
    When @c NULL is returned, there are two possibilities: one is the
Packit Service a721b1
    case where no property is found (see above); the other is the case
Packit Service a721b1
    where a property is found and its value is @c NULL.  In case that
Packit Service a721b1
    these two cases must be distinguished, use the mplist_find_by_key ()
Packit Service a721b1
    function.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリスト中のプロパティの値を得る.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_get () は、プロパティリスト $PLIST を始めから探して、キー
Packit Service a721b1
    が $KEY であるプロパティを見つける。見つかれば、その値を
Packit Service a721b1
    <tt>(void *)</tt> 型で返す。見つからなければ @c NULL を返す。
Packit Service a721b1
Packit Service a721b1
    @c NULL が返った際には二つの可能性がある: 
Packit Service a721b1
    上記のようにプロパティが見つからなかった場合と、プロパティが見つかり、その値が
Packit Service a721b1
    @c NULL である場合である。これらを区別する必要がある場合には関数 
Packit Service a721b1
    mplist_find_by_key () を使うこと。  */
Packit Service a721b1
Packit Service a721b1
/***
Packit Service a721b1
    @seealso
Packit Service a721b1
    mplist_find_by_key () */
Packit Service a721b1
Packit Service a721b1
void *
Packit Service a721b1
mplist_get (MPlist *plist, MSymbol key)
Packit Service a721b1
{
Packit Service a721b1
  MPLIST_FIND (plist, key);
Packit Service a721b1
  return (MPLIST_TAIL_P (plist) ? NULL : MPLIST_VAL (plist));
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Set the value (function pointer) of a property in a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_put_func () function is similar to mplist_put () but for
Packit Service a721b1
    setting function pointer $FUNC in property list $PLIST for key
Packit Service a721b1
    $KEY.  $KEY must not be a managing key.  */
Packit Service a721b1
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリスト中のプロパティに関数ポインタである値を設定する.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_put_func () は関数 mplist_put () 同様、プロパティリスト $PLIST
Packit Service a721b1
    中でキーが $KEY であるプロパティに値を設定する。但しその値は関数ポインタ
Packit Service a721b1
    $FUNC である。$KEY は管理キーであってはならない。  */
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/***
Packit Service a721b1
    @seealso
Packit Service a721b1
    mplist_put (), M17N_FUNC ()  */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist_put_func (MPlist *plist, MSymbol key, M17NFunc func)
Packit Service a721b1
{
Packit Service a721b1
  if (key == Mnil || key->managing_key)
Packit Service a721b1
    MERROR (MERROR_PLIST, NULL);
Packit Service a721b1
  MPLIST_FIND (plist, key);
Packit Service a721b1
  MPLIST_KEY (plist) = key;
Packit Service a721b1
  MPLIST_FUNC (plist) = func;
Packit Service a721b1
  MPLIST_SET_VAL_FUNC_P (plist);
Packit Service a721b1
  if (! plist->next)
Packit Service a721b1
    MPLIST_NEW ((plist)->next);
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Get the value (function pointer) of a property in a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_get_func () function is similar to mplist_get () but for
Packit Service a721b1
    getting a function pointer from property list $PLIST by key $KEY.  */
Packit Service a721b1
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリストからプロパティの関数ポインタである値を得る.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_get_func () は関数 mplist_get () と同様に、プロパティリ
Packit Service a721b1
    スト $PLIST 中でキーが $KEY であるプロパティの値、但し関数ポインタ、
Packit Service a721b1
    を得る。 */
Packit Service a721b1
Packit Service a721b1
Packit Service a721b1
/***
Packit Service a721b1
    @seealso
Packit Service a721b1
    mplist_get () */
Packit Service a721b1
M17NFunc
Packit Service a721b1
mplist_get_func (MPlist *plist, MSymbol key)
Packit Service a721b1
{
Packit Service a721b1
  MPLIST_FIND (plist, key);
Packit Service a721b1
  return (MPLIST_TAIL_P (plist) ? NULL : MPLIST_FUNC (plist));
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Add a property at the end of a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_add () function appends at the end of property list
Packit Service a721b1
    $PLIST a property whose key is $KEY and value is $VAL.  $KEY can
Packit Service a721b1
    be any symbol other than @c Mnil.
Packit Service a721b1
Packit Service a721b1
    If $KEY is a managing key, $VAL must be a managed object.  In this
Packit Service a721b1
    case, the reference count of $VAL is incremented by one.
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    If the operation was successful, mplist_add () returns a sublist of
Packit Service a721b1
    $PLIST whose first element is the just added one.  Otherwise, it
Packit Service a721b1
    returns @c NULL.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリスト末尾にプロパティを追加する.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_add () は、プロパティリスト $PLIST の末尾にキーが $KEY 
Packit Service a721b1
    で値が $VAL であるプロパティを追加する。$KEY は、@c Mnil 以外の任意のシンボルでよい。
Packit Service a721b1
Packit Service a721b1
    $KEY が管理キーならば、$VAL は管理下オブジェクトでなくてはならない。この場合、
Packit Service a721b1
    $VAL の参照数は 1 増やされる。
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    処理が成功すれば mplist_add () は追加された要素から始まる $PLIST 
Packit Service a721b1
    の部分リストを返す。そうでなければ @c NULL を返す。  */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist_add (MPlist *plist, MSymbol key, void *val)
Packit Service a721b1
{
Packit Service a721b1
  if (key == Mnil)
Packit Service a721b1
    MERROR (MERROR_PLIST, NULL);
Packit Service a721b1
  MPLIST_FIND (plist, Mnil);
Packit Service a721b1
  if (val && key->managing_key)
Packit Service a721b1
    M17N_OBJECT_REF (val);
Packit Service a721b1
  MPLIST_KEY (plist) = key;
Packit Service a721b1
  MPLIST_VAL (plist) = val;
Packit Service a721b1
  MPLIST_NEW (plist->next);
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Add a property at the beginning of a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_push () function inserts at the beginning of property
Packit Service a721b1
    list $PLIST a property whose key is $KEY and value is $VAL.
Packit Service a721b1
Packit Service a721b1
    If $KEY is a managing key, $VAL must be a managed object.  In this
Packit Service a721b1
    case, the reference count of $VAL is incremented by one.
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    If the operation was successful, this function returns $PLIST.
Packit Service a721b1
    Otherwise, it returns @c NULL.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリストの先頭にプロパティを挿入する.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_push () はプロパティリスト $PLIST の先頭にキーが $KEY 
Packit Service a721b1
    で値が $VAL であるオブジェクトを挿入する。
Packit Service a721b1
Packit Service a721b1
    $KEY が管理キーならば、$VAL は管理下オブジェクトでなくてはならない。この場合、
Packit Service a721b1
    $VAL の参照数は 1 増やされる。
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    処理が成功すればこの関数は $PLIST を返し、そうでなければ@c NULL 
Packit Service a721b1
    を返す。  */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist_push (MPlist *plist, MSymbol key, void *val)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *pl;
Packit Service a721b1
Packit Service a721b1
  if (key == Mnil)
Packit Service a721b1
    MERROR (MERROR_PLIST, NULL);
Packit Service a721b1
  MPLIST_NEW (pl);
Packit Service a721b1
  MPLIST_KEY (pl) = MPLIST_KEY (plist);
Packit Service a721b1
  MPLIST_VAL (pl) = MPLIST_VAL (plist);
Packit Service a721b1
  if (MPLIST_NESTED_P (plist))
Packit Service a721b1
    MPLIST_SET_NESTED_P (pl);
Packit Service a721b1
  MPLIST_NEXT (pl) = MPLIST_NEXT (plist);
Packit Service a721b1
  plist->next = pl;
Packit Service a721b1
  if (val && key->managing_key)
Packit Service a721b1
    M17N_OBJECT_REF (val);
Packit Service a721b1
  MPLIST_KEY (plist) = key;
Packit Service a721b1
  MPLIST_VAL (plist) = val;
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Remove a property at the beginning of a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_pop () function removes a property at the beginning of
Packit Service a721b1
    property list $PLIST.  As a result, the second key and value of
Packit Service a721b1
    the $PLIST become the first ones.
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    If the operation was successful, this function return the value of
Packit Service a721b1
    the just popped property.  Otherwise, it returns @c NULL.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリストの先頭からプロパティを削除する.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_pop () はプロパティリスト $PLIST の先頭のプロパティを削
Packit Service a721b1
    除する。結果として、元の2番目のキーと値が先頭のキーと値になる。
Packit Service a721b1
Packit Service a721b1
    @return 
Packit Service a721b1
    処理に成功すれば、この関数は削除されたプロパティの値を返す。そうでなければ
Packit Service a721b1
    @c NULL を返す。  */
Packit Service a721b1
Packit Service a721b1
void *
Packit Service a721b1
mplist_pop (MPlist *plist)
Packit Service a721b1
{
Packit Service a721b1
  void *val;
Packit Service a721b1
  MPlist *next;
Packit Service a721b1
Packit Service a721b1
  if (MPLIST_TAIL_P (plist))
Packit Service a721b1
    return NULL;
Packit Service a721b1
  val = MPLIST_VAL (plist);
Packit Service a721b1
  next = MPLIST_NEXT (plist);
Packit Service a721b1
  MPLIST_KEY (plist) = MPLIST_KEY (next);
Packit Service a721b1
  MPLIST_VAL (plist) = MPLIST_VAL (next);
Packit Service a721b1
  if (MPLIST_KEY (plist) != Mnil
Packit Service a721b1
      && MPLIST_KEY (plist)->managing_key
Packit Service a721b1
      && MPLIST_VAL (plist))
Packit Service a721b1
    M17N_OBJECT_REF (MPLIST_VAL (plist));
Packit Service a721b1
  MPLIST_NEXT (plist) = MPLIST_NEXT (next);
Packit Service a721b1
  if (plist->next)
Packit Service a721b1
    M17N_OBJECT_REF (plist->next);
Packit Service a721b1
  M17N_OBJECT_UNREF (next);
Packit Service a721b1
  return val;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Find a property of a specific key in a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_find_by_key () function searches property list
Packit Service a721b1
    $PLIST from the beginning for a property whose key is $KEY.  If
Packit Service a721b1
    such a property is found, a sublist of $PLIST whose first element
Packit Service a721b1
    is the found one is returned.  Otherwise, @c NULL is returned.
Packit Service a721b1
Packit Service a721b1
    If $KEY is @c Mnil, it returns a sublist of $PLIST whose
Packit Service a721b1
    first element is the last one of $PLIST.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリスト中から指定のキーを持つプロパティを探す.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_find_by_key () はプロパティリスト $PLIST 
Packit Service a721b1
    を始めから探 して、キーが $KEY 
Packit Service a721b1
    であるプロパティを見つける。見つかれば、そのプロパティから始まる
Packit Service a721b1
    $PLIST の部分リストを返す。そうでなければ @c NULL を返す。
Packit Service a721b1
Packit Service a721b1
    $KEY が @c Mnil ならば、$PLIST の最後の要素から始まる部分リストを返す。  */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist_find_by_key (MPlist *plist, MSymbol key)
Packit Service a721b1
{
Packit Service a721b1
  MPLIST_FIND (plist, key);
Packit Service a721b1
  return (MPLIST_TAIL_P (plist)
Packit Service a721b1
	  ? (key == Mnil ? plist : NULL)
Packit Service a721b1
	  : plist);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Find a property of a specific value in a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_find_by_value () function searches property list $PLIST
Packit Service a721b1
    from the beginning for a property whose value is $VAL.  If such a
Packit Service a721b1
    property is found, a sublist of $PLIST whose first element is the
Packit Service a721b1
    found one is returned.  Otherwise, @c NULL is returned.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリスト中から指定の値を持つプロパティを探す.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_find_by_value () はプロパティリスト $PLIST 
Packit Service a721b1
    を始めから探して、値が $VAL 
Packit Service a721b1
    であるプロパティを見つける。見つかれば、そのプロパティから始まる
Packit Service a721b1
    $PLIST の部分リストを返す。そうでなければ @c NULL を返す。 */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist_find_by_value (MPlist *plist, void *val)
Packit Service a721b1
{
Packit Service a721b1
  MPLIST_DO (plist, plist)
Packit Service a721b1
    {
Packit Service a721b1
      if (MPLIST_VAL (plist) == val)
Packit Service a721b1
	return plist;
Packit Service a721b1
    }
Packit Service a721b1
  return NULL;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Return the next sublist of a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_next () function returns a pointer to the sublist of
Packit Service a721b1
    property list $PLIST, which begins at the second element in $PLIST.  If the
Packit Service a721b1
    length of $PLIST is zero, it returns @c NULL.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリストの次の部分リストを返す.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_next () はプロパティリスト $PLIST の 2 
Packit Service a721b1
    番目の要素から始まる部分リストへのポインタを返す。$PLIST の長さが 0 
Packit Service a721b1
    ならば @c NULL を返す。  */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist_next (MPlist *plist)
Packit Service a721b1
{
Packit Service a721b1
  return (MPLIST_TAIL_P (plist) ? NULL : plist->next);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Set the first property in a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_set () function sets the key and the value of the first
Packit Service a721b1
    property in property list $PLIST to $KEY and $VALUE, respectively.
Packit Service a721b1
    See the documentation of mplist_add () for the restriction on $KEY
Packit Service a721b1
    and $VAL.
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    If the operation was successful, mplist_set () returns $PLIST.
Packit Service a721b1
    Otherwise, it returns @c NULL.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリストの最初のプロパティを設定する.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_set () はプロパティリスト $PLIST 
Packit Service a721b1
    の最初のプロパティのキーと値をそれぞれ $KEY と $VALUE に設定する。
Packit Service a721b1
    $KEY と $VAL に対する制限については、mplist_add () の説明を参照。
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    処理に成功すれば mplist_set () は $PLIST を返す。そうでなければ @c NULL を返す。  */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist_set (MPlist *plist, MSymbol key, void * val)
Packit Service a721b1
{
Packit Service a721b1
  if (key == Mnil)
Packit Service a721b1
    {
Packit Service a721b1
      if (! MPLIST_TAIL_P (plist))
Packit Service a721b1
	{
Packit Service a721b1
	  key = MPLIST_KEY (plist);
Packit Service a721b1
	  M17N_OBJECT_UNREF (MPLIST_NEXT (plist));
Packit Service a721b1
	  MPLIST_KEY (plist) = Mnil;
Packit Service a721b1
	  if (key->managing_key)
Packit Service a721b1
	    M17N_OBJECT_UNREF (MPLIST_VAL (plist));
Packit Service a721b1
	  plist->next = NULL;
Packit Service a721b1
	}
Packit Service a721b1
    }
Packit Service a721b1
  else
Packit Service a721b1
    {
Packit Service a721b1
      if (val && key->managing_key)
Packit Service a721b1
	M17N_OBJECT_REF (val);
Packit Service a721b1
      if (! MPLIST_TAIL_P (plist)
Packit Service a721b1
	  && MPLIST_KEY (plist)->managing_key)
Packit Service a721b1
	M17N_OBJECT_UNREF (MPLIST_VAL (plist));
Packit Service a721b1
      MPLIST_SET (plist, key, val);
Packit Service a721b1
    }
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Return the length of a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_length () function returns the number of properties in
Packit Service a721b1
    property list  $PLIST.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリストの長さを返す.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_length () はプロパティリスト $PLIST 中のプロパティの数を返す。  */
Packit Service a721b1
Packit Service a721b1
int
Packit Service a721b1
mplist_length (MPlist *plist)
Packit Service a721b1
{
Packit Service a721b1
  int n;
Packit Service a721b1
Packit Service a721b1
  for (n = 0; ! (MPLIST_TAIL_P (plist)); n++, plist = plist->next);
Packit Service a721b1
  return n;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Return the key of the first property in a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_key () function returns the key of the first property
Packit Service a721b1
    in property list $PLIST.  If the length of $PLIST is zero,
Packit Service a721b1
    it returns @c Mnil.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリスト中の最初のプロパティのキーを返す.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_key () は、プロパティリスト $PLIST 
Packit Service a721b1
    中の最初のプロパティのキーを返す。$PLIST の長さが 0 ならば、 @c Mnil 
Packit Service a721b1
    を返す。  */
Packit Service a721b1
Packit Service a721b1
MSymbol
Packit Service a721b1
mplist_key (MPlist *plist)
Packit Service a721b1
{
Packit Service a721b1
  return MPLIST_KEY (plist);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*=*/
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Return the value of the first property in a property list.
Packit Service a721b1
Packit Service a721b1
    The mplist_value () function returns the value of the first
Packit Service a721b1
    property in property list  $PLIST.  If the length of $PLIST
Packit Service a721b1
    is zero, it returns @c NULL.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリスト中の最初のプロパティの値を返す.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_value () は、プロパティリスト $PLIST 中の最初のプロパティの値を返す。
Packit Service a721b1
    $PLIST の長さが 0 ならば、 @c Mnil を返す。  */
Packit Service a721b1
Packit Service a721b1
void *
Packit Service a721b1
mplist_value (MPlist *plist)
Packit Service a721b1
{
Packit Service a721b1
  return MPLIST_VAL (plist);
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Generate a property list by deserializing an M-text.
Packit Service a721b1
Packit Service a721b1
    The mplist_deserialize () function parses M-text $MT and returns a
Packit Service a721b1
    property list.
Packit Service a721b1
Packit Service a721b1
    The syntax of $MT is as follows.
Packit Service a721b1
Packit Service a721b1
    MT ::= '(' ELEMENT * ')'
Packit Service a721b1
Packit Service a721b1
    ELEMENT ::= SYMBOL | INTEGER | M-TEXT | PLIST
Packit Service a721b1
Packit Service a721b1
    SYMBOL ::= ascii-character-sequence
Packit Service a721b1
Packit Service a721b1
    INTEGER ::= '-' ? [ '0' | .. | '9' ]+
Packit Service a721b1
		| '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
Packit Service a721b1
Packit Service a721b1
    M-TEXT ::= '"' character-sequence '"'
Packit Service a721b1
Packit Service a721b1
    Each alternatives of @c ELEMENT is assigned one of these keys: @c
Packit Service a721b1
    Msymbol, @c Minteger, @c Mtext, @c Mplist
Packit Service a721b1
Packit Service a721b1
    In an ascii-character-sequence, a backslash (\) is used as the escape
Packit Service a721b1
    character, which means that, for instance, <tt>abc\ def</tt>
Packit Service a721b1
    produces a symbol whose name is of length seven with the fourth
Packit Service a721b1
    character being a space.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief M-text をデシリアライズしてプロパティリストを作る.
Packit Service a721b1
Packit Service a721b1
    関数 mplist_deserialize () は M-text $MT を解析してプロパティリストを返す。
Packit Service a721b1
Packit Service a721b1
    $MT のシンタックスは以下の通り。
Packit Service a721b1
Packit Service a721b1
    MT ::= '(' ELEMENT * ')'
Packit Service a721b1
Packit Service a721b1
    ELEMENT ::= SYMBOL | INTEGER | M-TEXT | PLIST
Packit Service a721b1
Packit Service a721b1
    SYMBOL ::= アスキー文字列
Packit Service a721b1
Packit Service a721b1
    INTEGER ::= '-' ? [ '0' | .. | '9' ]+
Packit Service a721b1
		| '0x' [ '0' | .. | '9' | 'A' | .. | 'F' | 'a' | .. | 'f' ]+
Packit Service a721b1
Packit Service a721b1
    M-TEXT ::= '"' character-sequence '"'
Packit Service a721b1
Packit Service a721b1
    @c ELEMENT の各選択肢はキー:@c Msymbol, @c Minteger, @c Mtext,
Packit Service a721b1
    @c Mplist のいずれかを割り当てられている。
Packit Service a721b1
Packit Service a721b1
    アスキー文字列内では、バックスラッシュ (\) がエスケープ文字として用いられる。たとえば
Packit Service a721b1
    <tt>abc\ def</tt> は 4 文字目が空白文字であり長さが 7 
Packit Service a721b1
    である持つ名前を持つシンボルを生成する。   */
Packit Service a721b1
Packit Service a721b1
MPlist *
Packit Service a721b1
mplist_deserialize (MText *mt)
Packit Service a721b1
{
Packit Service a721b1
  MPlist *plist;
Packit Service a721b1
  MText *tmp = NULL;
Packit Service a721b1
Packit Service a721b1
  if (mt->format > MTEXT_FORMAT_UTF_8)
Packit Service a721b1
    {
Packit Service a721b1
      if (MTEXT_READ_ONLY_P (mt))
Packit Service a721b1
	mt = tmp = mtext_cpy (mtext (), mt);
Packit Service a721b1
      else
Packit Service a721b1
	mtext__adjust_format (mt, MTEXT_FORMAT_UTF_8);
Packit Service a721b1
    }
Packit Service a721b1
  plist = mplist__from_string (MTEXT_DATA (mt), mtext_nbytes (mt));
Packit Service a721b1
  if (tmp)
Packit Service a721b1
    M17N_OBJECT_UNREF (tmp);
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*** @}  */
Packit Service a721b1
Packit Service a721b1
/*** @addtogroup m17nDebug */
Packit Service a721b1
/*=*/
Packit Service a721b1
/*** @{  */
Packit Service a721b1
Packit Service a721b1
/***en
Packit Service a721b1
    @brief Dump a property list.
Packit Service a721b1
Packit Service a721b1
    The mdebug_dump_plist () function prints a property list $PLIST in
Packit Service a721b1
    a human readable way to the stderr or to what specified by the
Packit Service a721b1
    environment variable MDEBUG_OUTPUT_FILE.  $INDENT specifies how
Packit Service a721b1
    many columns to indent the lines but the first one.
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    This function returns $PLIST.  */
Packit Service a721b1
/***ja
Packit Service a721b1
    @brief プロパティリストをダンプする.
Packit Service a721b1
Packit Service a721b1
    関数 mdebug_dump_plist () はプロパティリスト $PLIST を標準エラー出
Packit Service a721b1
    力もしくは環境変数 MDEBUG_DUMP_FONT で指定されたファイルに人間に可
Packit Service a721b1
    読な形で印刷する。 $INDENT は2行目以降のインデントを指定する。
Packit Service a721b1
Packit Service a721b1
    @return
Packit Service a721b1
    この関数は $PLIST を返す。  */
Packit Service a721b1
MPlist *
Packit Service a721b1
mdebug_dump_plist (MPlist *plist, int indent)
Packit Service a721b1
{
Packit Service a721b1
  char *prefix = (char *) alloca (indent + 1);
Packit Service a721b1
  MPlist *pl;
Packit Service a721b1
Packit Service a721b1
  memset (prefix, 32, indent);
Packit Service a721b1
  prefix[indent] = 0;
Packit Service a721b1
Packit Service a721b1
  fprintf (mdebug__output, "(");
Packit Service a721b1
  MPLIST_DO (pl, plist)
Packit Service a721b1
    {
Packit Service a721b1
      if (pl != plist)
Packit Service a721b1
	fprintf (mdebug__output, "\n%s ", prefix);
Packit Service a721b1
      write_element (NULL, pl, indent + 1);
Packit Service a721b1
    }
Packit Service a721b1
  fprintf (mdebug__output, ")");
Packit Service a721b1
  return plist;
Packit Service a721b1
}
Packit Service a721b1
Packit Service a721b1
/*** @} */
Packit Service a721b1
Packit Service a721b1
/*
Packit Service a721b1
  Local Variables:
Packit Service a721b1
  coding: euc-japan
Packit Service a721b1
  End:
Packit Service a721b1
*/