Git init
[external/pango1.0.git] / pango / pango-language.c
1 /* Pango
2  * pango-language.c: Language handling routines
3  *
4  * Copyright (C) 2000 Red Hat Software
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23 #include <errno.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include <locale.h>
28
29 #include "pango-language.h"
30 #include "pango-impl-utils.h"
31
32
33 /* We embed a private struct right *before* a where a PangoLanguage *
34  * points to.
35  */
36
37 typedef struct {
38   gconstpointer lang_info;
39   gconstpointer script_for_lang;
40
41   int magic; /* Used for verification */
42 } PangoLanguagePrivate;
43
44 #define PANGO_LANGUAGE_PRIVATE_MAGIC 0x0BE4DAD0
45
46 static void
47 pango_language_private_init (PangoLanguagePrivate *priv)
48 {
49   priv->magic = PANGO_LANGUAGE_PRIVATE_MAGIC;
50
51   priv->lang_info = (gconstpointer) -1;
52   priv->script_for_lang = (gconstpointer) -1;
53 }
54
55 static PangoLanguagePrivate * pango_language_get_private (PangoLanguage *language) G_GNUC_CONST;
56
57 static PangoLanguagePrivate *
58 pango_language_get_private (PangoLanguage *language)
59 {
60   PangoLanguagePrivate *priv;
61
62   if (!language)
63     return NULL;
64
65   priv = (PangoLanguagePrivate *) ((char *)language - sizeof (PangoLanguagePrivate));
66
67   if (G_UNLIKELY (priv->magic != PANGO_LANGUAGE_PRIVATE_MAGIC))
68     {
69       g_critical ("Invalid PangoLanguage.  Did you pass in a straight string instead of calling pango_language_from_string()?");
70       return NULL;
71     }
72
73   return priv;
74 }
75
76
77
78 #define LANGUAGE_SEPARATORS ";:, \t"
79
80 static const char canon_map[256] = {
81    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
82    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
83    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,  '-',  0,   0,
84   '0', '1', '2', '3', '4', '5', '6', '7',  '8', '9',  0,   0,   0,   0,   0,   0,
85   '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
86   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,  '-',
87    0,  'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
88   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,   0
89 };
90
91 static gboolean
92 lang_equal (gconstpointer v1,
93             gconstpointer v2)
94 {
95   const guchar *p1 = v1;
96   const guchar *p2 = v2;
97
98   while (canon_map[*p1] && canon_map[*p1] == canon_map[*p2])
99     {
100       p1++, p2++;
101     }
102
103   return (canon_map[*p1] == canon_map[*p2]);
104 }
105
106 static guint
107 lang_hash (gconstpointer key)
108 {
109   const guchar *p = key;
110   guint h = 0;
111   while (canon_map[*p])
112     {
113       h = (h << 5) - h + canon_map[*p];
114       p++;
115     }
116
117   return h;
118 }
119
120 static PangoLanguage *
121 pango_language_copy (PangoLanguage *language)
122 {
123   return language; /* language tags are const */
124 }
125
126 static void
127 pango_language_free (PangoLanguage *language G_GNUC_UNUSED)
128 {
129   return; /* nothing */
130 }
131
132 GType
133 pango_language_get_type (void)
134 {
135   static GType our_type = 0;
136
137   if (G_UNLIKELY (our_type == 0))
138     our_type = g_boxed_type_register_static (I_("PangoLanguage"),
139                                              (GBoxedCopyFunc)pango_language_copy,
140                                              (GBoxedFreeFunc)pango_language_free);
141   return our_type;
142 }
143
144 /**
145  * _pango_get_lc_ctype:
146  *
147  * Return the Unix-style locale string for the language currently in
148  * effect. On Unix systems, this is the return value from
149  * <literal>setlocale(LC_CTYPE, NULL)</literal>, and the user can
150  * affect this through the environment variables LC_ALL, LC_CTYPE or
151  * LANG (checked in that order). The locale strings typically is in
152  * the form lang_COUNTRY, where lang is an ISO-639 language code, and
153  * COUNTRY is an ISO-3166 country code. For instance, sv_FI for
154  * Swedish as written in Finland or pt_BR for Portuguese as written in
155  * Brazil.
156  *
157  * On Windows, the C library doesn't use any such environment
158  * variables, and setting them won't affect the behavior of functions
159  * like ctime(). The user sets the locale through the Regional Options
160  * in the Control Panel. The C library (in the setlocale() function)
161  * does not use country and language codes, but country and language
162  * names spelled out in English.
163  * However, this function does check the above environment
164  * variables, and does return a Unix-style locale string based on
165  * either said environment variables or the thread's current locale.
166  *
167  * Return value: a dynamically allocated string, free with g_free().
168  */
169 static gchar *
170 _pango_get_lc_ctype (void)
171 {
172 #ifdef G_OS_WIN32
173   /* Somebody might try to set the locale for this process using the
174    * LANG or LC_ environment variables. The Microsoft C library
175    * doesn't know anything about them. You set the locale in the
176    * Control Panel. Setting these env vars won't have any affect on
177    * locale-dependent C library functions like ctime(). But just for
178    * kicks, do obey LC_ALL, LC_CTYPE and LANG in Pango. (This also makes
179    * it easier to test GTK and Pango in various default languages, you
180    * don't have to clickety-click in the Control Panel, you can simply
181    * start the program with LC_ALL=something on the command line.)
182    */
183
184   gchar *p;
185
186   p = getenv ("LC_ALL");
187   if (p != NULL)
188     return g_strdup (p);
189
190   p = getenv ("LC_CTYPE");
191   if (p != NULL)
192     return g_strdup (p);
193
194   p = getenv ("LANG");
195   if (p != NULL)
196     return g_strdup (p);
197
198   return g_win32_getlocale ();
199 #else
200   return g_strdup (setlocale (LC_CTYPE, NULL));
201 #endif
202 }
203
204 /**
205  * pango_language_get_default:
206  *
207  * Returns the #PangoLanguage for the current locale of the process.
208  * Note that this can change over the life of an application.
209  *
210  * On Unix systems, this is the return value is derived from
211  * <literal>setlocale(LC_CTYPE, NULL)</literal>, and the user can
212  * affect this through the environment variables LC_ALL, LC_CTYPE or
213  * LANG (checked in that order). The locale string typically is in
214  * the form lang_COUNTRY, where lang is an ISO-639 language code, and
215  * COUNTRY is an ISO-3166 country code. For instance, sv_FI for
216  * Swedish as written in Finland or pt_BR for Portuguese as written in
217  * Brazil.
218  *
219  * On Windows, the C library does not use any such environment
220  * variables, and setting them won't affect the behavior of functions
221  * like ctime(). The user sets the locale through the Regional Options
222  * in the Control Panel. The C library (in the setlocale() function)
223  * does not use country and language codes, but country and language
224  * names spelled out in English.
225  * However, this function does check the above environment
226  * variables, and does return a Unix-style locale string based on
227  * either said environment variables or the thread's current locale.
228  *
229  * Your application should call <literal>setlocale(LC_ALL, "");</literal>
230  * for the user settings to take effect.  Gtk+ does this in its initialization
231  * functions automatically (by calling gtk_set_locale()).
232  * See <literal>man setlocale</literal> for more details.
233  *
234  * Return value: the default language as a #PangoLanguage, must not be
235  *               freed.
236  *
237  * Since: 1.16
238  **/
239 PangoLanguage *
240 pango_language_get_default (void)
241 {
242   static PangoLanguage *result = NULL;
243
244   if (G_UNLIKELY (!result))
245     {
246       gchar *lang = _pango_get_lc_ctype ();
247       result = pango_language_from_string (lang);
248       g_free (lang);
249     }
250
251   return result;
252 }
253
254 /**
255  * pango_language_from_string:
256  * @language: a string representing a language tag, or %NULL
257  *
258  * Take a RFC-3066 format language tag as a string and convert it to a
259  * #PangoLanguage pointer that can be efficiently copied (copy the
260  * pointer) and compared with other language tags (compare the
261  * pointer.)
262  *
263  * This function first canonicalizes the string by converting it to
264  * lowercase, mapping '_' to '-', and stripping all characters other
265  * than letters and '-'.
266  *
267  * Use pango_language_get_default() if you want to get the #PangoLanguage for
268  * the current locale of the process.
269  *
270  * Return value: an opaque pointer to a #PangoLanguage structure, or %NULL
271  *               if @language was %NULL.  The returned pointer will be valid
272  *               forever after, and should not be freed.
273  **/
274 PangoLanguage *
275 pango_language_from_string (const char *language)
276 {
277   static GHashTable *hash = NULL;
278   PangoLanguagePrivate *priv;
279   char *result;
280   int len;
281   char *p;
282
283   if (language == NULL)
284     return NULL;
285
286   if (G_UNLIKELY (!hash))
287     hash = g_hash_table_new (lang_hash, lang_equal);
288   else
289     {
290       result = g_hash_table_lookup (hash, language);
291       if (result)
292         return (PangoLanguage *)result;
293     }
294
295   len = strlen (language);
296   result = g_malloc0 (sizeof (PangoLanguagePrivate) + len + 1);
297   g_assert (result);
298
299   priv = (PangoLanguagePrivate *) result;
300   result += sizeof (*priv);
301
302   pango_language_private_init (priv);
303
304   p = result;
305   while ((*(p++) = canon_map[*(guchar *)language++]))
306     ;
307
308   g_hash_table_insert (hash, result, result);
309
310   return (PangoLanguage *)result;
311 }
312
313 /**
314  * pango_language_to_string:
315  * @language: a language tag.
316  *
317  * Gets the RFC-3066 format string representing the given language tag. 
318  *
319  * Returns: a string representing the language tag.  This is owned by
320  *          Pango and should not be freed.
321  */
322 G_CONST_RETURN char *
323 (pango_language_to_string) (PangoLanguage *language)
324 {
325   return pango_language_to_string (language);
326 }
327
328 /**
329  * pango_language_matches:
330  * @language: a language tag (see pango_language_from_string()),
331  *            %NULL is allowed and matches nothing but '*'
332  * @range_list: a list of language ranges, separated by ';', ':',
333  *   ',', or space characters.
334  *   Each element must either be '*', or a RFC 3066 language range
335  *   canonicalized as by pango_language_from_string()
336  *
337  * Checks if a language tag matches one of the elements in a list of
338  * language ranges. A language tag is considered to match a range
339  * in the list if the range is '*', the range is exactly the tag,
340  * or the range is a prefix of the tag, and the character after it
341  * in the tag is '-'.
342  *
343  * Return value: %TRUE if a match was found.
344  **/
345 gboolean
346 pango_language_matches (PangoLanguage *language,
347                         const char    *range_list)
348 {
349   const char *lang_str = pango_language_to_string (language);
350   const char *p = range_list;
351   gboolean done = FALSE;
352
353   while (!done)
354     {
355       const char *end = strpbrk (p, LANGUAGE_SEPARATORS);
356       if (!end)
357         {
358           end = p + strlen (p);
359           done = TRUE;
360         }
361
362       if (strncmp (p, "*", 1) == 0 ||
363           (lang_str && strncmp (lang_str, p, end - p) == 0 &&
364            (lang_str[end - p] == '\0' || lang_str[end - p] == '-')))
365         return TRUE;
366
367       if (!done)
368         p = end + 1;
369     }
370
371   return FALSE;
372 }
373
374 static int
375 lang_compare_first_component (gconstpointer pa,
376                               gconstpointer pb)
377 {
378   const char *a = pa, *b = pb;
379   unsigned int da, db;
380   const char *p;
381
382   p = strstr (a, "-");
383   da = p ? (unsigned int) (p - a) : strlen (a);
384
385   p = strstr (b, "-");
386   db = p ? (unsigned int) (p - b) : strlen (b);
387    
388   return strncmp (a, b, MAX (da, db));
389 }
390
391 /* Finds the best record for @language in an array of records.
392  * Each record should start with the string representation of the language
393  * code for the record (embedded, not a pointer), and the records must be
394  * sorted on language code.
395  */
396 static gconstpointer
397 find_best_lang_match (PangoLanguage *language,
398                       gconstpointer  records,
399                       guint          num_records,
400                       guint          record_size)
401 {
402   const char *lang_str;
403   const char *record, *start, *end;
404
405   if (language == NULL)
406     return NULL;
407
408   lang_str = pango_language_to_string (language);
409
410   record = bsearch (lang_str,
411                     records, num_records, record_size,
412                     lang_compare_first_component);
413   if (!record)
414     return NULL;
415
416   start = (const char *) records;
417   end   = start + num_records * record_size;
418
419   /* find the best match among all those that have the same first-component */
420
421   /* go to the final one matching in the first component */
422   while (record < end - record_size &&
423          lang_compare_first_component (lang_str, record + record_size) == 0)
424     record += record_size;
425
426   /* go back, find which one matches completely */
427   while (start <= record &&
428          lang_compare_first_component (lang_str, record) == 0)
429     {
430       if (pango_language_matches (language, record))
431         return record;
432
433       record -= record_size;
434     }
435
436   return NULL;
437 }
438
439 static gconstpointer
440 find_best_lang_match_cached (PangoLanguage *language,
441                              gconstpointer *cache,
442                              gconstpointer  records,
443                              guint          num_records,
444                              guint          record_size)
445 {
446   gconstpointer result;
447
448   if (G_LIKELY (cache && *cache != (gconstpointer) -1))
449     return *cache;
450
451   result = find_best_lang_match (language,
452                                  records,
453                                  num_records,
454                                  record_size);
455
456   if (cache)
457     *cache = result;
458
459   return result;
460 }
461
462 #define FIND_BEST_LANG_MATCH(language, records) \
463         find_best_lang_match ((language), \
464                               records, \
465                               G_N_ELEMENTS (records), \
466                               sizeof (*records));
467
468 #define FIND_BEST_LANG_MATCH_CACHED(language, cache_key, records) \
469         find_best_lang_match_cached ((language), \
470                                      pango_language_get_private (language) ? \
471                                        &(pango_language_get_private (language)->cache_key) : NULL, \
472                                      records, \
473                                      G_N_ELEMENTS (records), \
474                                      sizeof (*records));
475
476 typedef struct {
477   char lang[6];
478   guint16 offset;
479 } LangInfo;
480
481 /* Pure black magic, based on appendix of dsohowto.pdf */
482 #define POOLSTRFIELD(line) POOLSTRFIELD1(line)
483 #define POOLSTRFIELD1(line) str##line
484 struct _LangPoolStruct {
485   char str0[1];
486 #define LANGUAGE(id, source, sample) char POOLSTRFIELD(__LINE__)[sizeof(sample)];
487 #include "pango-language-sample-table.h"
488 #undef LANGUAGE
489 };
490
491 static const union _LangPool {
492   struct _LangPoolStruct lang_pool_struct;
493   const char str[1];
494 } lang_pool = { {
495     "",
496 #define LANGUAGE(id, source, sample) sample,
497 #include "pango-language-sample-table.h"
498 #undef LANGUAGE
499 } };
500 static const LangInfo lang_texts[] = {
501 #define LANGUAGE(id, source, sample) {G_STRINGIFY(id),  G_STRUCT_OFFSET(struct _LangPoolStruct, POOLSTRFIELD(__LINE__))},
502 #include "pango-language-sample-table.h"
503 #undef LANGUAGE
504   /* One extra entry with no final comma, to make it C89-happy */
505  {"~~", 0}
506 };
507
508 /**
509  * pango_language_get_sample_string:
510  * @language: a #PangoLanguage, or %NULL
511  *
512  * Get a string that is representative of the characters needed to
513  * render a particular language.
514  *
515  * The sample text may be a pangram, but is not necessarily.  It is chosen to
516  * be demonstrative of normal text in the language, as well as exposing font
517  * feature requirements unique to the language.  It is suitable for use
518  * as sample text in a font selection dialog.
519  *
520  * If @language is %NULL, the default language as found by
521  * pango_language_get_default() is used.
522  *
523  * If Pango does not have a sample string for @language, the classic
524  * "The quick brown fox..." is returned.  This can be detected by
525  * comparing the returned pointer value to that returned for (non-existent)
526  * language code "xx".  That is, compare to:
527  * <informalexample><programlisting>
528  * pango_language_get_sample_string (pango_language_from_string ("xx"))
529  * </programlisting></informalexample>
530  *
531  * Return value: the sample string. This value is owned by Pango
532  *   and should not be freed.
533  **/
534 G_CONST_RETURN char *
535 pango_language_get_sample_string (PangoLanguage *language)
536 {
537   const LangInfo *lang_info;
538
539   if (!language)
540     language = pango_language_get_default ();
541
542   lang_info = FIND_BEST_LANG_MATCH_CACHED (language,
543                                            lang_info,
544                                            lang_texts);
545
546   if (lang_info)
547     return lang_pool.str + lang_info->offset;
548
549   return "The quick brown fox jumps over the lazy dog.";
550 }
551
552
553
554
555 /*
556  * From language to script
557  */
558
559
560 #include "pango-script-lang-table.h"
561
562 /**
563  * pango_language_get_scripts:
564  * @language: a #PangoLanguage, or %NULL
565  * @num_scripts: location to return number of scripts, or %NULL
566  *
567  * Determines the scripts used to to write @language.
568  * If nothing is known about the language tag @language,
569  * or if @language is %NULL, then %NULL is returned.
570  * The list of scripts returned starts with the script that the
571  * language uses most and continues to the one it uses least.
572  *
573  * The value @num_script points at will be set to the number
574  * of scripts in the returned array (or zero if %NULL is returned).
575  *
576  * Most languages use only one script for writing, but there are
577  * some that use two (Latin and Cyrillic for example), and a few
578  * use three (Japanese for example).  Applications should not make
579  * any assumptions on the maximum number of scripts returned
580  * though, except that it is positive if the return value is not
581  * %NULL, and it is a small number.
582  *
583  * The pango_language_includes_script() function uses this function
584  * internally.
585  *
586  * Return value: An array of #PangoScript values, with the
587  * number of entries in the array stored in @num_scripts, or
588  * %NULL if Pango does not have any information about this
589  * particular language tag (also the case if @language is %NULL).
590  * The returned array is owned by Pango and should not be modified
591  * or freed.
592  
593  * Since: 1.22
594  **/
595 G_CONST_RETURN PangoScript *
596 pango_language_get_scripts (PangoLanguage *language,
597                             int           *num_scripts)
598 {
599   const PangoScriptForLang *script_for_lang;
600   unsigned int j;
601
602   script_for_lang = FIND_BEST_LANG_MATCH_CACHED (language,
603                                                  script_for_lang,
604                                                  pango_script_for_lang);
605
606   if (!script_for_lang)
607     {
608       if (num_scripts)
609         *num_scripts = 0;
610
611       return NULL;
612     }
613
614   if (num_scripts)
615     {
616       for (j = 0; j < G_N_ELEMENTS (script_for_lang->scripts); j++)
617         if (script_for_lang->scripts[j] == 0)
618           break;
619
620       g_assert (j > 0);
621
622       *num_scripts = j;
623     }
624
625   return script_for_lang->scripts;
626 }
627
628 /**
629  * pango_language_includes_script:
630  * @language: a #PangoLanguage, or %NULL
631  * @script: a #PangoScript
632  *
633  * Determines if @script is one of the scripts used to
634  * write @language. The returned value is conservative;
635  * if nothing is known about the language tag @language,
636  * %TRUE will be returned, since, as far as Pango knows,
637  * @script might be used to write @language.
638  *
639  * This routine is used in Pango's itemization process when
640  * determining if a supplied language tag is relevant to
641  * a particular section of text. It probably is not useful for
642  * applications in most circumstances.
643  *
644  * This function uses pango_language_get_scripts() internally.
645  *
646  * Return value: %TRUE if @script is one of the scripts used
647  * to write @language or if nothing is known about @language
648  * (including the case that @language is %NULL),
649  * %FALSE otherwise.
650  
651  * Since: 1.4
652  **/
653 gboolean
654 pango_language_includes_script (PangoLanguage *language,
655                                 PangoScript    script)
656 {
657   const PangoScript *scripts;
658   int num_scripts, j;
659
660 /* copied from the one in pango-script.c */
661 #define REAL_SCRIPT(script) \
662   ((script) > PANGO_SCRIPT_INHERITED && (script) != PANGO_SCRIPT_UNKNOWN)
663
664   if (!REAL_SCRIPT (script))
665     return TRUE;
666
667 #undef REAL_SCRIPT
668
669   scripts = pango_language_get_scripts (language, &num_scripts);
670   if (!scripts)
671     return TRUE;
672
673   for (j = 0; j < num_scripts; j++)
674     if (scripts[j] == script)
675       return TRUE;
676
677   return FALSE;
678 }
679
680
681
682
683 /*
684  * From script to language
685  */
686
687
688 static PangoLanguage **
689 parse_default_languages (void)
690 {
691   char *p, *p_copy;
692   gboolean done = FALSE;
693   GArray *langs;
694
695   p = getenv ("PANGO_LANGUAGE");
696
697   if (p == NULL)
698     p = getenv ("LANGUAGE");
699
700   if (p == NULL)
701     return NULL;
702
703   p_copy = p = g_strdup (p);
704
705   langs = g_array_new (TRUE, FALSE, sizeof (PangoLanguage *));
706
707   while (!done)
708     {
709       char *end = strpbrk (p, LANGUAGE_SEPARATORS);
710       if (!end)
711         {
712           end = p + strlen (p);
713           done = TRUE;
714         }
715       else
716         *end = '\0';
717
718       /* skip empty languages, and skip the language 'C' */
719       if (p != end && !(p + 1 == end && *p == 'C'))
720         {
721           PangoLanguage *l = pango_language_from_string (p);
722           
723           g_array_append_val (langs, l);
724         }
725
726       if (!done)
727         p = end + 1;
728     }
729
730   g_free (p_copy);
731
732   return (PangoLanguage **) g_array_free (langs, FALSE);
733 }
734
735 static PangoLanguage *
736 _pango_script_get_default_language (PangoScript script)
737 {
738   static gboolean initialized = FALSE;
739   static PangoLanguage * const * languages = NULL;
740   static GHashTable *hash = NULL;
741   PangoLanguage *result, * const * p;
742
743   if (G_UNLIKELY (!initialized))
744     {
745       languages = parse_default_languages ();
746
747       if (languages)
748         hash = g_hash_table_new (NULL, NULL);
749
750       initialized = TRUE;
751     }
752
753   if (!languages)
754     return NULL;
755
756   if (g_hash_table_lookup_extended (hash, GINT_TO_POINTER (script), NULL, (gpointer *) (gpointer) &result))
757     return result;
758
759   for (p = languages; *p; p++)
760     if (pango_language_includes_script (*p, script))
761       break;
762   result = *p;
763
764   g_hash_table_insert (hash, GINT_TO_POINTER (script), result);
765
766   return result;
767 }
768
769 /**
770  * pango_script_get_sample_language:
771  * @script: a #PangoScript
772  *
773  * Given a script, finds a language tag that is reasonably
774  * representative of that script. This will usually be the
775  * most widely spoken or used language written in that script:
776  * for instance, the sample language for %PANGO_SCRIPT_CYRILLIC
777  * is <literal>ru</literal> (Russian), the sample language
778  * for %PANGO_SCRIPT_ARABIC is <literal>ar</literal>.
779  *
780  * For some
781  * scripts, no sample language will be returned because there
782  * is no language that is sufficiently representative. The best
783  * example of this is %PANGO_SCRIPT_HAN, where various different
784  * variants of written Chinese, Japanese, and Korean all use
785  * significantly different sets of Han characters and forms
786  * of shared characters. No sample language can be provided
787  * for many historical scripts as well.
788  *
789  * As of 1.18, this function checks the environment variables
790  * PANGO_LANGUAGE and LANGUAGE (checked in that order) first.
791  * If one of them is set, it is parsed as a list of language tags
792  * separated by colons or other separators.  This function
793  * will return the first language in the parsed list that Pango
794  * believes may use @script for writing.  This last predicate
795  * is tested using pango_language_includes_script().  This can
796  * be used to control Pango's font selection for non-primary
797  * languages.  For example, a PANGO_LANGUAGE enviroment variable
798  * set to "en:fa" makes Pango choose fonts suitable for Persian (fa) 
799  * instead of Arabic (ar) when a segment of Arabic text is found
800  * in an otherwise non-Arabic text.  The same trick can be used to
801  * choose a default language for %PANGO_SCRIPT_HAN when setting
802  * context language is not feasible.
803  *
804  * Return value: a #PangoLanguage that is representative
805  * of the script, or %NULL if no such language exists.
806  *
807  * Since: 1.4
808  **/
809 PangoLanguage *
810 pango_script_get_sample_language (PangoScript script)
811 {
812   /* Note that in the following, we want
813    * pango_language_includes_script() for the sample language
814    * to include the script, so alternate orthographies
815    * (Shavian for English, Osmanya for Somali, etc), typically
816    * have no sample language
817    */
818   static const char sample_languages[][4] = {
819     "",    /* PANGO_SCRIPT_COMMON */
820     "",    /* PANGO_SCRIPT_INHERITED */
821     "ar",  /* PANGO_SCRIPT_ARABIC */
822     "hy",  /* PANGO_SCRIPT_ARMENIAN */
823     "bn",  /* PANGO_SCRIPT_BENGALI */
824     /* Used primarily in Taiwan, but not part of the standard
825      * zh-tw orthography  */
826     "",    /* PANGO_SCRIPT_BOPOMOFO */
827     "chr", /* PANGO_SCRIPT_CHEROKEE */
828     "cop", /* PANGO_SCRIPT_COPTIC */
829     "ru",  /* PANGO_SCRIPT_CYRILLIC */
830     /* Deseret was used to write English */
831     "",    /* PANGO_SCRIPT_DESERET */
832     "hi",  /* PANGO_SCRIPT_DEVANAGARI */
833     "am",  /* PANGO_SCRIPT_ETHIOPIC */
834     "ka",  /* PANGO_SCRIPT_GEORGIAN */
835     "",    /* PANGO_SCRIPT_GOTHIC */
836     "el",  /* PANGO_SCRIPT_GREEK */
837     "gu",  /* PANGO_SCRIPT_GUJARATI */
838     "pa",  /* PANGO_SCRIPT_GURMUKHI */
839     "",    /* PANGO_SCRIPT_HAN */
840     "ko",  /* PANGO_SCRIPT_HANGUL */
841     "he",  /* PANGO_SCRIPT_HEBREW */
842     "ja",  /* PANGO_SCRIPT_HIRAGANA */
843     "kn",  /* PANGO_SCRIPT_KANNADA */
844     "ja",  /* PANGO_SCRIPT_KATAKANA */
845     "km",  /* PANGO_SCRIPT_KHMER */
846     "lo",  /* PANGO_SCRIPT_LAO */
847     "en",  /* PANGO_SCRIPT_LATIN */
848     "ml",  /* PANGO_SCRIPT_MALAYALAM */
849     "mn",  /* PANGO_SCRIPT_MONGOLIAN */
850     "my",  /* PANGO_SCRIPT_MYANMAR */
851     /* Ogham was used to write old Irish */
852     "",    /* PANGO_SCRIPT_OGHAM */
853     "",    /* PANGO_SCRIPT_OLD_ITALIC */
854     "or",  /* PANGO_SCRIPT_ORIYA */
855     "",    /* PANGO_SCRIPT_RUNIC */
856     "si",  /* PANGO_SCRIPT_SINHALA */
857     "syr", /* PANGO_SCRIPT_SYRIAC */
858     "ta",  /* PANGO_SCRIPT_TAMIL */
859     "te",  /* PANGO_SCRIPT_TELUGU */
860     "dv",  /* PANGO_SCRIPT_THAANA */
861     "th",  /* PANGO_SCRIPT_THAI */
862     "bo",  /* PANGO_SCRIPT_TIBETAN */
863     "iu",  /* PANGO_SCRIPT_CANADIAN_ABORIGINAL */
864     "",    /* PANGO_SCRIPT_YI */
865     "tl",  /* PANGO_SCRIPT_TAGALOG */
866     /* Phillipino languages/scripts */
867     "hnn", /* PANGO_SCRIPT_HANUNOO */
868     "bku", /* PANGO_SCRIPT_BUHID */
869     "tbw", /* PANGO_SCRIPT_TAGBANWA */
870
871     "",    /* PANGO_SCRIPT_BRAILLE */
872     "",    /* PANGO_SCRIPT_CYPRIOT */
873     "",    /* PANGO_SCRIPT_LIMBU */
874     /* Used for Somali (so) in the past */
875     "",    /* PANGO_SCRIPT_OSMANYA */
876     /* The Shavian alphabet was designed for English */
877     "",    /* PANGO_SCRIPT_SHAVIAN */
878     "",    /* PANGO_SCRIPT_LINEAR_B */
879     "",    /* PANGO_SCRIPT_TAI_LE */
880     "uga", /* PANGO_SCRIPT_UGARITIC */
881
882     "",    /* PANGO_SCRIPT_NEW_TAI_LUE */
883     "bug", /* PANGO_SCRIPT_BUGINESE */
884     /* The original script for Old Church Slavonic (chu), later
885      * written with Cyrillic */
886     "",    /* PANGO_SCRIPT_GLAGOLITIC */
887     /* Used for for Berber (ber), but Arabic script is more common */
888     "",    /* PANGO_SCRIPT_TIFINAGH */
889     "syl", /* PANGO_SCRIPT_SYLOTI_NAGRI */
890     "peo", /* PANGO_SCRIPT_OLD_PERSIAN */
891     "",    /* PANGO_SCRIPT_KHAROSHTHI */
892
893     "",    /* PANGO_SCRIPT_UNKNOWN */
894     "",    /* PANGO_SCRIPT_BALINESE */
895     "",    /* PANGO_SCRIPT_CUNEIFORM */
896     "",    /* PANGO_SCRIPT_PHOENICIAN */
897     "",    /* PANGO_SCRIPT_PHAGS_PA */
898     "nqo"  /* PANGO_SCRIPT_NKO */
899   };
900   const char *sample_language;
901   PangoLanguage *result;
902
903   g_return_val_if_fail (script >= 0, NULL);
904
905   if ((guint)script >= G_N_ELEMENTS (sample_languages))
906     return NULL;
907
908   result = _pango_script_get_default_language (script);
909   if (result)
910     return result;
911
912   sample_language = sample_languages[script];
913
914   if (!sample_language[0])
915     return NULL;
916   else
917     return pango_language_from_string (sample_language);
918 }