*** empty log message ***
[m17n/m17n-lib.git] / src / language.c
index a9b5912..8eb389b 100644 (file)
@@ -1,5 +1,5 @@
-/* language.c -- language module.
-   Copyright (C) 2003, 2004
+/* language.c -- language (and script) module.
+   Copyright (C) 2003, 2004, 2006
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
@@ -17,7 +17,7 @@
 
    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 "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 *
+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 ...) ...).  */
+  MPLIST_DO (pl, plist)
+    {
+      if (! MPLIST_PLIST_P (pl))
+       break;
+      p = MPLIST_PLIST (pl);
+      if (! MPLIST_SYMBOL_P (p))
+       break;
+    }
+  if (! MPLIST_TAIL_P (pl))
+    {
+      M17N_OBJECT_UNREF (plist);
+      return NULL;
+    }
+  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;
+}
+
 \f
 /* Internal API */
 
 int
 mlang__init ()
 {
-  /* ISO 639 */
-  struct {
-    char *name, *fullname;
-  } lang_rec[] =
-      { {"ab", "Abkhazian"},
-       {"aa", "Afar"},
-       {"af", "Afrikaans"},
-       {"ak", "Akan"},
-       {"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"},
-       {"dv", "Dhivehi"},
-       {"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 = NULL;
   return 0;
 }
 
 void
 mlang__fini (void)
 {
+  M17N_OBJECT_UNREF (language_list);
+  language_list = NULL;
+  M17N_OBJECT_UNREF (script_list);
+  script_list = NULL;
+}
+
+/*=*/
+
+/***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_P (pl) && MPLIST_SYMBOL (pl) == language)
+       return MPLIST_PLIST (plist);
+      if (! MPLIST_TAIL_P (pl))
+       {
+         pl = MPLIST_NEXT (pl);
+         if (MPLIST_SYMBOL_P (pl) && MPLIST_SYMBOL (pl) == language)
+           return MPLIST_PLIST (plist);
+         if (! MPLIST_TAIL_P (pl))
+           {
+             pl = MPLIST_NEXT (pl);
+             if (MPLIST_SYMBOL_P (pl) && MPLIST_SYMBOL (pl) == language)
+               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_SYMBOL_P (p)
+         && otf_tag == MPLIST_SYMBOL (p))
+       {
+         script = MPLIST_SYMBOL (pl);
+         break;
+       }
+    }
+  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\e$BJ8;z8@8l%3!<%I$r%j%9%H$9$k\e(B.
+
+    \e$B4X?t\e(B mlanguage_list () \e$B$O!"@07A<0\e(B (well-formed) plist \e$B$rJV$9!#3F%-!<\e(B
+    \e$B$O\e(B #Msymbol \e$B$G$"$j!"8D!9$NCM$O\e(B ISO639-2 \e$B$KDj$a$i$l$?\e(B3\e$BJ8;z8@8l%3!<\e(B
+    \e$B%I$rL>A0$H$9$k%7%s%\%k$G$"$k!#\e(B
+
+    @return
+    \e$B$3$N4X?t$,JV$9\e(B plist \e$B$O!"8F$S=P$7B&$,\e(B m17n_object_unref () \e$B$r;H$C\e(B
+    \e$B$F2rJ|$9$kI,MW$,$"$k!#\e(B
+
+    @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 (), mlanguage_text ().  */
+
+/***ja
+    @brief \e$B8@8l%3!<%I$rF@$k\e(B.
+
+    \e$B4X?t\e(B mlanguage_code () \e$B$O!"\e(B$LANGUAGE \e$B$KBP1~$7$?\e(B ISO-639 \e$B8@8l%3!<%I\e(B
+    \e$B$,L>A0$G$"$k$h$&$J%7%s%\%k$rJV$9!#\e(B$LANGUAGE \e$B$O%7%s%\%k$G$"$j!"$=$N\e(B
+    \e$BL>A0$O!"\e(BISO639-2 3\e$BJ8;z8@8l%3!<%I!"\e(BISO639-1 2\e$BJ8;z8@8l%3!<%I!"1Q8lL>!"\e(B
+    \e$B$N$$$:$l$+$G$"$k!#\e(B
+
+    $LEN \e$B$OJV$5$l$k8@8l%3!<%I$N<oN`$r7hDj$9$k!#\e(B$LEN \e$B$,\e(B3\e$B$N>l9g$O\e(B 
+    ISO639-2 3\e$BJ8;z8@8l%3!<%I$,JV$5$l$k!#\e(B2\e$B$N>l9g$O!"$b$7Dj5A$5$l$F$$$l\e(B
+    \e$B$P\e(B ISO639-1 2\e$BJ8;z8@8l%3!<%I$,!"$=$&$G$J$1$l$P\e(B #Mnil \e$B$,JV$5$l$k!#\e(B0 
+    \e$B$N>l9g$O!"$b$7Dj5A$5$l$F$$$l$P\e(B2\e$BJ8;z%3!<%I$,!"$=$&$G$J$1$l$P\e(B3\e$BJ8;z%3!<\e(B
+    \e$B%I$,JV$5$l$k!#\e(B
+
+    @return
+    \e$B$b$7>pJs$,F@$i$l$l$P!"$3$N4X?t$O\e(B #Mnil \e$B0J30$N%7%s%\%k$rJV$9!#$=$&\e(B
+    \e$B$G$J$1$l$P\e(B #Mnil \e$B$rJV$9!#\e(B
+
+    @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 Get an English language name.
+
+    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 \e$B8@8l$N1Q8lL>$rF@$k\e(B.
+
+    \e$B4X?t\e(B mlanguage_name () \e$B$O!"\e(B$LANGUAGE \e$B$N1Q8lL>$rL>A0$H$9$k$h$&$J%7\e(B
+    \e$B%s%\%k$rJV$9!#\e(B$LANGUAGE \e$B$O%7%s%\%k$G$"$j!"$=$NL>A0$O!"\e(BISO639-2 3\e$BJ8\e(B
+    \e$B;z8@8l%3!<%I!"\e(BISO639-1 2\e$BJ8;z8@8l%3!<%I!"1Q8lL>!"$N$$$:$l$+$G$"$k!#\e(B
+
+    @return
+    \e$B5a$a$F$$$k>pJs$,F@$i$l$k$J$i!"$3$N4X?t$O\e(B #Mnil \e$B0J30$N%7%s%\%k$rJV\e(B
+    \e$B$9!#$=$&$G$J$1$l$P\e(B #Mnil \e$B$rJV$9!#\e(B
+
+    @seealso
+    mlanguage_code (), mlanguage_text ().  */
+
+MSymbol
+mlanguage_name (MSymbol language)
+{
+  MPlist *plist = mlanguage__info (language);
+
+  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_SYMBOL_P (plist))
+    return Mnil;
+  return MPLIST_SYMBOL (plist);
+}
+
+/*=*/
+
+/***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 \e$BM?$($i$l$?8@8l<+?H$G=q$+$l$?8@8lL>$rJV$9\e(B.
+
+    \e$B4X?t\e(B mlanguage_text () \e$B$O!"8@8l\e(B $LANGUAGE \e$B$G=q$+$l$?\e(B $LANGUAGE \e$B$N\e(B
+    \e$BL>A0$r\e(B M-text \e$B$N7A<0$GJV$9!#$=$N8@8l$NBeI=E*$JJ8;z$,$o$+$C$F$$$k>l\e(B
+    \e$B9g$O!"JV$5$l$k\e(B M-text \e$B$N3FJ8;z$K!"%-!<$,\e(B #Mtext \e$B$GCM$,$=$NBeI=E*$J\e(B
+    \e$BJ8;z$r4^$`\e(B M-text \e$B$G$"$k$h$&$J%F%-%9%H%W%m%Q%F%#$,IU2C$5$l$k!#\e(B
+
+    @return
+    \e$B5a$a$k>pJs$,F@$i$l$?>l9g!"$3$N4X?t$,JV$9\e(B M-text \e$B$rJQ99$7$?$j2rJ|$7\e(B
+    \e$B$?$j$7$F$O$$$1$J$$!#>pJs$,F@$i$l$J$+$C$?>l9g$O\e(B @c NULL \e$B$,JV$5$l$k!#\e(B
+
+    @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 \e$B%9%/%j%W%HL>$r%j%9%H$9$k\e(B.
+
+    \e$B4X?t\e(B mscript_list () \e$B$O!"@07A<0\e(B (well-formed) plist \e$B$rJV$9!#3F%-!<\e(B
+    \e$B$O\e(B #Msymbol \e$B$G$"$j!"8D!9$NCM$O%9%/%j%W%HL>$rL>A0$H$9$k%7%s%\%k$G$"\e(B
+    \e$B$k!#\e(B
+
+    @return
+    \e$B$3$N4X?t$,JV$9\e(B plist \e$B$O!"8F$S=P$7B&$,\e(B m17n_object_unref () \e$B$r;H$C\e(B
+    \e$B$F2rJ|$9$kI,MW$,$"$k!#\e(B
+
+    @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 \e$BM?$($i$l$?%9%/%j%W%H$rMQ$$$k8@8l$r%j%9%H$9$k\e(B.
+
+    \e$B4X?t\e(B mscript_language_list () \e$B$O!"\e(B$SCRIPT \e$B$rMQ$$$k8@8l$r%j%9%H$9$k!#\e(B
+    $SCRIPT \e$B$O%7%s%\%k$G!"$=$NL>A0$O\e(B Unicode Character Database \e$B$K<($5\e(B
+    \e$B$l$F$$$k%9%/%j%W%HL>$r$9$Y$F>.J8;z$K$7$?$b$N$G$"$k!#\e(B
+
+    @return \e$B$3$N4X?t$O!"@07A<0\e(B (well-formed) plist \e$B$rJV$9!#3F%-!<$O\e(B 
+    #Msymbol \e$B$G$"$j!"8D!9$NCM$O\e(B ISO639-1 \e$B$KDj$a$i$l$?\e(B2\e$BJ8;z8@8l%3!<%I\e(B
+    (\e$BDj5A$5$l$F$$$J$$>l9g$O\e(B ISO639-2 \e$B$KDj$a$i$l$?\e(B3\e$BJ8;z8@8l%3!<%I\e(B) \e$B$rL>\e(B
+    \e$BA0$H$9$k%7%s%\%k$G$"$k!#JV$5$l$k\e(B plist \e$B$OJQ99$7$?$j2rJ|$7$?$j$7$F\e(B
+    \e$B$O$J$i$J$$!#\e(B$SCRIPT \e$B$,L$CN$N>l9g$O\e(B @c NULL \e$B$,JV$5$l$k!#\e(B
+
+    @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;
+}