(parse_otf_command): Fix previous change.
[m17n/m17n-lib.git] / src / language.c
index 359d0bd..b31eeeb 100644 (file)
@@ -1,5 +1,5 @@
 /* language.c -- language (and script) module.
-   Copyright (C) 2003, 2004, 2006
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
@@ -23,6 +23,7 @@
 #include <config.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <locale.h>
 #include "m17n.h"
 #include "m17n-misc.h"
@@ -91,6 +92,57 @@ init_script_list (void)
   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 */
 
@@ -111,13 +163,8 @@ mlang__init ()
 void
 mlang__fini (void)
 {
-  MPlist *pl;
-
   M17N_OBJECT_UNREF (language_list);
   M17N_OBJECT_UNREF (script_list);
-  if (langname_list)
-    MPLIST_DO (pl, langname_list)
-      M17N_OBJECT_UNREF (MPLIST_VAL (pl));
   M17N_OBJECT_UNREF (langname_list);
 }
 
@@ -185,9 +232,9 @@ mlanguage__info (MSymbol language)
          MText *mt = MPLIST_MTEXT (pl);
 
          if (mtext_nbytes (mt) == MSYMBOL_NAMELEN (language)
-             && memcmp (MTEXT_DATA (MPLIST_MTEXT (pl)),
-                        MSYMBOL_NAME (language),
-                        MSYMBOL_NAMELEN (language)) == 0)
+             && strncasecmp ((char *) MTEXT_DATA (MPLIST_MTEXT (pl)),
+                             MSYMBOL_NAME (language),
+                             MSYMBOL_NAMELEN (language)) == 0)
            return MPLIST_PLIST (plist);
        }
     }
@@ -270,11 +317,21 @@ mscript__from_otf_tag (MSymbol otf_tag)
          && (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))
+         && ! MPLIST_TAIL_P (p))
        {
-         script = MPLIST_SYMBOL (pl);
-         break;
+         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;
@@ -403,78 +460,153 @@ mlanguage_code (MSymbol language, int len)
     @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.
+    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 information is available, this function returns a non-empty
-    plist whose keys are #Mtext and values are M-texts of the
-    translated language names.  Otherwise, @c NULL is returned.
+    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)
+mlanguage_name_list (MSymbol language, MSymbol target,
+                    MSymbol script, MSymbol territory)
 {
-  MPlist *plist;
+  MPlist *plist, *pl;
+  MSymbol language2, target2;
 
   plist = mlanguage__info (language);
   if (! plist)
     return NULL;
-  language = mplist_value (plist);
+  language = MPLIST_SYMBOL (plist);
+  language2 = MPLIST_SYMBOL (MPLIST_NEXT (plist));
   if (target != Mnil)
     {
       plist = mlanguage__info (target);
       if (! plist)
        return NULL;
-      target = mplist_value (plist);
+      target = MPLIST_SYMBOL (plist);
+      target2 = MPLIST_SYMBOL (MPLIST_NEXT (plist));
     }
   else
     {
       MLocale *locale = mlocale_set (LC_MESSAGES, NULL);
 
       if (! locale)
-       target = msymbol ("eng");
+       {
+         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_value (plist);
+         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)
-    plist = mplist_get (langname_list, target);
+  /* 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
-    langname_list = mplist (), plist = NULL;
-  if (! plist)
+    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))
     {
-      MDatabase *mdb = mdatabase_find (Mlanguage, Mname, target, Mnil);
+      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;
+       }
+    }
 
-      if (! mdb
-         || ! (plist = mdatabase_load (mdb)))
-       plist = mplist ();
-      else
-       mplist__pop_unref (plist);
-      langname_list = mplist_push (langname_list, target, plist);
-      MPLIST_SET_NESTED_P (langname_list);
+  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;
     }
-  /* PLIST == ((LANGUAGE TRANSLATED) ...) */
-  plist = mplist__assq (plist, language);
-  if (! plist || MPLIST_TAIL_P (plist))
-    return NULL;
-  plist = MPLIST_PLIST (plist);
-  plist = MPLIST_NEXT (plist);
-  return plist;
+  MPLIST_DO (plist, plist)
+    if (MPLIST_MTEXT_P (plist))
+      break;
+  return (MPLIST_MTEXT_P (plist) ? plist : NULL);
 }
 
 /*=*/
@@ -612,7 +744,8 @@ mscript_list (void)
     $SCRIPT ¤Ï¥·¥ó¥Ü¥ë¤Ç¡¢¤½¤Î̾Á°¤Ï Unicode Character Database ¤Ë¼¨¤µ
     ¤ì¤Æ¤¤¤ë¥¹¥¯¥ê¥×¥È̾¤ò¤¹¤Ù¤Æ¾®Ê¸»ú¤Ë¤·¤¿¤â¤Î¤Ç¤¢¤ë¡£
 
-    @return ¤³¤Î´Ø¿ô¤Ï¡¢À°·Á¼° (well-formed) plist ¤òÊÖ¤¹¡£³Æ¥­¡¼¤Ï 
+    @return 
+    ¤³¤Î´Ø¿ô¤Ï¡¢À°·Á¼° (well-formed) plist ¤òÊÖ¤¹¡£³Æ¥­¡¼¤Ï 
     #Msymbol ¤Ç¤¢¤ê¡¢¸Ä¡¹¤ÎÃͤϠISO639-1 ¤ËÄê¤á¤é¤ì¤¿2ʸ»ú¸À¸ì¥³¡¼¥É
     (ÄêµÁ¤µ¤ì¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ï ISO639-2 ¤ËÄê¤á¤é¤ì¤¿3ʸ»ú¸À¸ì¥³¡¼¥É) ¤ò̾
     Á°¤È¤¹¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£ÊÖ¤µ¤ì¤ë plist ¤ÏÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ
@@ -680,6 +813,7 @@ mlanguage_name (MSymbol language)
 {
   MPlist *plist = mlanguage__info (language);
   MText *mt;
+  char *str;
 
   if (! plist)                 /* 3-letter code */
     return Mnil;
@@ -687,15 +821,13 @@ mlanguage_name (MSymbol language)
   if (MPLIST_TAIL_P (plist))
     return Mnil;
   plist = MPLIST_NEXT (plist); /* english name */
-  if (MPLIST_MTEXT_P (plist))
+  if (! MPLIST_MTEXT_P (plist))
     return Mnil;
   mt = MPLIST_MTEXT (plist);
-  if (mtext_nbytes (mt) != MSYMBOL_NAMELEN (language)
-      || memcmp (MTEXT_DATA (MPLIST_MTEXT (plist)),
-                MSYMBOL_NAME (language),
-                MSYMBOL_NAMELEN (language)))
-    return Mnil;
-  return language;
+  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));
 }
 
 /*=*/