(struct MInputContext): Fix typo in comment.
[m17n/m17n-lib.git] / src / language.c
index 02bc214..b31eeeb 100644 (file)
@@ -1,5 +1,5 @@
-/* language.c -- language module.
-   Copyright (C) 2003, 2004
+/* language.c -- language (and script) module.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
 
    You should have received a copy of the GNU Lesser General Public
    License along with the m17n library; if not, write to the Free
 
    You should have received a copy of the GNU Lesser General Public
    License along with the m17n library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    02111-1307, USA.  */
 
 #include <config.h>
 #include <stdlib.h>
    02111-1307, USA.  */
 
 #include <config.h>
 #include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <locale.h>
 #include "m17n.h"
 #include "m17n-misc.h"
 #include "internal.h"
 #include "language.h"
 #include "symbol.h"
 #include "m17n.h"
 #include "m17n-misc.h"
 #include "internal.h"
 #include "language.h"
 #include "symbol.h"
+#include "plist.h"
+#include "mtext.h"
+
+#if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
+
+static MPlist *language_list;
+static MPlist *script_list;
+static MPlist *langname_list;
+
+static MPlist *
+load_lang_script_list (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
+{
+  MDatabase *mdb = mdatabase_find (tag0, tag1, tag2, tag3);
+  MPlist *plist, *pl, *p;
+
+  if (! mdb
+      || ! (plist = mdatabase_load (mdb)))
+    return NULL;
+  /* Check at least if the plist is ((SYMBOL ...) ...).  */
+  for (pl = plist; ! MPLIST_TAIL_P (pl);)
+    {
+      if (! MPLIST_PLIST_P (pl))
+       mplist__pop_unref (pl);
+      else
+       {
+         p = MPLIST_PLIST (pl);
+         if (! MPLIST_SYMBOL_P (p))
+           mplist__pop_unref (pl);
+         else
+           pl = MPLIST_NEXT (pl);
+       }
+    }
+  return plist;
+}
+
+static int
+init_language_list (void)
+{
+  language_list = load_lang_script_list (msymbol ("standard"), Mlanguage,
+                                        msymbol ("iso639"), Mnil);
+  if (! language_list)
+    {
+      language_list = mplist ();
+      MERROR (MERROR_DB, -1);
+    }
+  return 0;
+}
+
+
+static int
+init_script_list (void)
+{
+  script_list = load_lang_script_list (msymbol ("standard"), Mscript,
+                                      msymbol ("unicode"), Mnil);
+  if (! script_list)
+    {
+      script_list = mplist ();
+      MERROR (MERROR_DB, -1);
+    }
+  return 0;
+}
+
+static MPlist *
+load_lang_name (MSymbol target3, MSymbol target2)
+{
+  MPlist *plist, *pl, *p;
+
+  plist = mplist ();
+  mplist_add (plist, Msymbol, target3);
+  pl = mdatabase_list (Mlanguage, Mname, target3, Mnil);
+  if (! pl && target2 != Mnil)
+    pl = mdatabase_list (Mlanguage, Mname, target2, Mnil);
+  if (pl)
+    {
+      MPLIST_DO (p, pl)
+       {
+         MDatabase *mdb = MPLIST_VAL (p);
+         MPlist *p0 = mdatabase_load (mdb), *p1, *territories;
+         MSymbol script = mdatabase_tag (mdb)[3];
+         
+         if (MPLIST_PLIST_P (p0))
+           {
+             p1 = MPLIST_PLIST (p0);
+             if (MPLIST_SYMBOL_P (p1) && MPLIST_SYMBOL (p1) == Mlanguage)
+               {
+                 p1 = MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (p1))));
+                 territories = p1;
+                 while (! MPLIST_TAIL_P (p1))
+                   {
+                     if (MPLIST_SYMBOL_P (p1))
+                       p1 = MPLIST_NEXT (p1);
+                     else
+                       mplist__pop_unref (p1);
+                   }
+                 M17N_OBJECT_REF (territories);
+                 mplist__pop_unref (p0);
+               }
+             else
+               territories = mplist ();
+             mplist_push (p0, Mplist, territories);
+             M17N_OBJECT_UNREF (territories);
+             mplist_push (p0, Msymbol, script);
+             mplist_add (plist, Mplist, p0);
+             M17N_OBJECT_UNREF (p0);
+           }
+       }
+      M17N_OBJECT_UNREF (pl);
+    }
+  mplist_push (langname_list, Mplist, plist);
+  M17N_OBJECT_UNREF (plist);
+  return plist;
+}
 
 \f
 /* Internal API */
 
 \f
 /* Internal API */
 int
 mlang__init ()
 {
 int
 mlang__init ()
 {
-  /* ISO 639 */
-  struct {
-    char *name, *fullname;
-  } lang_rec[] =
-      { {"ab", "Abkhazian"},
-       {"aa", "Afar"},
-       {"af", "Afrikaans"},
-       {"sq", "Albanian"},
-       {"am", "Amharic"},
-       {"ar", "Arabic"},
-       {"hy", "Armenian"},
-       {"as", "Assamese"},
-       {"ay", "Aymara"},
-       {"az", "Azerbaijani"},
-       {"ba", "Bashkir"},
-       {"eu", "Basque"},
-       {"bn", "Bengali"},              /* Bangla */
-       {"dz", "Bhutani"},
-       {"bh", "Bihari"},
-       {"bi", "Bislama"},
-       {"br", "Breton"},
-       {"bg", "Bulgarian"},
-       {"my", "Burmese"},
-       {"be", "Byelorussian"}, /* Belarusian */
-       {"km", "Cambodian"},    /* Khmer */
-       {"ca", "Catalan"},
-#if 0
-       {"??", "Cherokee"},
-       {"??", "Chewa"},
-#endif
-       {"zh", "Chinese"},
-       {"co", "Corsican"},
-       {"hr", "Croatian"},
-       {"cs", "Czech"},
-       {"da", "Danish"},
-#if 0
-       {"??", "Divehi"},
-#endif
-       {"nl", "Dutch"},
-#if 0
-       {"??", "Edo"},
-#endif
-       {"en", "English"},
-       {"eo", "Esperanto"},
-       {"et", "Estonian"},
-       {"fo", "Faeroese"},
-       {"fa", "Farsi"},
-       {"fj", "Fiji"},
-       {"fi", "Finnish"},
-#if 0
-       {"??", "Flemish"},
-#endif
-       {"fr", "French"},
-       {"fy", "Frisian"},
-#if 0
-       {"??", "Fulfulde"},
-#endif
-       {"gl", "Galician"},
-       {"gd", "Gaelic(Scottish)"},             /* Scottish */
-       {"gv", "Gaelic(Manx)"},         /* Manx */
-       {"ka", "Georgian"},
-       {"de", "German"},
-       {"el", "Greek"},
-       {"kl", "Greenlandic"},
-       {"gn", "Guarani"},
-       {"gu", "Gujarati"},
-       {"ha", "Hausa"},
-#if 0
-       {"??", "Hawaiian"},
-       {"iw", "Hebrew"},
-#endif
-       {"he", "Hebrew"},
-       {"hi", "Hindi"},
-       {"hu", "Hungarian"},
-#if 0
-       {"??", "Ibibio"},
-#endif
-       {"is", "Icelandic"},
-#if 0
-       {"??", "Igbo"},
-       {"in", "Indonesian"},
-#endif
-       {"id", "Indonesian"},
-#if 0
-       {"ia", "Interlingua"},
-       {"ie", "Interlingue"},
-#endif
-       {"iu", "Inuktitut"},
-       {"ik", "Inupiak"},
-       {"ga", "Irish"},
-       {"it", "Italian"},
-       {"ja", "Japanese"},
-       {"jw", "Javanese"},
-       {"kn", "Kannada"},
-#if 0
-       {"??", "Kanuri"},
-#endif
-       {"ks", "Kashmiri"},
-       {"kk", "Kazakh"},
-       {"rw", "Kinyarwanda"},  /* Ruanda */
-       {"ky", "Kirghiz"},
-       {"rn", "Kirundi"},              /* Rundi */
-       {"ko", "Korean"},
-       {"ku", "Kurdish"},
-       {"lo", "Laothian"},
-       {"la", "Latin"},
-       {"lv", "Latvian"},              /* Lettish */
-       {"ln", "Lingala"},
-       {"lt", "Lithuanian"},
-       {"mk", "Macedonian"},
-       {"mg", "Malagasy"},
-       {"ms", "Malay"},
-       {"ml", "Malayalam"},
-#if 0
-       {"??", "Manipuri"},
-#endif
-       {"mt", "Maltese"},
-       {"mi", "Maori"},
-       {"mr", "Marathi"},
-       {"mo", "Moldavian"},
-       {"mn", "Mongolian"},
-       {"na", "Nauru"},
-       {"ne", "Nepali"},
-       {"no", "Norwegian"},
-       {"oc", "Occitan"},
-       {"or", "Oriya"},
-       {"om", "Oromo"},                /* Afan, Galla */
-#if 0
-       {"??", "Papiamentu"},
-#endif
-       {"ps", "Pashto"},               /* Pushto */
-       {"pl", "Polish"},
-       {"pt", "Portuguese"},
-       {"pa", "Punjabi"},
-       {"qu", "Quechua"},
-       {"rm", "Rhaeto-Romance"},
-       {"ro", "Romanian"},
-       {"ru", "Russian"},
-#if 0
-       {"??", "Sami"},         /* Lappish */
-#endif
-       {"sm", "Samoan"},
-       {"sg", "Sangro"},
-       {"sa", "Sanskrit"},
-       {"sr", "Serbian"},
-       {"sh", "Serbo-Croatian"},
-       {"st", "Sesotho"},
-       {"tn", "Setswana"},
-       {"sn", "Shona"},
-       {"sd", "Sindhi"},
-       {"si", "Sinhalese"},
-       {"ss", "Siswati"},
-       {"sk", "Slovak"},
-       {"sl", "Slovenian"},
-       {"so", "Somali"},
-       {"es", "Spanish"},
-       {"su", "Sundanese"},
-       {"sw", "Swahili"},              /* Kiswahili */
-       {"sv", "Swedish"},
-#if 0
-       {"??", "Syriac"},
-#endif
-       {"tl", "Tagalog"},
-       {"tg", "Tajik"},
-#if 0
-       {"??", "Tamazight"},
-#endif
-       {"ta", "Tamil"},
-       {"tt", "Tatar"},
-       {"te", "Telugu"},
-       {"th", "Thai"},
-       {"bo", "Tibetan"},
-       {"ti", "Tigrinya"},
-       {"to", "Tonga"},
-       {"ts", "Tsonga"},
-       {"tr", "Turkish"},
-       {"tk", "Turkmen"},
-       {"tw", "Twi"},
-       {"ug", "Uighur"},
-       {"uk", "Ukrainian"},
-       {"ur", "Urdu"},
-       {"uz", "Uzbek"},
-#if 0
-       {"??", "Venda"},
-#endif
-       {"vi", "Vietnamese"},
-       {"vo", "Volapuk"},
-       {"cy", "Welsh"},
-       {"wo", "Wolof"},
-       {"xh", "Xhosa"},
-#if 0
-       {"??", "Yi"},
-       {"ji", "Yiddish"},
-#endif
-       {"yi", "Yiddish"},
-       {"yo", "Yoruba"},
-       {"zu", "Zulu"} };
-  int i;
-
-  Mlanguage = msymbol ("language");
-  msymbol_put (Mlanguage, Mtext_prop_serializer,
-              (void *) msymbol__serializer);
-  msymbol_put (Mlanguage, Mtext_prop_deserializer,
-              (void *) msymbol__deserializer);
-  for (i = 0; i < ((sizeof lang_rec) / (sizeof lang_rec[0])); i++)
-    msymbol_put (msymbol (lang_rec[i].name), Mlanguage,
-                msymbol (lang_rec[i].fullname));
+  msymbol_put_func (Mlanguage, Mtext_prop_serializer,
+                   M17N_FUNC (msymbol__serializer));
+  msymbol_put_func (Mlanguage, Mtext_prop_deserializer,
+                   M17N_FUNC (msymbol__deserializer));
+  Miso639_2 = msymbol ("iso639-2");
+  Miso639_1 = msymbol ("iso639-1");
+
+  language_list = script_list = langname_list = NULL;
   return 0;
 }
 
 void
 mlang__fini (void)
 {
   return 0;
 }
 
 void
 mlang__fini (void)
 {
+  M17N_OBJECT_UNREF (language_list);
+  M17N_OBJECT_UNREF (script_list);
+  M17N_OBJECT_UNREF (langname_list);
+}
+
+/*=*/
+
+/***en
+    @brief Get information about a language.
+
+    The mlanguage_info () function returns a well-formed @e plist that
+    contains information about $LANGUAGE.  $LANGUAGE is a symbol whose
+    name is an ISO639-2 3-letter language code, an ISO639-1 2-letter
+    language codes, or an English word.
+
+    The format of the plist is:
+
+@verbatim
+        (ISO639-2 [ISO639-1 | nil] ENGLISH-NAME ["NATIVE-NAME" | nil]
+                  ["REPRESENTATIVE-CHARACTERS"])
+@endverbatim
+
+    where, ISO639-2 is a symbol whose name is 3-letter language code
+    of ISO639-2, ISO639-1 is a symbol whose name is 2-letter language
+    code of ISO639-1, ENGLISH-NAME is a symbol whose name is the
+    English name of the language, "NATIVE-NAME" is an M-text written
+    by the most natural way in the language,
+    "REPRESENTATIVE-CHARACTERS" is an M-text that contains
+    representative characters used by the language.
+
+    It is assured that the formats of both M-texts are
+    #MTEXT_FORMAT_UTF_8.
+
+    @return
+    If the information is available, this function returns a plist
+    that should not be modified nor freed.  Otherwise, it returns
+    @c NULL.
+
+    @seealso
+    mlanguage_list ()  */
+
+MPlist *
+mlanguage__info (MSymbol language)
+{
+  MPlist *plist;
+
+  if (! language_list
+      && init_language_list () < 0)
+    return NULL;
+
+  MPLIST_DO (plist, language_list)
+    {
+      MPlist *pl = MPLIST_PLIST (plist);
+
+      if (MPLIST_SYMBOL (pl) == language)
+       return pl;
+      if (MPLIST_TAIL_P (pl))
+       continue;
+      pl = MPLIST_NEXT (pl);
+      if (MPLIST_SYMBOL_P (pl) && MPLIST_SYMBOL (pl) == language)
+       return MPLIST_PLIST (plist);
+      if (MPLIST_TAIL_P (pl))
+       continue;
+      pl = MPLIST_NEXT (pl);
+      if (MPLIST_MTEXT_P (pl))
+       {
+         MText *mt = MPLIST_MTEXT (pl);
+
+         if (mtext_nbytes (mt) == MSYMBOL_NAMELEN (language)
+             && strncasecmp ((char *) MTEXT_DATA (MPLIST_MTEXT (pl)),
+                             MSYMBOL_NAME (language),
+                             MSYMBOL_NAMELEN (language)) == 0)
+           return MPLIST_PLIST (plist);
+       }
+    }
+  return NULL;
+}
+
+static MPlist *
+mscript__info (MSymbol script)
+{
+  MPlist *plist;
+
+  if (! script_list
+      && init_script_list () < 0)
+    return NULL;
+  MPLIST_DO (plist, script_list)
+    {
+      MPlist *pl = MPLIST_PLIST (plist);
+
+      if (MPLIST_SYMBOL (pl) == script)
+       return pl;
+    }
+  return NULL;
+}
+
+MPlist *
+mscript__char_list (MSymbol name)
+{
+  MPlist *plist = mscript__info (name);
+
+  if (plist                    /* script name */
+      && (plist = MPLIST_NEXT (plist)) /* language list */
+      && ! MPLIST_TAIL_P (plist)
+      && (plist = MPLIST_NEXT (plist)) /* char list */
+      && MPLIST_PLIST_P (plist))
+    return MPLIST_PLIST (plist);
+  return NULL;
 }
 }
+
+MSymbol
+mscript__otf_tag (MSymbol script)
+{
+  MPlist *plist = mscript__info (script);
+
+  if (plist                    /* script name */
+      && (plist = MPLIST_NEXT (plist)) /* language list */
+      && ! MPLIST_TAIL_P (plist)
+      && (plist = MPLIST_NEXT (plist)) /* char list */
+      && ! MPLIST_TAIL_P (plist)
+      && (plist = MPLIST_NEXT (plist)) /* otf tag */
+      && MPLIST_SYMBOL_P (plist))
+    return MPLIST_SYMBOL (plist);
+  return NULL;
+}
+
+MSymbol
+mscript__from_otf_tag (MSymbol otf_tag)
+{
+  MPlist *plist;
+  /* As it is expected that this function is called in a sequence with
+     the same argument, we use a cache.  */
+  static MSymbol last_otf_tag, script;
+
+  if (! script_list)
+    {
+      last_otf_tag = script = Mnil;
+      if (init_script_list () < 0)
+       return Mnil;
+    }
+  if (otf_tag == last_otf_tag)
+    return script;
+  last_otf_tag = otf_tag;
+  script = Mnil;
+  MPLIST_DO (plist, script_list)
+    {
+      MPlist *pl = MPLIST_PLIST (plist), *p;
+
+      if (pl                          /* script name */
+         && (p = MPLIST_NEXT (pl))    /* language tag */
+         && ! MPLIST_TAIL_P (p)
+         && (p = MPLIST_NEXT (p)) /* char list */
+         && ! MPLIST_TAIL_P (p)
+         && (p = MPLIST_NEXT (p)) /* otf tag */
+         && ! MPLIST_TAIL_P (p))
+       {
+         if (MPLIST_SYMBOL_P (p))
+           {
+             if (otf_tag == MPLIST_SYMBOL (p))
+                 return MPLIST_SYMBOL (pl);
+           }
+         else if (MPLIST_PLIST (p))
+           {
+             MPlist *p0;
+
+             MPLIST_DO (p0, MPLIST_PLIST (p))
+               if (MPLIST_SYMBOL_P (p0) && otf_tag == MPLIST_SYMBOL (p0))
+                 return MPLIST_SYMBOL (pl);
+           }
+       }
+    }
+  return script;
+}
+
+#endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
+\f
+
+/* External API */
+
+MSymbol Miso639_1, Miso639_2;
+
+/*=*/
+
+/***en
+    @brief List 3-letter language codes.
+
+    The mlanguage_list () funciton returns a well-formed plist whose
+    keys are #Msymbol and values are symbols whose names are ISO639-2
+    3-letter language codes.
+
+    @return
+    This function returns a plist.  The caller should free it by
+    m17n_object_unref ().
+
+    @seealso
+    mscript_list ().  */
+
+/***ja
+    @brief 3ʸ»ú¸À¸ì¥³¡¼¥É¤ò¥ê¥¹¥È¤¹¤ë.
+
+    ´Ø¿ô mlanguage_list () ¤Ï¡¢À°·Á¼° (well-formed) plist ¤òÊÖ¤¹¡£³Æ¥­¡¼
+    ¤Ï #Msymbol ¤Ç¤¢¤ê¡¢¸Ä¡¹¤ÎÃͤϠISO639-2 ¤ËÄê¤á¤é¤ì¤¿3ʸ»ú¸À¸ì¥³¡¼
+    ¥É¤ò̾Á°¤È¤¹¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
+
+    @return
+    ¤³¤Î´Ø¿ô¤¬ÊÖ¤¹ plist ¤Ï¡¢¸Æ¤Ó½Ð¤·Â¦¤¬ m17n_object_unref () ¤ò»È¤Ã
+    ¤Æ²òÊü¤¹¤ëɬÍפ¬¤¢¤ë¡£
+
+    @seealso
+    mscript_list ().  */
+
+MPlist *
+mlanguage_list (void)
+{
+  MPlist *plist, *pl, *p, *p0;
+
+  if (! language_list
+      && init_language_list () < 0)
+    return NULL;
+  plist = pl = mplist ();
+  MPLIST_DO (p, language_list)
+    {
+      p0 = MPLIST_PLIST (p);
+      pl = mplist_add (pl, Msymbol, MPLIST_VAL (p0));
+    }
+  return plist;
+}
+
+/*=*/
+
+/***en
+    @brief Get a language code.
+
+    The mlanguage_code () function returns a symbol whose name is the
+    ISO639 language code of $LANGUAGE. $LANGUAGE is a symbol whose
+    name is an ISO639-2 3-letter language code, an ISO639-1 2-letter
+    language codes, or an English word.
+
+    $LEN specifies the type of the returned language code.  If it is
+    3, an ISO639-2 3-letter language code is returned.  If it is 2, an
+    ISO639-1 2-letter language code is returned when defined;
+    otherwise #Mnil is returned.  If it is 0, a 2-letter code is
+    returned when defined; otherwise a 3-letter code is returned.
+
+    @return
+    If the information is available, this function returns a non-#Mnil
+    symbol.  Otherwise, it returns #Mnil.
+
+    @seealso
+    mlanguage_name_list (), mlanguage_text ().  */
+
+/***ja
+    @brief ¸À¸ì¥³¡¼¥É¤òÆÀ¤ë.
+
+    ´Ø¿ô mlanguage_code () ¤Ï¡¢$LANGUAGE ¤ËÂбþ¤·¤¿ ISO-639 ¸À¸ì¥³¡¼¥É
+    ¤¬Ì¾Á°¤Ç¤¢¤ë¤è¤¦¤Ê¥·¥ó¥Ü¥ë¤òÊÖ¤¹¡£$LANGUAGE ¤Ï¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢¤½¤Î
+    Ì¾Á°¤Ï¡¢ISO639-2 3ʸ»ú¸À¸ì¥³¡¼¥É¡¢ISO639-1 2ʸ»ú¸À¸ì¥³¡¼¥É¡¢±Ñ¸ì̾¡¢
+    ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£
+
+    $LEN ¤ÏÊÖ¤µ¤ì¤ë¸À¸ì¥³¡¼¥É¤Î¼ïÎà¤ò·èÄꤹ¤ë¡£$LEN ¤¬3¤Î¾ì¹ç¤Ï 
+    ISO639-2 3ʸ»ú¸À¸ì¥³¡¼¥É¤¬ÊÖ¤µ¤ì¤ë¡£2¤Î¾ì¹ç¤Ï¡¢¤â¤·ÄêµÁ¤µ¤ì¤Æ¤¤¤ì
+    ¤Ð ISO639-1 2ʸ»ú¸À¸ì¥³¡¼¥É¤¬¡¢¤½¤¦¤Ç¤Ê¤±¤ì¤Ð #Mnil ¤¬ÊÖ¤µ¤ì¤ë¡£0 
+    ¤Î¾ì¹ç¤Ï¡¢¤â¤·ÄêµÁ¤µ¤ì¤Æ¤¤¤ì¤Ð2ʸ»ú¥³¡¼¥É¤¬¡¢¤½¤¦¤Ç¤Ê¤±¤ì¤Ð3ʸ»ú¥³¡¼
+    ¥É¤¬ÊÖ¤µ¤ì¤ë¡£
+
+    @return
+    ¤â¤·¾ðÊó¤¬ÆÀ¤é¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï #Mnil °Ê³°¤Î¥·¥ó¥Ü¥ë¤òÊÖ¤¹¡£¤½¤¦
+    ¤Ç¤Ê¤±¤ì¤Ð #Mnil ¤òÊÖ¤¹¡£
+
+    @seealso
+    mlanguage_name (), mlanguage_text ().  */
+
+MSymbol
+mlanguage_code (MSymbol language, int len)
+{
+  MPlist *plist = mlanguage__info (language);
+  MSymbol code;
+
+  if (! plist)
+    return Mnil;
+  if (! MPLIST_SYMBOL_P (plist))
+    return Mnil;
+  code = MPLIST_SYMBOL (plist);
+  if (len == 3)
+    return code;
+  plist = MPLIST_NEXT (plist);
+  return ((MPLIST_SYMBOL_P (plist) && MPLIST_SYMBOL (plist) != Mnil)
+         ? MPLIST_SYMBOL (plist)
+         : len == 0 ? code : Mnil);
+}
+
+/*=*/
+
+/***en
+    @brief Return the language names written in the specified language.
+
+    The mlanguage_name_list () function returns a plist of LANGUAGE's
+    names written in TARGET language.  SCRIPT and TERRITORY, if not #Mnil,
+    specifies which script and territory to concern at first.
+
+    LANGUAGE and TARGET must be a symbol whose name is an ISO639-2
+    3-letter language code or an ISO639-1 2-letter language codes.
+    TARGET may be #Mnil, in which case, the language of the current
+    locale is used.  If locale is not set or is C, English is used.
+
+    SCRIPT and TERRITORY must be a symbol whose name is a script and
+    territory name of a locale (e.g. "TW", "SG") respectively.
+
+    @return
+    If the translation is available, this function returns a non-empty
+    plist.  The first element has key #MText and the value is an
+    M-text of a translated language name.  If the succeeding elements
+    also have key #MText, their values are M-texts of alternate
+    translations.
+
+    If no translation is available, @c NULL is returned.
+
+    The returned plist should not be modified nor freed.
+
+    @seealso
+    mlanguage_code (), mlanguage_text ().  */
+
+MPlist *
+mlanguage_name_list (MSymbol language, MSymbol target,
+                    MSymbol script, MSymbol territory)
+{
+  MPlist *plist, *pl;
+  MSymbol language2, target2;
+
+  plist = mlanguage__info (language);
+  if (! plist)
+    return NULL;
+  language = MPLIST_SYMBOL (plist);
+  language2 = MPLIST_SYMBOL (MPLIST_NEXT (plist));
+  if (target != Mnil)
+    {
+      plist = mlanguage__info (target);
+      if (! plist)
+       return NULL;
+      target = MPLIST_SYMBOL (plist);
+      target2 = MPLIST_SYMBOL (MPLIST_NEXT (plist));
+    }
+  else
+    {
+      MLocale *locale = mlocale_set (LC_MESSAGES, NULL);
+
+      if (! locale)
+       {
+         target = msymbol ("eng");
+         target2 = msymbol ("en");
+         script = territory = Mnil;
+       }
+      else
+       {
+         target = mlocale_get_prop (locale, Mlanguage);
+         plist = mlanguage__info (target);
+         if (! plist)
+           return NULL;
+         target = MPLIST_SYMBOL (plist);
+         target2 = MPLIST_SYMBOL (MPLIST_NEXT (plist));
+         script = mlocale_get_prop (locale, Mscript);
+         territory = mlocale_get_prop (locale, Mterritory);
+       }
+    }
+
+  /* Now both LANGUAGE and TARGET are 3-letter codes.  */
+  if (! langname_list)
+    langname_list = mplist ();
+  plist = mplist__assq (langname_list, target);
+  if (plist)
+    plist = MPLIST_PLIST (plist);
+  else
+    plist = load_lang_name (target, target2);
+
+  /* PLIST = (TARGET (SCRIPT (TERRITORY ...) (LANG-CODE NAME ...) ...) ...) */
+  plist = MPLIST_NEXT (plist);
+  if (MPLIST_TAIL_P (plist))
+    return NULL;
+
+  MPLIST_DO (pl, plist)
+    {
+      MPlist *p = MPLIST_PLIST (pl), *p0;
+
+      if (MPLIST_SYMBOL (p) == script
+         && (territory == Mnil
+             || mplist_find_by_value (MPLIST_PLIST (MPLIST_NEXT (p)),
+                                      territory))
+         && (p = MPLIST_NEXT (MPLIST_NEXT (p)))
+         && ((p0 = mplist__assq (p, language))
+             || (p0 = mplist__assq (p, language2))))
+       {
+         plist = p0;
+         break;
+       }
+    }
+  if (MPLIST_TAIL_P (pl))
+    {
+      MPLIST_DO (pl, plist)
+       {
+         MPlist *p = MPLIST_NEXT (MPLIST_PLIST (pl)), *p0;
+
+         if ((territory == Mnil
+              || mplist_find_by_value (MPLIST_VAL (p), territory))
+             && (p = MPLIST_NEXT (MPLIST_NEXT (p)))
+             && ((p0 = mplist__assq (p, language))
+                 || (p0 = mplist__assq (p, language2))))
+           {
+             plist = p0;
+             break;
+           }
+       }
+      if (MPLIST_TAIL_P (pl))
+       {
+         MPLIST_DO (pl, plist)
+           {
+             MPlist *p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (pl))), *p0;
+
+             if ((p0 = mplist__assq (p, language))
+                 || (p0 = mplist__assq (p, language2)))
+               {
+                 plist = p0;
+                 break;
+               }
+           }
+         if (MPLIST_TAIL_P (pl))
+           return NULL;
+       }
+    }
+
+  plist = MPLIST_NEXT (MPLIST_PLIST (plist));
+  if (territory != Mnil)
+    {
+      MPLIST_DO (pl, MPLIST_NEXT (plist))
+       if (MPLIST_SYMBOL_P (pl) && MPLIST_SYMBOL (pl) == territory)
+         break;
+      if (! MPLIST_TAIL_P (pl)
+         && (pl = MPLIST_NEXT (pl))
+         && MPLIST_MTEXT_P (pl))
+       return pl;
+    }
+  MPLIST_DO (plist, plist)
+    if (MPLIST_MTEXT_P (plist))
+      break;
+  return (MPLIST_MTEXT_P (plist) ? plist : NULL);
+}
+
+/*=*/
+
+/***en
+    @brief Return the language name written in that language.
+
+    The mlanguage_text () function returns, in the form of M-text, the
+    language name of $LANGUAGE written in $LANGUAGE.  If the
+    representative characters of the language are known, the
+    characters of the returned M-text has a text property whose key is
+    #Mtext and whose value is an M-text that contains the
+    representative characters.
+
+    @return
+    If the information is available, this function returns an M-text
+    that should not be modified nor freed.  Otherwise, it returns @c
+    NULL.
+
+    @seealso
+    mlanguage_code (), mlanguage_name ().  */
+
+/***ja
+    @brief Í¿¤¨¤é¤ì¤¿¸À¸ì¼«¿È¤Ç½ñ¤«¤ì¤¿¸À¸ì̾¤òÊÖ¤¹.
+
+    ´Ø¿ô mlanguage_text () ¤Ï¡¢¸À¸ì $LANGUAGE ¤Ç½ñ¤«¤ì¤¿ $LANGUAGE ¤Î
+    Ì¾Á°¤ò M-text ¤Î·Á¼°¤ÇÊÖ¤¹¡£¤½¤Î¸À¸ì¤ÎÂåɽŪ¤Êʸ»ú¤¬¤ï¤«¤Ã¤Æ¤¤¤ë¾ì
+    ¹ç¤Ï¡¢ÊÖ¤µ¤ì¤ë M-text ¤Î³Æʸ»ú¤Ë¡¢¥­¡¼¤¬ #Mtext ¤ÇÃͤ¬¤½¤ÎÂåɽŪ¤Ê
+    Ê¸»ú¤ò´Þ¤à M-text ¤Ç¤¢¤ë¤è¤¦¤Ê¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£¤¬Éղ䵤ì¤ë¡£
+
+    @return
+    µá¤á¤ë¾ðÊó¤¬ÆÀ¤é¤ì¤¿¾ì¹ç¡¢¤³¤Î´Ø¿ô¤¬ÊÖ¤¹ M-text ¤òÊѹ¹¤·¤¿¤ê²òÊü¤·
+    ¤¿¤ê¤·¤Æ¤Ï¤¤¤±¤Ê¤¤¡£¾ðÊó¤¬ÆÀ¤é¤ì¤Ê¤«¤Ã¤¿¾ì¹ç¤Ï @c NULL ¤¬ÊÖ¤µ¤ì¤ë¡£
+
+    @seealso
+    mlanguage_code (), mlanguage_name ().  */
+
+MText *
+mlanguage_text (MSymbol language)
+{
+  MPlist *plist = mlanguage__info (language);
+  MText *mt;
+
+  if (! plist)
+    return NULL;
+  plist = MPLIST_NEXT (plist);
+  if (MPLIST_TAIL_P (plist))
+    return NULL;
+  plist = MPLIST_NEXT (plist);
+  if (MPLIST_TAIL_P (plist))
+    return NULL;
+  plist = MPLIST_NEXT (plist);           
+  if (! MPLIST_MTEXT_P (plist))
+    return NULL;
+  mt = MPLIST_MTEXT (plist);
+  if (mtext_nchars (mt) == 0)
+    return NULL;
+  plist = MPLIST_NEXT (plist);
+  if (MPLIST_MTEXT_P (plist)
+      && ! mtext_get_prop (mt, 0, Mtext))
+    mtext_put_prop (mt, 0, mtext_nchars (mt), Mtext, MPLIST_MTEXT (plist));
+  return mt;
+}
+
+/***en
+    @brief List script names.
+
+    The mscript_list () funciton returns a well-formed plist whose
+    keys are #Msymbol and values are symbols whose names are script
+    names.
+
+    @return
+    This function returns a plist.  The caller should free it by
+    m17n_object_unref ().
+
+    @seealso
+    mscript_language_list (), mlanguage_list ().  */
+
+/***ja
+    @brief ¥¹¥¯¥ê¥×¥È̾¤ò¥ê¥¹¥È¤¹¤ë.
+
+    ´Ø¿ô mscript_list () ¤Ï¡¢À°·Á¼° (well-formed) plist ¤òÊÖ¤¹¡£³Æ¥­¡¼
+    ¤Ï #Msymbol ¤Ç¤¢¤ê¡¢¸Ä¡¹¤ÎÃͤϥ¹¥¯¥ê¥×¥È̾¤ò̾Á°¤È¤¹¤ë¥·¥ó¥Ü¥ë¤Ç¤¢
+    ¤ë¡£
+
+    @return
+    ¤³¤Î´Ø¿ô¤¬ÊÖ¤¹ plist ¤Ï¡¢¸Æ¤Ó½Ð¤·Â¦¤¬ m17n_object_unref () ¤ò»È¤Ã
+    ¤Æ²òÊü¤¹¤ëɬÍפ¬¤¢¤ë¡£
+
+    @seealso
+    mscript_language_list (), mlanguage_list ().  */
+
+MPlist *
+mscript_list (void)
+{
+  MPlist *plist, *pl, *p, *p0;
+
+  if (! script_list
+      && init_script_list () < 0)
+    return NULL;
+  plist = pl = mplist ();
+  MPLIST_DO (p, script_list)
+    {
+      p0 = MPLIST_PLIST (p);
+      pl = mplist_add (pl, Msymbol, MPLIST_VAL (p0));
+    }
+  return plist;
+}
+
+/*=*/
+
+/***en
+    @brief List languages that use a specified script.
+
+    The mscript_language_list () function lists languages that use
+    $SCRIPT.  $SCRIPT is a symbol whose name is the lower-cased
+    version of a script name that appears in the Unicode Character
+    Database.
+
+    @return
+
+    This function returns a well-formed plist whose keys are #Msymbol
+    and values are symbols whose names are ISO639-1 2-letter codes (or
+    ISO639-2 3-letter codes, if the former is not available).  The
+    caller should not modify nor free it.  If the m17n library does
+    not know about $SCRIPT, it returns @ c NULL.
+
+    @seealso
+    mscript_list (), mlanguage_list ().  */
+
+/***ja
+    @brief Í¿¤¨¤é¤ì¤¿¥¹¥¯¥ê¥×¥È¤òÍѤ¤¤ë¸À¸ì¤ò¥ê¥¹¥È¤¹¤ë.
+
+    ´Ø¿ô mscript_language_list () ¤Ï¡¢$SCRIPT ¤òÍѤ¤¤ë¸À¸ì¤ò¥ê¥¹¥È¤¹¤ë¡£
+    $SCRIPT ¤Ï¥·¥ó¥Ü¥ë¤Ç¡¢¤½¤Î̾Á°¤Ï Unicode Character Database ¤Ë¼¨¤µ
+    ¤ì¤Æ¤¤¤ë¥¹¥¯¥ê¥×¥È̾¤ò¤¹¤Ù¤Æ¾®Ê¸»ú¤Ë¤·¤¿¤â¤Î¤Ç¤¢¤ë¡£
+
+    @return 
+    ¤³¤Î´Ø¿ô¤Ï¡¢À°·Á¼° (well-formed) plist ¤òÊÖ¤¹¡£³Æ¥­¡¼¤Ï 
+    #Msymbol ¤Ç¤¢¤ê¡¢¸Ä¡¹¤ÎÃͤϠISO639-1 ¤ËÄê¤á¤é¤ì¤¿2ʸ»ú¸À¸ì¥³¡¼¥É
+    (ÄêµÁ¤µ¤ì¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ï ISO639-2 ¤ËÄê¤á¤é¤ì¤¿3ʸ»ú¸À¸ì¥³¡¼¥É) ¤ò̾
+    Á°¤È¤¹¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£ÊÖ¤µ¤ì¤ë plist ¤ÏÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ
+    ¤Ï¤Ê¤é¤Ê¤¤¡£$SCRIPT ¤¬Ì¤ÃΤξì¹ç¤Ï @c NULL ¤¬ÊÖ¤µ¤ì¤ë¡£
+
+    @seealso
+    mscript_list (), mlanguage_list ().  */
+    
+
+MPlist *
+mscript_language_list (MSymbol script)
+{
+  MPlist *plist = mscript__info (script);
+
+  if (plist                    /* script name */
+      && (plist = MPLIST_NEXT (plist)) /* language list */
+      && MPLIST_PLIST_P (plist))
+    return MPLIST_PLIST (plist);
+  return NULL;
+}
+
+/*** @} */
+/*=*/
+/***en
+    @name Obsolete functions
+*/
+/***ja
+    @name Obsolete ¤Ê´Ø¿ô
+*/
+/*** @{ */
+
+/***en
+    @brief Get an English language name.
+
+    This function is obsolete.  Use mlanguage_name_list () instead.
+
+    The mlanguage_name () function returns a symbol whose name is an
+    English name of $LANGUAGE.  $LANGUAGE is a symbol whose name is an
+    ISO639-2 3-letter language code, an ISO639-1 2-letter language
+    codes, or an English word.
+
+    @return
+    If the information is available, this function returns a non-#Mnil
+    symbol.  Otherwise, it returns #Mnil.
+
+    @seealso
+    mlanguage_code (), mlanguage_text ().  */
+
+/***ja
+    @brief ¸À¸ì¤Î±Ñ¸ì̾¤òÆÀ¤ë.
+
+    ´Ø¿ô mlanguage_name () ¤Ï¡¢$LANGUAGE ¤Î±Ñ¸ì̾¤ò̾Á°¤È¤¹¤ë¤è¤¦¤Ê¥·
+    ¥ó¥Ü¥ë¤òÊÖ¤¹¡£$LANGUAGE ¤Ï¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢¤½¤Î̾Á°¤Ï¡¢ISO639-2 3ʸ
+    »ú¸À¸ì¥³¡¼¥É¡¢ISO639-1 2ʸ»ú¸À¸ì¥³¡¼¥É¡¢±Ñ¸ì̾¡¢¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£
+
+    @return
+    µá¤á¤Æ¤¤¤ë¾ðÊó¤¬ÆÀ¤é¤ì¤ë¤Ê¤é¡¢¤³¤Î´Ø¿ô¤Ï #Mnil °Ê³°¤Î¥·¥ó¥Ü¥ë¤òÊÖ
+    ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð #Mnil ¤òÊÖ¤¹¡£
+
+    @seealso
+    mlanguage_code (), mlanguage_text ().  */
+
+MSymbol
+mlanguage_name (MSymbol language)
+{
+  MPlist *plist = mlanguage__info (language);
+  MText *mt;
+  char *str;
+
+  if (! plist)                 /* 3-letter code */
+    return Mnil;
+  plist = MPLIST_NEXT (plist); /* 2-letter code */
+  if (MPLIST_TAIL_P (plist))
+    return Mnil;
+  plist = MPLIST_NEXT (plist); /* english name */
+  if (! MPLIST_MTEXT_P (plist))
+    return Mnil;
+  mt = MPLIST_MTEXT (plist);
+  str = alloca (mtext_nbytes (mt));
+  memcpy (str, MTEXT_DATA (mt), mtext_nbytes (mt));
+  str[0] = tolower (str[0]);
+  return msymbol__with_len (str, mtext_nbytes (mt));
+}
+
+/*=*/
+
+/*
+  Local Variables:
+  coding: euc-japan
+  End:
+*/