xref: /aosp_15_r20/external/libcups/cups/language.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * I18N/language support for CUPS.
3*5e7646d2SAndroid Build Coastguard Worker  *
4*5e7646d2SAndroid Build Coastguard Worker  * Copyright 2007-2017 by Apple Inc.
5*5e7646d2SAndroid Build Coastguard Worker  * Copyright 1997-2007 by Easy Software Products.
6*5e7646d2SAndroid Build Coastguard Worker  *
7*5e7646d2SAndroid Build Coastguard Worker  * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
8*5e7646d2SAndroid Build Coastguard Worker  */
9*5e7646d2SAndroid Build Coastguard Worker 
10*5e7646d2SAndroid Build Coastguard Worker /*
11*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers...
12*5e7646d2SAndroid Build Coastguard Worker  */
13*5e7646d2SAndroid Build Coastguard Worker 
14*5e7646d2SAndroid Build Coastguard Worker #include "cups-private.h"
15*5e7646d2SAndroid Build Coastguard Worker #include "debug-internal.h"
16*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_LANGINFO_H
17*5e7646d2SAndroid Build Coastguard Worker #  include <langinfo.h>
18*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_LANGINFO_H */
19*5e7646d2SAndroid Build Coastguard Worker #ifdef _WIN32
20*5e7646d2SAndroid Build Coastguard Worker #  include <io.h>
21*5e7646d2SAndroid Build Coastguard Worker #else
22*5e7646d2SAndroid Build Coastguard Worker #  include <unistd.h>
23*5e7646d2SAndroid Build Coastguard Worker #endif /* _WIN32 */
24*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_COREFOUNDATION_H
25*5e7646d2SAndroid Build Coastguard Worker #  include <CoreFoundation/CoreFoundation.h>
26*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_COREFOUNDATION_H */
27*5e7646d2SAndroid Build Coastguard Worker 
28*5e7646d2SAndroid Build Coastguard Worker 
29*5e7646d2SAndroid Build Coastguard Worker /*
30*5e7646d2SAndroid Build Coastguard Worker  * Local globals...
31*5e7646d2SAndroid Build Coastguard Worker  */
32*5e7646d2SAndroid Build Coastguard Worker 
33*5e7646d2SAndroid Build Coastguard Worker static _cups_mutex_t	lang_mutex = _CUPS_MUTEX_INITIALIZER;
34*5e7646d2SAndroid Build Coastguard Worker 					/* Mutex to control access to cache */
35*5e7646d2SAndroid Build Coastguard Worker static cups_lang_t	*lang_cache = NULL;
36*5e7646d2SAndroid Build Coastguard Worker 					/* Language string cache */
37*5e7646d2SAndroid Build Coastguard Worker static const char * const lang_encodings[] =
38*5e7646d2SAndroid Build Coastguard Worker 			{		/* Encoding strings */
39*5e7646d2SAndroid Build Coastguard Worker 			  "us-ascii",		"iso-8859-1",
40*5e7646d2SAndroid Build Coastguard Worker 			  "iso-8859-2",		"iso-8859-3",
41*5e7646d2SAndroid Build Coastguard Worker 			  "iso-8859-4",		"iso-8859-5",
42*5e7646d2SAndroid Build Coastguard Worker 			  "iso-8859-6",		"iso-8859-7",
43*5e7646d2SAndroid Build Coastguard Worker 			  "iso-8859-8",		"iso-8859-9",
44*5e7646d2SAndroid Build Coastguard Worker 			  "iso-8859-10",	"utf-8",
45*5e7646d2SAndroid Build Coastguard Worker 			  "iso-8859-13",	"iso-8859-14",
46*5e7646d2SAndroid Build Coastguard Worker 			  "iso-8859-15",	"cp874",
47*5e7646d2SAndroid Build Coastguard Worker 			  "cp1250",		"cp1251",
48*5e7646d2SAndroid Build Coastguard Worker 			  "cp1252",		"cp1253",
49*5e7646d2SAndroid Build Coastguard Worker 			  "cp1254",		"cp1255",
50*5e7646d2SAndroid Build Coastguard Worker 			  "cp1256",		"cp1257",
51*5e7646d2SAndroid Build Coastguard Worker 			  "cp1258",		"koi8-r",
52*5e7646d2SAndroid Build Coastguard Worker 			  "koi8-u",		"iso-8859-11",
53*5e7646d2SAndroid Build Coastguard Worker 			  "iso-8859-16",	"mac",
54*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
55*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
56*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
57*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
58*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
59*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
60*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
61*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
62*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
63*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
64*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
65*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
66*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
67*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
68*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
69*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
70*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
71*5e7646d2SAndroid Build Coastguard Worker 			  "cp932",		"cp936",
72*5e7646d2SAndroid Build Coastguard Worker 			  "cp949",		"cp950",
73*5e7646d2SAndroid Build Coastguard Worker 			  "cp1361",		"unknown",
74*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
75*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
76*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
77*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
78*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
79*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
80*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
81*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
82*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
83*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
84*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
85*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
86*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
87*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
88*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
89*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
90*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
91*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
92*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
93*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
94*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
95*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
96*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
97*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
98*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
99*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
100*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
101*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
102*5e7646d2SAndroid Build Coastguard Worker 			  "unknown",		"unknown",
103*5e7646d2SAndroid Build Coastguard Worker 			  "euc-cn",		"euc-jp",
104*5e7646d2SAndroid Build Coastguard Worker 			  "euc-kr",		"euc-tw",
105*5e7646d2SAndroid Build Coastguard Worker 			  "shift_jisx0213"
106*5e7646d2SAndroid Build Coastguard Worker 			};
107*5e7646d2SAndroid Build Coastguard Worker 
108*5e7646d2SAndroid Build Coastguard Worker #ifdef __APPLE__
109*5e7646d2SAndroid Build Coastguard Worker typedef struct
110*5e7646d2SAndroid Build Coastguard Worker {
111*5e7646d2SAndroid Build Coastguard Worker   const char * const language;		/* Language ID */
112*5e7646d2SAndroid Build Coastguard Worker   const char * const locale;		/* Locale ID */
113*5e7646d2SAndroid Build Coastguard Worker } _apple_language_locale_t;
114*5e7646d2SAndroid Build Coastguard Worker 
115*5e7646d2SAndroid Build Coastguard Worker static const _apple_language_locale_t apple_language_locale[] =
116*5e7646d2SAndroid Build Coastguard Worker {					/* Language to locale ID LUT */
117*5e7646d2SAndroid Build Coastguard Worker   { "en",         "en_US" },
118*5e7646d2SAndroid Build Coastguard Worker   { "nb",         "no" },
119*5e7646d2SAndroid Build Coastguard Worker   { "nb_NO",      "no" },
120*5e7646d2SAndroid Build Coastguard Worker   { "zh-Hans",    "zh_CN" },
121*5e7646d2SAndroid Build Coastguard Worker   { "zh_HANS",    "zh_CN" },
122*5e7646d2SAndroid Build Coastguard Worker   { "zh-Hant",    "zh_TW" },
123*5e7646d2SAndroid Build Coastguard Worker   { "zh_HANT",    "zh_TW" },
124*5e7646d2SAndroid Build Coastguard Worker   { "zh-Hant_CN", "zh_TW" }
125*5e7646d2SAndroid Build Coastguard Worker };
126*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ */
127*5e7646d2SAndroid Build Coastguard Worker 
128*5e7646d2SAndroid Build Coastguard Worker 
129*5e7646d2SAndroid Build Coastguard Worker /*
130*5e7646d2SAndroid Build Coastguard Worker  * Local functions...
131*5e7646d2SAndroid Build Coastguard Worker  */
132*5e7646d2SAndroid Build Coastguard Worker 
133*5e7646d2SAndroid Build Coastguard Worker 
134*5e7646d2SAndroid Build Coastguard Worker #ifdef __APPLE__
135*5e7646d2SAndroid Build Coastguard Worker static const char	*appleLangDefault(void);
136*5e7646d2SAndroid Build Coastguard Worker #  ifdef CUPS_BUNDLEDIR
137*5e7646d2SAndroid Build Coastguard Worker #    ifndef CF_RETURNS_RETAINED
138*5e7646d2SAndroid Build Coastguard Worker #      if __has_feature(attribute_cf_returns_retained)
139*5e7646d2SAndroid Build Coastguard Worker #        define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
140*5e7646d2SAndroid Build Coastguard Worker #      else
141*5e7646d2SAndroid Build Coastguard Worker #        define CF_RETURNS_RETAINED
142*5e7646d2SAndroid Build Coastguard Worker #      endif /* __has_feature(attribute_cf_returns_retained) */
143*5e7646d2SAndroid Build Coastguard Worker #    endif /* !CF_RETURNED_RETAINED */
144*5e7646d2SAndroid Build Coastguard Worker static cups_array_t	*appleMessageLoad(const char *locale) CF_RETURNS_RETAINED;
145*5e7646d2SAndroid Build Coastguard Worker #  endif /* CUPS_BUNDLEDIR */
146*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ */
147*5e7646d2SAndroid Build Coastguard Worker static cups_lang_t	*cups_cache_lookup(const char *name, cups_encoding_t encoding);
148*5e7646d2SAndroid Build Coastguard Worker static int		cups_message_compare(_cups_message_t *m1, _cups_message_t *m2);
149*5e7646d2SAndroid Build Coastguard Worker static void		cups_message_free(_cups_message_t *m);
150*5e7646d2SAndroid Build Coastguard Worker static void		cups_message_load(cups_lang_t *lang);
151*5e7646d2SAndroid Build Coastguard Worker static void		cups_message_puts(cups_file_t *fp, const char *s);
152*5e7646d2SAndroid Build Coastguard Worker static int		cups_read_strings(cups_file_t *fp, int flags, cups_array_t *a);
153*5e7646d2SAndroid Build Coastguard Worker static void		cups_unquote(char *d, const char *s);
154*5e7646d2SAndroid Build Coastguard Worker 
155*5e7646d2SAndroid Build Coastguard Worker 
156*5e7646d2SAndroid Build Coastguard Worker #ifdef __APPLE__
157*5e7646d2SAndroid Build Coastguard Worker /*
158*5e7646d2SAndroid Build Coastguard Worker  * '_cupsAppleLanguage()' - Get the Apple language identifier associated with a
159*5e7646d2SAndroid Build Coastguard Worker  *                          locale ID.
160*5e7646d2SAndroid Build Coastguard Worker  */
161*5e7646d2SAndroid Build Coastguard Worker 
162*5e7646d2SAndroid Build Coastguard Worker const char *				/* O - Language ID */
_cupsAppleLanguage(const char * locale,char * language,size_t langsize)163*5e7646d2SAndroid Build Coastguard Worker _cupsAppleLanguage(const char *locale,	/* I - Locale ID */
164*5e7646d2SAndroid Build Coastguard Worker                    char       *language,/* I - Language ID buffer */
165*5e7646d2SAndroid Build Coastguard Worker                    size_t     langsize)	/* I - Size of language ID buffer */
166*5e7646d2SAndroid Build Coastguard Worker {
167*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
168*5e7646d2SAndroid Build Coastguard Worker   CFStringRef	localeid,		/* CF locale identifier */
169*5e7646d2SAndroid Build Coastguard Worker 		langid;			/* CF language identifier */
170*5e7646d2SAndroid Build Coastguard Worker 
171*5e7646d2SAndroid Build Coastguard Worker 
172*5e7646d2SAndroid Build Coastguard Worker  /*
173*5e7646d2SAndroid Build Coastguard Worker   * Copy the locale name and convert, as needed, to the Apple-specific
174*5e7646d2SAndroid Build Coastguard Worker   * locale identifier...
175*5e7646d2SAndroid Build Coastguard Worker   */
176*5e7646d2SAndroid Build Coastguard Worker 
177*5e7646d2SAndroid Build Coastguard Worker   switch (strlen(locale))
178*5e7646d2SAndroid Build Coastguard Worker   {
179*5e7646d2SAndroid Build Coastguard Worker     default :
180*5e7646d2SAndroid Build Coastguard Worker         /*
181*5e7646d2SAndroid Build Coastguard Worker 	 * Invalid locale...
182*5e7646d2SAndroid Build Coastguard Worker 	 */
183*5e7646d2SAndroid Build Coastguard Worker 
184*5e7646d2SAndroid Build Coastguard Worker 	 strlcpy(language, "en", langsize);
185*5e7646d2SAndroid Build Coastguard Worker 	 break;
186*5e7646d2SAndroid Build Coastguard Worker 
187*5e7646d2SAndroid Build Coastguard Worker     case 2 :
188*5e7646d2SAndroid Build Coastguard Worker         strlcpy(language, locale, langsize);
189*5e7646d2SAndroid Build Coastguard Worker         break;
190*5e7646d2SAndroid Build Coastguard Worker 
191*5e7646d2SAndroid Build Coastguard Worker     case 5 :
192*5e7646d2SAndroid Build Coastguard Worker         strlcpy(language, locale, langsize);
193*5e7646d2SAndroid Build Coastguard Worker 
194*5e7646d2SAndroid Build Coastguard Worker 	if (language[2] == '-')
195*5e7646d2SAndroid Build Coastguard Worker 	{
196*5e7646d2SAndroid Build Coastguard Worker 	 /*
197*5e7646d2SAndroid Build Coastguard Worker 	  * Convert ll-cc to ll_CC...
198*5e7646d2SAndroid Build Coastguard Worker 	  */
199*5e7646d2SAndroid Build Coastguard Worker 
200*5e7646d2SAndroid Build Coastguard Worker 	  language[2] = '_';
201*5e7646d2SAndroid Build Coastguard Worker 	  language[3] = (char)toupper(language[3] & 255);
202*5e7646d2SAndroid Build Coastguard Worker 	  language[4] = (char)toupper(language[4] & 255);
203*5e7646d2SAndroid Build Coastguard Worker 	}
204*5e7646d2SAndroid Build Coastguard Worker 	break;
205*5e7646d2SAndroid Build Coastguard Worker   }
206*5e7646d2SAndroid Build Coastguard Worker 
207*5e7646d2SAndroid Build Coastguard Worker   for (i = 0;
208*5e7646d2SAndroid Build Coastguard Worker        i < (int)(sizeof(apple_language_locale) /
209*5e7646d2SAndroid Build Coastguard Worker 		 sizeof(apple_language_locale[0]));
210*5e7646d2SAndroid Build Coastguard Worker        i ++)
211*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(locale, apple_language_locale[i].locale))
212*5e7646d2SAndroid Build Coastguard Worker     {
213*5e7646d2SAndroid Build Coastguard Worker       strlcpy(language, apple_language_locale[i].language, sizeof(language));
214*5e7646d2SAndroid Build Coastguard Worker       break;
215*5e7646d2SAndroid Build Coastguard Worker     }
216*5e7646d2SAndroid Build Coastguard Worker 
217*5e7646d2SAndroid Build Coastguard Worker  /*
218*5e7646d2SAndroid Build Coastguard Worker   * Attempt to map the locale ID to a language ID...
219*5e7646d2SAndroid Build Coastguard Worker   */
220*5e7646d2SAndroid Build Coastguard Worker 
221*5e7646d2SAndroid Build Coastguard Worker   if ((localeid = CFStringCreateWithCString(kCFAllocatorDefault, language,
222*5e7646d2SAndroid Build Coastguard Worker                                             kCFStringEncodingASCII)) != NULL)
223*5e7646d2SAndroid Build Coastguard Worker   {
224*5e7646d2SAndroid Build Coastguard Worker     if ((langid = CFLocaleCreateCanonicalLanguageIdentifierFromString(
225*5e7646d2SAndroid Build Coastguard Worker                       kCFAllocatorDefault, localeid)) != NULL)
226*5e7646d2SAndroid Build Coastguard Worker     {
227*5e7646d2SAndroid Build Coastguard Worker       CFStringGetCString(langid, language, (CFIndex)langsize, kCFStringEncodingASCII);
228*5e7646d2SAndroid Build Coastguard Worker       CFRelease(langid);
229*5e7646d2SAndroid Build Coastguard Worker     }
230*5e7646d2SAndroid Build Coastguard Worker 
231*5e7646d2SAndroid Build Coastguard Worker     CFRelease(localeid);
232*5e7646d2SAndroid Build Coastguard Worker   }
233*5e7646d2SAndroid Build Coastguard Worker 
234*5e7646d2SAndroid Build Coastguard Worker  /*
235*5e7646d2SAndroid Build Coastguard Worker   * Return what we got...
236*5e7646d2SAndroid Build Coastguard Worker   */
237*5e7646d2SAndroid Build Coastguard Worker 
238*5e7646d2SAndroid Build Coastguard Worker   return (language);
239*5e7646d2SAndroid Build Coastguard Worker }
240*5e7646d2SAndroid Build Coastguard Worker 
241*5e7646d2SAndroid Build Coastguard Worker 
242*5e7646d2SAndroid Build Coastguard Worker /*
243*5e7646d2SAndroid Build Coastguard Worker  * '_cupsAppleLocale()' - Get the locale associated with an Apple language ID.
244*5e7646d2SAndroid Build Coastguard Worker  */
245*5e7646d2SAndroid Build Coastguard Worker 
246*5e7646d2SAndroid Build Coastguard Worker const char *					/* O - Locale */
_cupsAppleLocale(CFStringRef languageName,char * locale,size_t localesize)247*5e7646d2SAndroid Build Coastguard Worker _cupsAppleLocale(CFStringRef languageName,	/* I - Apple language ID */
248*5e7646d2SAndroid Build Coastguard Worker                  char        *locale,		/* I - Buffer for locale */
249*5e7646d2SAndroid Build Coastguard Worker 		 size_t      localesize)	/* I - Size of buffer */
250*5e7646d2SAndroid Build Coastguard Worker {
251*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
252*5e7646d2SAndroid Build Coastguard Worker   CFStringRef	localeName;		/* Locale as a CF string */
253*5e7646d2SAndroid Build Coastguard Worker #ifdef DEBUG
254*5e7646d2SAndroid Build Coastguard Worker   char          temp[1024];             /* Temporary string */
255*5e7646d2SAndroid Build Coastguard Worker 
256*5e7646d2SAndroid Build Coastguard Worker 
257*5e7646d2SAndroid Build Coastguard Worker   if (!CFStringGetCString(languageName, temp, (CFIndex)sizeof(temp), kCFStringEncodingASCII))
258*5e7646d2SAndroid Build Coastguard Worker     temp[0] = '\0';
259*5e7646d2SAndroid Build Coastguard Worker 
260*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("_cupsAppleLocale(languageName=%p(%s), locale=%p, localsize=%d)", (void *)languageName, temp, (void *)locale, (int)localesize));
261*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG */
262*5e7646d2SAndroid Build Coastguard Worker 
263*5e7646d2SAndroid Build Coastguard Worker   localeName = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, languageName);
264*5e7646d2SAndroid Build Coastguard Worker 
265*5e7646d2SAndroid Build Coastguard Worker   if (localeName)
266*5e7646d2SAndroid Build Coastguard Worker   {
267*5e7646d2SAndroid Build Coastguard Worker    /*
268*5e7646d2SAndroid Build Coastguard Worker     * Copy the locale name and tweak as needed...
269*5e7646d2SAndroid Build Coastguard Worker     */
270*5e7646d2SAndroid Build Coastguard Worker 
271*5e7646d2SAndroid Build Coastguard Worker     if (!CFStringGetCString(localeName, locale, (CFIndex)localesize, kCFStringEncodingASCII))
272*5e7646d2SAndroid Build Coastguard Worker       *locale = '\0';
273*5e7646d2SAndroid Build Coastguard Worker 
274*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("_cupsAppleLocale: locale=\"%s\"", locale));
275*5e7646d2SAndroid Build Coastguard Worker 
276*5e7646d2SAndroid Build Coastguard Worker     CFRelease(localeName);
277*5e7646d2SAndroid Build Coastguard Worker 
278*5e7646d2SAndroid Build Coastguard Worker    /*
279*5e7646d2SAndroid Build Coastguard Worker     * Map new language identifiers to locales...
280*5e7646d2SAndroid Build Coastguard Worker     */
281*5e7646d2SAndroid Build Coastguard Worker 
282*5e7646d2SAndroid Build Coastguard Worker     for (i = 0;
283*5e7646d2SAndroid Build Coastguard Worker 	 i < (int)(sizeof(apple_language_locale) /
284*5e7646d2SAndroid Build Coastguard Worker 		   sizeof(apple_language_locale[0]));
285*5e7646d2SAndroid Build Coastguard Worker 	 i ++)
286*5e7646d2SAndroid Build Coastguard Worker     {
287*5e7646d2SAndroid Build Coastguard Worker       size_t len = strlen(apple_language_locale[i].language);
288*5e7646d2SAndroid Build Coastguard Worker 
289*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(locale, apple_language_locale[i].language) ||
290*5e7646d2SAndroid Build Coastguard Worker           (!strncmp(locale, apple_language_locale[i].language, len) && (locale[len] == '_' || locale[len] == '-')))
291*5e7646d2SAndroid Build Coastguard Worker       {
292*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("_cupsAppleLocale: Updating locale to \"%s\".", apple_language_locale[i].locale));
293*5e7646d2SAndroid Build Coastguard Worker 	strlcpy(locale, apple_language_locale[i].locale, localesize);
294*5e7646d2SAndroid Build Coastguard Worker 	break;
295*5e7646d2SAndroid Build Coastguard Worker       }
296*5e7646d2SAndroid Build Coastguard Worker     }
297*5e7646d2SAndroid Build Coastguard Worker   }
298*5e7646d2SAndroid Build Coastguard Worker   else
299*5e7646d2SAndroid Build Coastguard Worker   {
300*5e7646d2SAndroid Build Coastguard Worker    /*
301*5e7646d2SAndroid Build Coastguard Worker     * Just try the Apple language name...
302*5e7646d2SAndroid Build Coastguard Worker     */
303*5e7646d2SAndroid Build Coastguard Worker 
304*5e7646d2SAndroid Build Coastguard Worker     if (!CFStringGetCString(languageName, locale, (CFIndex)localesize, kCFStringEncodingASCII))
305*5e7646d2SAndroid Build Coastguard Worker       *locale = '\0';
306*5e7646d2SAndroid Build Coastguard Worker   }
307*5e7646d2SAndroid Build Coastguard Worker 
308*5e7646d2SAndroid Build Coastguard Worker   if (!*locale)
309*5e7646d2SAndroid Build Coastguard Worker   {
310*5e7646d2SAndroid Build Coastguard Worker     DEBUG_puts("_cupsAppleLocale: Returning NULL.");
311*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
312*5e7646d2SAndroid Build Coastguard Worker   }
313*5e7646d2SAndroid Build Coastguard Worker 
314*5e7646d2SAndroid Build Coastguard Worker  /*
315*5e7646d2SAndroid Build Coastguard Worker   * Convert language subtag into region subtag...
316*5e7646d2SAndroid Build Coastguard Worker   */
317*5e7646d2SAndroid Build Coastguard Worker 
318*5e7646d2SAndroid Build Coastguard Worker   if (locale[2] == '-')
319*5e7646d2SAndroid Build Coastguard Worker     locale[2] = '_';
320*5e7646d2SAndroid Build Coastguard Worker   else if (locale[3] == '-')
321*5e7646d2SAndroid Build Coastguard Worker     locale[3] = '_';
322*5e7646d2SAndroid Build Coastguard Worker 
323*5e7646d2SAndroid Build Coastguard Worker   if (!strchr(locale, '.'))
324*5e7646d2SAndroid Build Coastguard Worker     strlcat(locale, ".UTF-8", localesize);
325*5e7646d2SAndroid Build Coastguard Worker 
326*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("_cupsAppleLocale: Returning \"%s\".", locale));
327*5e7646d2SAndroid Build Coastguard Worker 
328*5e7646d2SAndroid Build Coastguard Worker   return (locale);
329*5e7646d2SAndroid Build Coastguard Worker }
330*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ */
331*5e7646d2SAndroid Build Coastguard Worker 
332*5e7646d2SAndroid Build Coastguard Worker 
333*5e7646d2SAndroid Build Coastguard Worker /*
334*5e7646d2SAndroid Build Coastguard Worker  * '_cupsEncodingName()' - Return the character encoding name string
335*5e7646d2SAndroid Build Coastguard Worker  *                         for the given encoding enumeration.
336*5e7646d2SAndroid Build Coastguard Worker  */
337*5e7646d2SAndroid Build Coastguard Worker 
338*5e7646d2SAndroid Build Coastguard Worker const char *				/* O - Character encoding */
_cupsEncodingName(cups_encoding_t encoding)339*5e7646d2SAndroid Build Coastguard Worker _cupsEncodingName(
340*5e7646d2SAndroid Build Coastguard Worker     cups_encoding_t encoding)		/* I - Encoding value */
341*5e7646d2SAndroid Build Coastguard Worker {
342*5e7646d2SAndroid Build Coastguard Worker   if (encoding < CUPS_US_ASCII ||
343*5e7646d2SAndroid Build Coastguard Worker       encoding >= (cups_encoding_t)(sizeof(lang_encodings) / sizeof(lang_encodings[0])))
344*5e7646d2SAndroid Build Coastguard Worker   {
345*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1_cupsEncodingName(encoding=%d) = out of range (\"%s\")",
346*5e7646d2SAndroid Build Coastguard Worker                   encoding, lang_encodings[0]));
347*5e7646d2SAndroid Build Coastguard Worker     return (lang_encodings[0]);
348*5e7646d2SAndroid Build Coastguard Worker   }
349*5e7646d2SAndroid Build Coastguard Worker   else
350*5e7646d2SAndroid Build Coastguard Worker   {
351*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1_cupsEncodingName(encoding=%d) = \"%s\"",
352*5e7646d2SAndroid Build Coastguard Worker                   encoding, lang_encodings[encoding]));
353*5e7646d2SAndroid Build Coastguard Worker     return (lang_encodings[encoding]);
354*5e7646d2SAndroid Build Coastguard Worker   }
355*5e7646d2SAndroid Build Coastguard Worker }
356*5e7646d2SAndroid Build Coastguard Worker 
357*5e7646d2SAndroid Build Coastguard Worker 
358*5e7646d2SAndroid Build Coastguard Worker /*
359*5e7646d2SAndroid Build Coastguard Worker  * 'cupsLangDefault()' - Return the default language.
360*5e7646d2SAndroid Build Coastguard Worker  */
361*5e7646d2SAndroid Build Coastguard Worker 
362*5e7646d2SAndroid Build Coastguard Worker cups_lang_t *				/* O - Language data */
cupsLangDefault(void)363*5e7646d2SAndroid Build Coastguard Worker cupsLangDefault(void)
364*5e7646d2SAndroid Build Coastguard Worker {
365*5e7646d2SAndroid Build Coastguard Worker   return (cupsLangGet(NULL));
366*5e7646d2SAndroid Build Coastguard Worker }
367*5e7646d2SAndroid Build Coastguard Worker 
368*5e7646d2SAndroid Build Coastguard Worker 
369*5e7646d2SAndroid Build Coastguard Worker /*
370*5e7646d2SAndroid Build Coastguard Worker  * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.)
371*5e7646d2SAndroid Build Coastguard Worker  *                        for the given language.
372*5e7646d2SAndroid Build Coastguard Worker  */
373*5e7646d2SAndroid Build Coastguard Worker 
374*5e7646d2SAndroid Build Coastguard Worker const char *				/* O - Character encoding */
cupsLangEncoding(cups_lang_t * lang)375*5e7646d2SAndroid Build Coastguard Worker cupsLangEncoding(cups_lang_t *lang)	/* I - Language data */
376*5e7646d2SAndroid Build Coastguard Worker {
377*5e7646d2SAndroid Build Coastguard Worker   if (lang == NULL)
378*5e7646d2SAndroid Build Coastguard Worker     return ((char*)lang_encodings[0]);
379*5e7646d2SAndroid Build Coastguard Worker   else
380*5e7646d2SAndroid Build Coastguard Worker     return ((char*)lang_encodings[lang->encoding]);
381*5e7646d2SAndroid Build Coastguard Worker }
382*5e7646d2SAndroid Build Coastguard Worker 
383*5e7646d2SAndroid Build Coastguard Worker 
384*5e7646d2SAndroid Build Coastguard Worker /*
385*5e7646d2SAndroid Build Coastguard Worker  * 'cupsLangFlush()' - Flush all language data out of the cache.
386*5e7646d2SAndroid Build Coastguard Worker  */
387*5e7646d2SAndroid Build Coastguard Worker 
388*5e7646d2SAndroid Build Coastguard Worker void
cupsLangFlush(void)389*5e7646d2SAndroid Build Coastguard Worker cupsLangFlush(void)
390*5e7646d2SAndroid Build Coastguard Worker {
391*5e7646d2SAndroid Build Coastguard Worker   cups_lang_t	*lang,			/* Current language */
392*5e7646d2SAndroid Build Coastguard Worker 		*next;			/* Next language */
393*5e7646d2SAndroid Build Coastguard Worker 
394*5e7646d2SAndroid Build Coastguard Worker 
395*5e7646d2SAndroid Build Coastguard Worker  /*
396*5e7646d2SAndroid Build Coastguard Worker   * Free all languages in the cache...
397*5e7646d2SAndroid Build Coastguard Worker   */
398*5e7646d2SAndroid Build Coastguard Worker 
399*5e7646d2SAndroid Build Coastguard Worker   _cupsMutexLock(&lang_mutex);
400*5e7646d2SAndroid Build Coastguard Worker 
401*5e7646d2SAndroid Build Coastguard Worker   for (lang = lang_cache; lang != NULL; lang = next)
402*5e7646d2SAndroid Build Coastguard Worker   {
403*5e7646d2SAndroid Build Coastguard Worker    /*
404*5e7646d2SAndroid Build Coastguard Worker     * Free all messages...
405*5e7646d2SAndroid Build Coastguard Worker     */
406*5e7646d2SAndroid Build Coastguard Worker 
407*5e7646d2SAndroid Build Coastguard Worker     _cupsMessageFree(lang->strings);
408*5e7646d2SAndroid Build Coastguard Worker 
409*5e7646d2SAndroid Build Coastguard Worker    /*
410*5e7646d2SAndroid Build Coastguard Worker     * Then free the language structure itself...
411*5e7646d2SAndroid Build Coastguard Worker     */
412*5e7646d2SAndroid Build Coastguard Worker 
413*5e7646d2SAndroid Build Coastguard Worker     next = lang->next;
414*5e7646d2SAndroid Build Coastguard Worker     free(lang);
415*5e7646d2SAndroid Build Coastguard Worker   }
416*5e7646d2SAndroid Build Coastguard Worker 
417*5e7646d2SAndroid Build Coastguard Worker   lang_cache = NULL;
418*5e7646d2SAndroid Build Coastguard Worker 
419*5e7646d2SAndroid Build Coastguard Worker   _cupsMutexUnlock(&lang_mutex);
420*5e7646d2SAndroid Build Coastguard Worker }
421*5e7646d2SAndroid Build Coastguard Worker 
422*5e7646d2SAndroid Build Coastguard Worker 
423*5e7646d2SAndroid Build Coastguard Worker /*
424*5e7646d2SAndroid Build Coastguard Worker  * 'cupsLangFree()' - Free language data.
425*5e7646d2SAndroid Build Coastguard Worker  *
426*5e7646d2SAndroid Build Coastguard Worker  * This does not actually free anything; use @link cupsLangFlush@ for that.
427*5e7646d2SAndroid Build Coastguard Worker  */
428*5e7646d2SAndroid Build Coastguard Worker 
429*5e7646d2SAndroid Build Coastguard Worker void
cupsLangFree(cups_lang_t * lang)430*5e7646d2SAndroid Build Coastguard Worker cupsLangFree(cups_lang_t *lang)		/* I - Language to free */
431*5e7646d2SAndroid Build Coastguard Worker {
432*5e7646d2SAndroid Build Coastguard Worker   _cupsMutexLock(&lang_mutex);
433*5e7646d2SAndroid Build Coastguard Worker 
434*5e7646d2SAndroid Build Coastguard Worker   if (lang != NULL && lang->used > 0)
435*5e7646d2SAndroid Build Coastguard Worker     lang->used --;
436*5e7646d2SAndroid Build Coastguard Worker 
437*5e7646d2SAndroid Build Coastguard Worker   _cupsMutexUnlock(&lang_mutex);
438*5e7646d2SAndroid Build Coastguard Worker }
439*5e7646d2SAndroid Build Coastguard Worker 
440*5e7646d2SAndroid Build Coastguard Worker 
441*5e7646d2SAndroid Build Coastguard Worker /*
442*5e7646d2SAndroid Build Coastguard Worker  * 'cupsLangGet()' - Get a language.
443*5e7646d2SAndroid Build Coastguard Worker  */
444*5e7646d2SAndroid Build Coastguard Worker 
445*5e7646d2SAndroid Build Coastguard Worker cups_lang_t *				/* O - Language data */
cupsLangGet(const char * language)446*5e7646d2SAndroid Build Coastguard Worker cupsLangGet(const char *language)	/* I - Language or locale */
447*5e7646d2SAndroid Build Coastguard Worker {
448*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
449*5e7646d2SAndroid Build Coastguard Worker #ifndef __APPLE__
450*5e7646d2SAndroid Build Coastguard Worker   char			locale[255];	/* Copy of locale name */
451*5e7646d2SAndroid Build Coastguard Worker #endif /* !__APPLE__ */
452*5e7646d2SAndroid Build Coastguard Worker   char			langname[16],	/* Requested language name */
453*5e7646d2SAndroid Build Coastguard Worker 			country[16],	/* Country code */
454*5e7646d2SAndroid Build Coastguard Worker 			charset[16],	/* Character set */
455*5e7646d2SAndroid Build Coastguard Worker 			*csptr,		/* Pointer to CODESET string */
456*5e7646d2SAndroid Build Coastguard Worker 			*ptr,		/* Pointer into language/charset */
457*5e7646d2SAndroid Build Coastguard Worker 			real[48];	/* Real language name */
458*5e7646d2SAndroid Build Coastguard Worker   cups_encoding_t	encoding;	/* Encoding to use */
459*5e7646d2SAndroid Build Coastguard Worker   cups_lang_t		*lang;		/* Current language... */
460*5e7646d2SAndroid Build Coastguard Worker   static const char * const locale_encodings[] =
461*5e7646d2SAndroid Build Coastguard Worker 		{			/* Locale charset names */
462*5e7646d2SAndroid Build Coastguard Worker 		  "ASCII",	"ISO88591",	"ISO88592",	"ISO88593",
463*5e7646d2SAndroid Build Coastguard Worker 		  "ISO88594",	"ISO88595",	"ISO88596",	"ISO88597",
464*5e7646d2SAndroid Build Coastguard Worker 		  "ISO88598",	"ISO88599",	"ISO885910",	"UTF8",
465*5e7646d2SAndroid Build Coastguard Worker 		  "ISO885913",	"ISO885914",	"ISO885915",	"CP874",
466*5e7646d2SAndroid Build Coastguard Worker 		  "CP1250",	"CP1251",	"CP1252",	"CP1253",
467*5e7646d2SAndroid Build Coastguard Worker 		  "CP1254",	"CP1255",	"CP1256",	"CP1257",
468*5e7646d2SAndroid Build Coastguard Worker 		  "CP1258",	"KOI8R",	"KOI8U",	"ISO885911",
469*5e7646d2SAndroid Build Coastguard Worker 		  "ISO885916",	"MACROMAN",	"",		"",
470*5e7646d2SAndroid Build Coastguard Worker 
471*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
472*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
473*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
474*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
475*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
476*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
477*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
478*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
479*5e7646d2SAndroid Build Coastguard Worker 
480*5e7646d2SAndroid Build Coastguard Worker 		  "CP932",	"CP936",	"CP949",	"CP950",
481*5e7646d2SAndroid Build Coastguard Worker 		  "CP1361",	"",		"",		"",
482*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
483*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
484*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
485*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
486*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
487*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
488*5e7646d2SAndroid Build Coastguard Worker 
489*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
490*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
491*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
492*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
493*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
494*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
495*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
496*5e7646d2SAndroid Build Coastguard Worker 		  "",		"",		"",		"",
497*5e7646d2SAndroid Build Coastguard Worker 
498*5e7646d2SAndroid Build Coastguard Worker 		  "EUCCN",	"EUCJP",	"EUCKR",	"EUCTW",
499*5e7646d2SAndroid Build Coastguard Worker 		  "SHIFT_JISX0213"
500*5e7646d2SAndroid Build Coastguard Worker 		};
501*5e7646d2SAndroid Build Coastguard Worker 
502*5e7646d2SAndroid Build Coastguard Worker 
503*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("2cupsLangGet(language=\"%s\")", language));
504*5e7646d2SAndroid Build Coastguard Worker 
505*5e7646d2SAndroid Build Coastguard Worker #ifdef __APPLE__
506*5e7646d2SAndroid Build Coastguard Worker  /*
507*5e7646d2SAndroid Build Coastguard Worker   * Set the character set to UTF-8...
508*5e7646d2SAndroid Build Coastguard Worker   */
509*5e7646d2SAndroid Build Coastguard Worker 
510*5e7646d2SAndroid Build Coastguard Worker   strlcpy(charset, "UTF8", sizeof(charset));
511*5e7646d2SAndroid Build Coastguard Worker 
512*5e7646d2SAndroid Build Coastguard Worker  /*
513*5e7646d2SAndroid Build Coastguard Worker   * Apple's setlocale doesn't give us the user's localization
514*5e7646d2SAndroid Build Coastguard Worker   * preference so we have to look it up this way...
515*5e7646d2SAndroid Build Coastguard Worker   */
516*5e7646d2SAndroid Build Coastguard Worker 
517*5e7646d2SAndroid Build Coastguard Worker   if (!language)
518*5e7646d2SAndroid Build Coastguard Worker   {
519*5e7646d2SAndroid Build Coastguard Worker     if (!getenv("SOFTWARE") || (language = getenv("LANG")) == NULL)
520*5e7646d2SAndroid Build Coastguard Worker       language = appleLangDefault();
521*5e7646d2SAndroid Build Coastguard Worker 
522*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("4cupsLangGet: language=\"%s\"", language));
523*5e7646d2SAndroid Build Coastguard Worker   }
524*5e7646d2SAndroid Build Coastguard Worker 
525*5e7646d2SAndroid Build Coastguard Worker #else
526*5e7646d2SAndroid Build Coastguard Worker  /*
527*5e7646d2SAndroid Build Coastguard Worker   * Set the charset to "unknown"...
528*5e7646d2SAndroid Build Coastguard Worker   */
529*5e7646d2SAndroid Build Coastguard Worker 
530*5e7646d2SAndroid Build Coastguard Worker   charset[0] = '\0';
531*5e7646d2SAndroid Build Coastguard Worker 
532*5e7646d2SAndroid Build Coastguard Worker  /*
533*5e7646d2SAndroid Build Coastguard Worker   * Use setlocale() to determine the currently set locale, and then
534*5e7646d2SAndroid Build Coastguard Worker   * fallback to environment variables to avoid setting the locale,
535*5e7646d2SAndroid Build Coastguard Worker   * since setlocale() is not thread-safe!
536*5e7646d2SAndroid Build Coastguard Worker   */
537*5e7646d2SAndroid Build Coastguard Worker 
538*5e7646d2SAndroid Build Coastguard Worker   if (!language)
539*5e7646d2SAndroid Build Coastguard Worker   {
540*5e7646d2SAndroid Build Coastguard Worker    /*
541*5e7646d2SAndroid Build Coastguard Worker     * First see if the locale has been set; if it is still "C" or
542*5e7646d2SAndroid Build Coastguard Worker     * "POSIX", use the environment to get the default...
543*5e7646d2SAndroid Build Coastguard Worker     */
544*5e7646d2SAndroid Build Coastguard Worker 
545*5e7646d2SAndroid Build Coastguard Worker #  ifdef LC_MESSAGES
546*5e7646d2SAndroid Build Coastguard Worker     ptr = setlocale(LC_MESSAGES, NULL);
547*5e7646d2SAndroid Build Coastguard Worker #  else
548*5e7646d2SAndroid Build Coastguard Worker     ptr = setlocale(LC_ALL, NULL);
549*5e7646d2SAndroid Build Coastguard Worker #  endif /* LC_MESSAGES */
550*5e7646d2SAndroid Build Coastguard Worker 
551*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("4cupsLangGet: current locale is \"%s\"", ptr));
552*5e7646d2SAndroid Build Coastguard Worker 
553*5e7646d2SAndroid Build Coastguard Worker     if (!ptr || !strcmp(ptr, "C") || !strcmp(ptr, "POSIX"))
554*5e7646d2SAndroid Build Coastguard Worker     {
555*5e7646d2SAndroid Build Coastguard Worker      /*
556*5e7646d2SAndroid Build Coastguard Worker       * Get the character set from the LC_CTYPE locale setting...
557*5e7646d2SAndroid Build Coastguard Worker       */
558*5e7646d2SAndroid Build Coastguard Worker 
559*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = getenv("LC_CTYPE")) == NULL)
560*5e7646d2SAndroid Build Coastguard Worker         if ((ptr = getenv("LC_ALL")) == NULL)
561*5e7646d2SAndroid Build Coastguard Worker 	  if ((ptr = getenv("LANG")) == NULL)
562*5e7646d2SAndroid Build Coastguard Worker 	    ptr = "en_US";
563*5e7646d2SAndroid Build Coastguard Worker 
564*5e7646d2SAndroid Build Coastguard Worker       if ((csptr = strchr(ptr, '.')) != NULL)
565*5e7646d2SAndroid Build Coastguard Worker       {
566*5e7646d2SAndroid Build Coastguard Worker        /*
567*5e7646d2SAndroid Build Coastguard Worker         * Extract the character set from the environment...
568*5e7646d2SAndroid Build Coastguard Worker 	*/
569*5e7646d2SAndroid Build Coastguard Worker 
570*5e7646d2SAndroid Build Coastguard Worker 	for (ptr = charset, csptr ++; *csptr; csptr ++)
571*5e7646d2SAndroid Build Coastguard Worker 	  if (ptr < (charset + sizeof(charset) - 1) && _cups_isalnum(*csptr))
572*5e7646d2SAndroid Build Coastguard Worker 	    *ptr++ = *csptr;
573*5e7646d2SAndroid Build Coastguard Worker 
574*5e7646d2SAndroid Build Coastguard Worker         *ptr = '\0';
575*5e7646d2SAndroid Build Coastguard Worker       }
576*5e7646d2SAndroid Build Coastguard Worker 
577*5e7646d2SAndroid Build Coastguard Worker      /*
578*5e7646d2SAndroid Build Coastguard Worker       * Get the locale for messages from the LC_MESSAGES locale setting...
579*5e7646d2SAndroid Build Coastguard Worker       */
580*5e7646d2SAndroid Build Coastguard Worker 
581*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = getenv("LC_MESSAGES")) == NULL)
582*5e7646d2SAndroid Build Coastguard Worker         if ((ptr = getenv("LC_ALL")) == NULL)
583*5e7646d2SAndroid Build Coastguard Worker 	  if ((ptr = getenv("LANG")) == NULL)
584*5e7646d2SAndroid Build Coastguard Worker 	    ptr = "en_US";
585*5e7646d2SAndroid Build Coastguard Worker     }
586*5e7646d2SAndroid Build Coastguard Worker 
587*5e7646d2SAndroid Build Coastguard Worker     if (ptr)
588*5e7646d2SAndroid Build Coastguard Worker     {
589*5e7646d2SAndroid Build Coastguard Worker       strlcpy(locale, ptr, sizeof(locale));
590*5e7646d2SAndroid Build Coastguard Worker       language = locale;
591*5e7646d2SAndroid Build Coastguard Worker 
592*5e7646d2SAndroid Build Coastguard Worker      /*
593*5e7646d2SAndroid Build Coastguard Worker       * CUPS STR #2575: Map "nb" to "no" for back-compatibility...
594*5e7646d2SAndroid Build Coastguard Worker       */
595*5e7646d2SAndroid Build Coastguard Worker 
596*5e7646d2SAndroid Build Coastguard Worker       if (!strncmp(locale, "nb", 2))
597*5e7646d2SAndroid Build Coastguard Worker         locale[1] = 'o';
598*5e7646d2SAndroid Build Coastguard Worker 
599*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("4cupsLangGet: new language value is \"%s\"", language));
600*5e7646d2SAndroid Build Coastguard Worker     }
601*5e7646d2SAndroid Build Coastguard Worker   }
602*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ */
603*5e7646d2SAndroid Build Coastguard Worker 
604*5e7646d2SAndroid Build Coastguard Worker  /*
605*5e7646d2SAndroid Build Coastguard Worker   * If "language" is NULL at this point, then chances are we are using
606*5e7646d2SAndroid Build Coastguard Worker   * a language that is not installed for the base OS.
607*5e7646d2SAndroid Build Coastguard Worker   */
608*5e7646d2SAndroid Build Coastguard Worker 
609*5e7646d2SAndroid Build Coastguard Worker   if (!language)
610*5e7646d2SAndroid Build Coastguard Worker   {
611*5e7646d2SAndroid Build Coastguard Worker    /*
612*5e7646d2SAndroid Build Coastguard Worker     * Switch to the POSIX ("C") locale...
613*5e7646d2SAndroid Build Coastguard Worker     */
614*5e7646d2SAndroid Build Coastguard Worker 
615*5e7646d2SAndroid Build Coastguard Worker     language = "C";
616*5e7646d2SAndroid Build Coastguard Worker   }
617*5e7646d2SAndroid Build Coastguard Worker 
618*5e7646d2SAndroid Build Coastguard Worker #ifdef CODESET
619*5e7646d2SAndroid Build Coastguard Worker  /*
620*5e7646d2SAndroid Build Coastguard Worker   * On systems that support the nl_langinfo(CODESET) call, use
621*5e7646d2SAndroid Build Coastguard Worker   * this value as the character set...
622*5e7646d2SAndroid Build Coastguard Worker   */
623*5e7646d2SAndroid Build Coastguard Worker 
624*5e7646d2SAndroid Build Coastguard Worker   if (!charset[0] && (csptr = nl_langinfo(CODESET)) != NULL)
625*5e7646d2SAndroid Build Coastguard Worker   {
626*5e7646d2SAndroid Build Coastguard Worker    /*
627*5e7646d2SAndroid Build Coastguard Worker     * Copy all of the letters and numbers in the CODESET string...
628*5e7646d2SAndroid Build Coastguard Worker     */
629*5e7646d2SAndroid Build Coastguard Worker 
630*5e7646d2SAndroid Build Coastguard Worker     for (ptr = charset; *csptr; csptr ++)
631*5e7646d2SAndroid Build Coastguard Worker       if (_cups_isalnum(*csptr) && ptr < (charset + sizeof(charset) - 1))
632*5e7646d2SAndroid Build Coastguard Worker         *ptr++ = *csptr;
633*5e7646d2SAndroid Build Coastguard Worker 
634*5e7646d2SAndroid Build Coastguard Worker     *ptr = '\0';
635*5e7646d2SAndroid Build Coastguard Worker 
636*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("4cupsLangGet: charset set to \"%s\" via "
637*5e7646d2SAndroid Build Coastguard Worker                   "nl_langinfo(CODESET)...", charset));
638*5e7646d2SAndroid Build Coastguard Worker   }
639*5e7646d2SAndroid Build Coastguard Worker #endif /* CODESET */
640*5e7646d2SAndroid Build Coastguard Worker 
641*5e7646d2SAndroid Build Coastguard Worker  /*
642*5e7646d2SAndroid Build Coastguard Worker   * If we don't have a character set by now, default to UTF-8...
643*5e7646d2SAndroid Build Coastguard Worker   */
644*5e7646d2SAndroid Build Coastguard Worker 
645*5e7646d2SAndroid Build Coastguard Worker   if (!charset[0])
646*5e7646d2SAndroid Build Coastguard Worker     strlcpy(charset, "UTF8", sizeof(charset));
647*5e7646d2SAndroid Build Coastguard Worker 
648*5e7646d2SAndroid Build Coastguard Worker  /*
649*5e7646d2SAndroid Build Coastguard Worker   * Parse the language string passed in to a locale string. "C" is the
650*5e7646d2SAndroid Build Coastguard Worker   * standard POSIX locale and is copied unchanged.  Otherwise the
651*5e7646d2SAndroid Build Coastguard Worker   * language string is converted from ll-cc[.charset] (language-country)
652*5e7646d2SAndroid Build Coastguard Worker   * to ll_CC[.CHARSET] to match the file naming convention used by all
653*5e7646d2SAndroid Build Coastguard Worker   * POSIX-compliant operating systems.  Invalid language names are mapped
654*5e7646d2SAndroid Build Coastguard Worker   * to the POSIX locale.
655*5e7646d2SAndroid Build Coastguard Worker   */
656*5e7646d2SAndroid Build Coastguard Worker 
657*5e7646d2SAndroid Build Coastguard Worker   country[0] = '\0';
658*5e7646d2SAndroid Build Coastguard Worker 
659*5e7646d2SAndroid Build Coastguard Worker   if (language == NULL || !language[0] ||
660*5e7646d2SAndroid Build Coastguard Worker       !strcmp(language, "POSIX"))
661*5e7646d2SAndroid Build Coastguard Worker     strlcpy(langname, "C", sizeof(langname));
662*5e7646d2SAndroid Build Coastguard Worker   else
663*5e7646d2SAndroid Build Coastguard Worker   {
664*5e7646d2SAndroid Build Coastguard Worker    /*
665*5e7646d2SAndroid Build Coastguard Worker     * Copy the parts of the locale string over safely...
666*5e7646d2SAndroid Build Coastguard Worker     */
667*5e7646d2SAndroid Build Coastguard Worker 
668*5e7646d2SAndroid Build Coastguard Worker     for (ptr = langname; *language; language ++)
669*5e7646d2SAndroid Build Coastguard Worker       if (*language == '_' || *language == '-' || *language == '.')
670*5e7646d2SAndroid Build Coastguard Worker 	break;
671*5e7646d2SAndroid Build Coastguard Worker       else if (ptr < (langname + sizeof(langname) - 1))
672*5e7646d2SAndroid Build Coastguard Worker         *ptr++ = (char)tolower(*language & 255);
673*5e7646d2SAndroid Build Coastguard Worker 
674*5e7646d2SAndroid Build Coastguard Worker     *ptr = '\0';
675*5e7646d2SAndroid Build Coastguard Worker 
676*5e7646d2SAndroid Build Coastguard Worker     if (*language == '_' || *language == '-')
677*5e7646d2SAndroid Build Coastguard Worker     {
678*5e7646d2SAndroid Build Coastguard Worker      /*
679*5e7646d2SAndroid Build Coastguard Worker       * Copy the country code...
680*5e7646d2SAndroid Build Coastguard Worker       */
681*5e7646d2SAndroid Build Coastguard Worker 
682*5e7646d2SAndroid Build Coastguard Worker       for (language ++, ptr = country; *language; language ++)
683*5e7646d2SAndroid Build Coastguard Worker 	if (*language == '.')
684*5e7646d2SAndroid Build Coastguard Worker 	  break;
685*5e7646d2SAndroid Build Coastguard Worker 	else if (ptr < (country + sizeof(country) - 1))
686*5e7646d2SAndroid Build Coastguard Worker           *ptr++ = (char)toupper(*language & 255);
687*5e7646d2SAndroid Build Coastguard Worker 
688*5e7646d2SAndroid Build Coastguard Worker       *ptr = '\0';
689*5e7646d2SAndroid Build Coastguard Worker 
690*5e7646d2SAndroid Build Coastguard Worker      /*
691*5e7646d2SAndroid Build Coastguard Worker       * Map Chinese region codes to legacy country codes.
692*5e7646d2SAndroid Build Coastguard Worker       */
693*5e7646d2SAndroid Build Coastguard Worker 
694*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(language, "zh") && !strcmp(country, "HANS"))
695*5e7646d2SAndroid Build Coastguard Worker         strlcpy(country, "CN", sizeof(country));
696*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(language, "zh") && !strcmp(country, "HANT"))
697*5e7646d2SAndroid Build Coastguard Worker         strlcpy(country, "TW", sizeof(country));
698*5e7646d2SAndroid Build Coastguard Worker     }
699*5e7646d2SAndroid Build Coastguard Worker 
700*5e7646d2SAndroid Build Coastguard Worker     if (*language == '.' && !charset[0])
701*5e7646d2SAndroid Build Coastguard Worker     {
702*5e7646d2SAndroid Build Coastguard Worker      /*
703*5e7646d2SAndroid Build Coastguard Worker       * Copy the encoding...
704*5e7646d2SAndroid Build Coastguard Worker       */
705*5e7646d2SAndroid Build Coastguard Worker 
706*5e7646d2SAndroid Build Coastguard Worker       for (language ++, ptr = charset; *language; language ++)
707*5e7646d2SAndroid Build Coastguard Worker         if (_cups_isalnum(*language) && ptr < (charset + sizeof(charset) - 1))
708*5e7646d2SAndroid Build Coastguard Worker           *ptr++ = (char)toupper(*language & 255);
709*5e7646d2SAndroid Build Coastguard Worker 
710*5e7646d2SAndroid Build Coastguard Worker       *ptr = '\0';
711*5e7646d2SAndroid Build Coastguard Worker     }
712*5e7646d2SAndroid Build Coastguard Worker 
713*5e7646d2SAndroid Build Coastguard Worker    /*
714*5e7646d2SAndroid Build Coastguard Worker     * Force a POSIX locale for an invalid language name...
715*5e7646d2SAndroid Build Coastguard Worker     */
716*5e7646d2SAndroid Build Coastguard Worker 
717*5e7646d2SAndroid Build Coastguard Worker     if (strlen(langname) != 2 && strlen(langname) != 3)
718*5e7646d2SAndroid Build Coastguard Worker     {
719*5e7646d2SAndroid Build Coastguard Worker       strlcpy(langname, "C", sizeof(langname));
720*5e7646d2SAndroid Build Coastguard Worker       country[0] = '\0';
721*5e7646d2SAndroid Build Coastguard Worker       charset[0] = '\0';
722*5e7646d2SAndroid Build Coastguard Worker     }
723*5e7646d2SAndroid Build Coastguard Worker   }
724*5e7646d2SAndroid Build Coastguard Worker 
725*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("4cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"",
726*5e7646d2SAndroid Build Coastguard Worker                 langname, country, charset));
727*5e7646d2SAndroid Build Coastguard Worker 
728*5e7646d2SAndroid Build Coastguard Worker  /*
729*5e7646d2SAndroid Build Coastguard Worker   * Figure out the desired encoding...
730*5e7646d2SAndroid Build Coastguard Worker   */
731*5e7646d2SAndroid Build Coastguard Worker 
732*5e7646d2SAndroid Build Coastguard Worker   encoding = CUPS_AUTO_ENCODING;
733*5e7646d2SAndroid Build Coastguard Worker 
734*5e7646d2SAndroid Build Coastguard Worker   if (charset[0])
735*5e7646d2SAndroid Build Coastguard Worker   {
736*5e7646d2SAndroid Build Coastguard Worker     for (i = 0;
737*5e7646d2SAndroid Build Coastguard Worker          i < (int)(sizeof(locale_encodings) / sizeof(locale_encodings[0]));
738*5e7646d2SAndroid Build Coastguard Worker 	 i ++)
739*5e7646d2SAndroid Build Coastguard Worker       if (!_cups_strcasecmp(charset, locale_encodings[i]))
740*5e7646d2SAndroid Build Coastguard Worker       {
741*5e7646d2SAndroid Build Coastguard Worker 	encoding = (cups_encoding_t)i;
742*5e7646d2SAndroid Build Coastguard Worker 	break;
743*5e7646d2SAndroid Build Coastguard Worker       }
744*5e7646d2SAndroid Build Coastguard Worker 
745*5e7646d2SAndroid Build Coastguard Worker     if (encoding == CUPS_AUTO_ENCODING)
746*5e7646d2SAndroid Build Coastguard Worker     {
747*5e7646d2SAndroid Build Coastguard Worker      /*
748*5e7646d2SAndroid Build Coastguard Worker       * Map alternate names for various character sets...
749*5e7646d2SAndroid Build Coastguard Worker       */
750*5e7646d2SAndroid Build Coastguard Worker 
751*5e7646d2SAndroid Build Coastguard Worker       if (!_cups_strcasecmp(charset, "iso-2022-jp") ||
752*5e7646d2SAndroid Build Coastguard Worker           !_cups_strcasecmp(charset, "sjis"))
753*5e7646d2SAndroid Build Coastguard Worker 	encoding = CUPS_WINDOWS_932;
754*5e7646d2SAndroid Build Coastguard Worker       else if (!_cups_strcasecmp(charset, "iso-2022-cn"))
755*5e7646d2SAndroid Build Coastguard Worker 	encoding = CUPS_WINDOWS_936;
756*5e7646d2SAndroid Build Coastguard Worker       else if (!_cups_strcasecmp(charset, "iso-2022-kr"))
757*5e7646d2SAndroid Build Coastguard Worker 	encoding = CUPS_WINDOWS_949;
758*5e7646d2SAndroid Build Coastguard Worker       else if (!_cups_strcasecmp(charset, "big5"))
759*5e7646d2SAndroid Build Coastguard Worker 	encoding = CUPS_WINDOWS_950;
760*5e7646d2SAndroid Build Coastguard Worker     }
761*5e7646d2SAndroid Build Coastguard Worker   }
762*5e7646d2SAndroid Build Coastguard Worker 
763*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("4cupsLangGet: encoding=%d(%s)", encoding,
764*5e7646d2SAndroid Build Coastguard Worker                 encoding == CUPS_AUTO_ENCODING ? "auto" :
765*5e7646d2SAndroid Build Coastguard Worker 		    lang_encodings[encoding]));
766*5e7646d2SAndroid Build Coastguard Worker 
767*5e7646d2SAndroid Build Coastguard Worker  /*
768*5e7646d2SAndroid Build Coastguard Worker   * See if we already have this language/country loaded...
769*5e7646d2SAndroid Build Coastguard Worker   */
770*5e7646d2SAndroid Build Coastguard Worker 
771*5e7646d2SAndroid Build Coastguard Worker   if (country[0])
772*5e7646d2SAndroid Build Coastguard Worker     snprintf(real, sizeof(real), "%s_%s", langname, country);
773*5e7646d2SAndroid Build Coastguard Worker   else
774*5e7646d2SAndroid Build Coastguard Worker     strlcpy(real, langname, sizeof(real));
775*5e7646d2SAndroid Build Coastguard Worker 
776*5e7646d2SAndroid Build Coastguard Worker   _cupsMutexLock(&lang_mutex);
777*5e7646d2SAndroid Build Coastguard Worker 
778*5e7646d2SAndroid Build Coastguard Worker   if ((lang = cups_cache_lookup(real, encoding)) != NULL)
779*5e7646d2SAndroid Build Coastguard Worker   {
780*5e7646d2SAndroid Build Coastguard Worker     _cupsMutexUnlock(&lang_mutex);
781*5e7646d2SAndroid Build Coastguard Worker 
782*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("3cupsLangGet: Using cached copy of \"%s\"...", real));
783*5e7646d2SAndroid Build Coastguard Worker 
784*5e7646d2SAndroid Build Coastguard Worker     return (lang);
785*5e7646d2SAndroid Build Coastguard Worker   }
786*5e7646d2SAndroid Build Coastguard Worker 
787*5e7646d2SAndroid Build Coastguard Worker  /*
788*5e7646d2SAndroid Build Coastguard Worker   * See if there is a free language available; if so, use that
789*5e7646d2SAndroid Build Coastguard Worker   * record...
790*5e7646d2SAndroid Build Coastguard Worker   */
791*5e7646d2SAndroid Build Coastguard Worker 
792*5e7646d2SAndroid Build Coastguard Worker   for (lang = lang_cache; lang != NULL; lang = lang->next)
793*5e7646d2SAndroid Build Coastguard Worker     if (lang->used == 0)
794*5e7646d2SAndroid Build Coastguard Worker       break;
795*5e7646d2SAndroid Build Coastguard Worker 
796*5e7646d2SAndroid Build Coastguard Worker   if (lang == NULL)
797*5e7646d2SAndroid Build Coastguard Worker   {
798*5e7646d2SAndroid Build Coastguard Worker    /*
799*5e7646d2SAndroid Build Coastguard Worker     * Allocate memory for the language and add it to the cache.
800*5e7646d2SAndroid Build Coastguard Worker     */
801*5e7646d2SAndroid Build Coastguard Worker 
802*5e7646d2SAndroid Build Coastguard Worker     if ((lang = calloc(sizeof(cups_lang_t), 1)) == NULL)
803*5e7646d2SAndroid Build Coastguard Worker     {
804*5e7646d2SAndroid Build Coastguard Worker       _cupsMutexUnlock(&lang_mutex);
805*5e7646d2SAndroid Build Coastguard Worker 
806*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
807*5e7646d2SAndroid Build Coastguard Worker     }
808*5e7646d2SAndroid Build Coastguard Worker 
809*5e7646d2SAndroid Build Coastguard Worker     lang->next = lang_cache;
810*5e7646d2SAndroid Build Coastguard Worker     lang_cache = lang;
811*5e7646d2SAndroid Build Coastguard Worker   }
812*5e7646d2SAndroid Build Coastguard Worker   else
813*5e7646d2SAndroid Build Coastguard Worker   {
814*5e7646d2SAndroid Build Coastguard Worker    /*
815*5e7646d2SAndroid Build Coastguard Worker     * Free all old strings as needed...
816*5e7646d2SAndroid Build Coastguard Worker     */
817*5e7646d2SAndroid Build Coastguard Worker 
818*5e7646d2SAndroid Build Coastguard Worker     _cupsMessageFree(lang->strings);
819*5e7646d2SAndroid Build Coastguard Worker     lang->strings = NULL;
820*5e7646d2SAndroid Build Coastguard Worker   }
821*5e7646d2SAndroid Build Coastguard Worker 
822*5e7646d2SAndroid Build Coastguard Worker  /*
823*5e7646d2SAndroid Build Coastguard Worker   * Then assign the language and encoding fields...
824*5e7646d2SAndroid Build Coastguard Worker   */
825*5e7646d2SAndroid Build Coastguard Worker 
826*5e7646d2SAndroid Build Coastguard Worker   lang->used ++;
827*5e7646d2SAndroid Build Coastguard Worker   strlcpy(lang->language, real, sizeof(lang->language));
828*5e7646d2SAndroid Build Coastguard Worker 
829*5e7646d2SAndroid Build Coastguard Worker   if (encoding != CUPS_AUTO_ENCODING)
830*5e7646d2SAndroid Build Coastguard Worker     lang->encoding = encoding;
831*5e7646d2SAndroid Build Coastguard Worker   else
832*5e7646d2SAndroid Build Coastguard Worker     lang->encoding = CUPS_UTF8;
833*5e7646d2SAndroid Build Coastguard Worker 
834*5e7646d2SAndroid Build Coastguard Worker  /*
835*5e7646d2SAndroid Build Coastguard Worker   * Return...
836*5e7646d2SAndroid Build Coastguard Worker   */
837*5e7646d2SAndroid Build Coastguard Worker 
838*5e7646d2SAndroid Build Coastguard Worker   _cupsMutexUnlock(&lang_mutex);
839*5e7646d2SAndroid Build Coastguard Worker 
840*5e7646d2SAndroid Build Coastguard Worker   return (lang);
841*5e7646d2SAndroid Build Coastguard Worker }
842*5e7646d2SAndroid Build Coastguard Worker 
843*5e7646d2SAndroid Build Coastguard Worker 
844*5e7646d2SAndroid Build Coastguard Worker /*
845*5e7646d2SAndroid Build Coastguard Worker  * '_cupsLangString()' - Get a message string.
846*5e7646d2SAndroid Build Coastguard Worker  *
847*5e7646d2SAndroid Build Coastguard Worker  * The returned string is UTF-8 encoded; use cupsUTF8ToCharset() to
848*5e7646d2SAndroid Build Coastguard Worker  * convert the string to the language encoding.
849*5e7646d2SAndroid Build Coastguard Worker  */
850*5e7646d2SAndroid Build Coastguard Worker 
851*5e7646d2SAndroid Build Coastguard Worker const char *				/* O - Localized message */
_cupsLangString(cups_lang_t * lang,const char * message)852*5e7646d2SAndroid Build Coastguard Worker _cupsLangString(cups_lang_t *lang,	/* I - Language */
853*5e7646d2SAndroid Build Coastguard Worker                 const char  *message)	/* I - Message */
854*5e7646d2SAndroid Build Coastguard Worker {
855*5e7646d2SAndroid Build Coastguard Worker   const char *s;			/* Localized message */
856*5e7646d2SAndroid Build Coastguard Worker 
857*5e7646d2SAndroid Build Coastguard Worker 
858*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("_cupsLangString(lang=%p, message=\"%s\")", (void *)lang, message));
859*5e7646d2SAndroid Build Coastguard Worker 
860*5e7646d2SAndroid Build Coastguard Worker  /*
861*5e7646d2SAndroid Build Coastguard Worker   * Range check input...
862*5e7646d2SAndroid Build Coastguard Worker   */
863*5e7646d2SAndroid Build Coastguard Worker 
864*5e7646d2SAndroid Build Coastguard Worker   if (!lang || !message || !*message)
865*5e7646d2SAndroid Build Coastguard Worker     return (message);
866*5e7646d2SAndroid Build Coastguard Worker 
867*5e7646d2SAndroid Build Coastguard Worker   _cupsMutexLock(&lang_mutex);
868*5e7646d2SAndroid Build Coastguard Worker 
869*5e7646d2SAndroid Build Coastguard Worker  /*
870*5e7646d2SAndroid Build Coastguard Worker   * Load the message catalog if needed...
871*5e7646d2SAndroid Build Coastguard Worker   */
872*5e7646d2SAndroid Build Coastguard Worker 
873*5e7646d2SAndroid Build Coastguard Worker   if (!lang->strings)
874*5e7646d2SAndroid Build Coastguard Worker     cups_message_load(lang);
875*5e7646d2SAndroid Build Coastguard Worker 
876*5e7646d2SAndroid Build Coastguard Worker   s = _cupsMessageLookup(lang->strings, message);
877*5e7646d2SAndroid Build Coastguard Worker 
878*5e7646d2SAndroid Build Coastguard Worker   _cupsMutexUnlock(&lang_mutex);
879*5e7646d2SAndroid Build Coastguard Worker 
880*5e7646d2SAndroid Build Coastguard Worker   return (s);
881*5e7646d2SAndroid Build Coastguard Worker }
882*5e7646d2SAndroid Build Coastguard Worker 
883*5e7646d2SAndroid Build Coastguard Worker 
884*5e7646d2SAndroid Build Coastguard Worker /*
885*5e7646d2SAndroid Build Coastguard Worker  * '_cupsMessageFree()' - Free a messages array.
886*5e7646d2SAndroid Build Coastguard Worker  */
887*5e7646d2SAndroid Build Coastguard Worker 
888*5e7646d2SAndroid Build Coastguard Worker void
_cupsMessageFree(cups_array_t * a)889*5e7646d2SAndroid Build Coastguard Worker _cupsMessageFree(cups_array_t *a)	/* I - Message array */
890*5e7646d2SAndroid Build Coastguard Worker {
891*5e7646d2SAndroid Build Coastguard Worker #if defined(__APPLE__) && defined(CUPS_BUNDLEDIR)
892*5e7646d2SAndroid Build Coastguard Worker  /*
893*5e7646d2SAndroid Build Coastguard Worker   * Release the cups.strings dictionary as needed...
894*5e7646d2SAndroid Build Coastguard Worker   */
895*5e7646d2SAndroid Build Coastguard Worker 
896*5e7646d2SAndroid Build Coastguard Worker   if (cupsArrayUserData(a))
897*5e7646d2SAndroid Build Coastguard Worker     CFRelease((CFDictionaryRef)cupsArrayUserData(a));
898*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ && CUPS_BUNDLEDIR */
899*5e7646d2SAndroid Build Coastguard Worker 
900*5e7646d2SAndroid Build Coastguard Worker  /*
901*5e7646d2SAndroid Build Coastguard Worker   * Free the array...
902*5e7646d2SAndroid Build Coastguard Worker   */
903*5e7646d2SAndroid Build Coastguard Worker 
904*5e7646d2SAndroid Build Coastguard Worker   cupsArrayDelete(a);
905*5e7646d2SAndroid Build Coastguard Worker }
906*5e7646d2SAndroid Build Coastguard Worker 
907*5e7646d2SAndroid Build Coastguard Worker 
908*5e7646d2SAndroid Build Coastguard Worker /*
909*5e7646d2SAndroid Build Coastguard Worker  * '_cupsMessageLoad()' - Load a .po or .strings file into a messages array.
910*5e7646d2SAndroid Build Coastguard Worker  */
911*5e7646d2SAndroid Build Coastguard Worker 
912*5e7646d2SAndroid Build Coastguard Worker cups_array_t *				/* O - New message array */
_cupsMessageLoad(const char * filename,int flags)913*5e7646d2SAndroid Build Coastguard Worker _cupsMessageLoad(const char *filename,	/* I - Message catalog to load */
914*5e7646d2SAndroid Build Coastguard Worker                  int        flags)	/* I - Load flags */
915*5e7646d2SAndroid Build Coastguard Worker {
916*5e7646d2SAndroid Build Coastguard Worker   cups_file_t		*fp;		/* Message file */
917*5e7646d2SAndroid Build Coastguard Worker   cups_array_t		*a;		/* Message array */
918*5e7646d2SAndroid Build Coastguard Worker   _cups_message_t	*m;		/* Current message */
919*5e7646d2SAndroid Build Coastguard Worker   char			s[4096],	/* String buffer */
920*5e7646d2SAndroid Build Coastguard Worker 			*ptr,		/* Pointer into buffer */
921*5e7646d2SAndroid Build Coastguard Worker 			*temp;		/* New string */
922*5e7646d2SAndroid Build Coastguard Worker   size_t		length,		/* Length of combined strings */
923*5e7646d2SAndroid Build Coastguard Worker 			ptrlen;		/* Length of string */
924*5e7646d2SAndroid Build Coastguard Worker 
925*5e7646d2SAndroid Build Coastguard Worker 
926*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("4_cupsMessageLoad(filename=\"%s\")", filename));
927*5e7646d2SAndroid Build Coastguard Worker 
928*5e7646d2SAndroid Build Coastguard Worker  /*
929*5e7646d2SAndroid Build Coastguard Worker   * Create an array to hold the messages...
930*5e7646d2SAndroid Build Coastguard Worker   */
931*5e7646d2SAndroid Build Coastguard Worker 
932*5e7646d2SAndroid Build Coastguard Worker   if ((a = _cupsMessageNew(NULL)) == NULL)
933*5e7646d2SAndroid Build Coastguard Worker   {
934*5e7646d2SAndroid Build Coastguard Worker     DEBUG_puts("5_cupsMessageLoad: Unable to allocate array!");
935*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
936*5e7646d2SAndroid Build Coastguard Worker   }
937*5e7646d2SAndroid Build Coastguard Worker 
938*5e7646d2SAndroid Build Coastguard Worker  /*
939*5e7646d2SAndroid Build Coastguard Worker   * Open the message catalog file...
940*5e7646d2SAndroid Build Coastguard Worker   */
941*5e7646d2SAndroid Build Coastguard Worker 
942*5e7646d2SAndroid Build Coastguard Worker   if ((fp = cupsFileOpen(filename, "r")) == NULL)
943*5e7646d2SAndroid Build Coastguard Worker   {
944*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5_cupsMessageLoad: Unable to open file: %s",
945*5e7646d2SAndroid Build Coastguard Worker                   strerror(errno)));
946*5e7646d2SAndroid Build Coastguard Worker     return (a);
947*5e7646d2SAndroid Build Coastguard Worker   }
948*5e7646d2SAndroid Build Coastguard Worker 
949*5e7646d2SAndroid Build Coastguard Worker   if (flags & _CUPS_MESSAGE_STRINGS)
950*5e7646d2SAndroid Build Coastguard Worker   {
951*5e7646d2SAndroid Build Coastguard Worker     while (cups_read_strings(fp, flags, a));
952*5e7646d2SAndroid Build Coastguard Worker   }
953*5e7646d2SAndroid Build Coastguard Worker   else
954*5e7646d2SAndroid Build Coastguard Worker   {
955*5e7646d2SAndroid Build Coastguard Worker    /*
956*5e7646d2SAndroid Build Coastguard Worker     * Read messages from the catalog file until EOF...
957*5e7646d2SAndroid Build Coastguard Worker     *
958*5e7646d2SAndroid Build Coastguard Worker     * The format is the GNU gettext .po format, which is fairly simple:
959*5e7646d2SAndroid Build Coastguard Worker     *
960*5e7646d2SAndroid Build Coastguard Worker     *     msgid "some text"
961*5e7646d2SAndroid Build Coastguard Worker     *     msgstr "localized text"
962*5e7646d2SAndroid Build Coastguard Worker     *
963*5e7646d2SAndroid Build Coastguard Worker     * The ID and localized text can span multiple lines using the form:
964*5e7646d2SAndroid Build Coastguard Worker     *
965*5e7646d2SAndroid Build Coastguard Worker     *     msgid ""
966*5e7646d2SAndroid Build Coastguard Worker     *     "some long text"
967*5e7646d2SAndroid Build Coastguard Worker     *     msgstr ""
968*5e7646d2SAndroid Build Coastguard Worker     *     "localized text spanning "
969*5e7646d2SAndroid Build Coastguard Worker     *     "multiple lines"
970*5e7646d2SAndroid Build Coastguard Worker     */
971*5e7646d2SAndroid Build Coastguard Worker 
972*5e7646d2SAndroid Build Coastguard Worker     m = NULL;
973*5e7646d2SAndroid Build Coastguard Worker 
974*5e7646d2SAndroid Build Coastguard Worker     while (cupsFileGets(fp, s, sizeof(s)) != NULL)
975*5e7646d2SAndroid Build Coastguard Worker     {
976*5e7646d2SAndroid Build Coastguard Worker      /*
977*5e7646d2SAndroid Build Coastguard Worker       * Skip blank and comment lines...
978*5e7646d2SAndroid Build Coastguard Worker       */
979*5e7646d2SAndroid Build Coastguard Worker 
980*5e7646d2SAndroid Build Coastguard Worker       if (s[0] == '#' || !s[0])
981*5e7646d2SAndroid Build Coastguard Worker 	continue;
982*5e7646d2SAndroid Build Coastguard Worker 
983*5e7646d2SAndroid Build Coastguard Worker      /*
984*5e7646d2SAndroid Build Coastguard Worker       * Strip the trailing quote...
985*5e7646d2SAndroid Build Coastguard Worker       */
986*5e7646d2SAndroid Build Coastguard Worker 
987*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = strrchr(s, '\"')) == NULL)
988*5e7646d2SAndroid Build Coastguard Worker 	continue;
989*5e7646d2SAndroid Build Coastguard Worker 
990*5e7646d2SAndroid Build Coastguard Worker       *ptr = '\0';
991*5e7646d2SAndroid Build Coastguard Worker 
992*5e7646d2SAndroid Build Coastguard Worker      /*
993*5e7646d2SAndroid Build Coastguard Worker       * Find start of value...
994*5e7646d2SAndroid Build Coastguard Worker       */
995*5e7646d2SAndroid Build Coastguard Worker 
996*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = strchr(s, '\"')) == NULL)
997*5e7646d2SAndroid Build Coastguard Worker 	continue;
998*5e7646d2SAndroid Build Coastguard Worker 
999*5e7646d2SAndroid Build Coastguard Worker       ptr ++;
1000*5e7646d2SAndroid Build Coastguard Worker 
1001*5e7646d2SAndroid Build Coastguard Worker      /*
1002*5e7646d2SAndroid Build Coastguard Worker       * Unquote the text...
1003*5e7646d2SAndroid Build Coastguard Worker       */
1004*5e7646d2SAndroid Build Coastguard Worker 
1005*5e7646d2SAndroid Build Coastguard Worker       if (flags & _CUPS_MESSAGE_UNQUOTE)
1006*5e7646d2SAndroid Build Coastguard Worker 	cups_unquote(ptr, ptr);
1007*5e7646d2SAndroid Build Coastguard Worker 
1008*5e7646d2SAndroid Build Coastguard Worker      /*
1009*5e7646d2SAndroid Build Coastguard Worker       * Create or add to a message...
1010*5e7646d2SAndroid Build Coastguard Worker       */
1011*5e7646d2SAndroid Build Coastguard Worker 
1012*5e7646d2SAndroid Build Coastguard Worker       if (!strncmp(s, "msgid", 5))
1013*5e7646d2SAndroid Build Coastguard Worker       {
1014*5e7646d2SAndroid Build Coastguard Worker        /*
1015*5e7646d2SAndroid Build Coastguard Worker 	* Add previous message as needed...
1016*5e7646d2SAndroid Build Coastguard Worker 	*/
1017*5e7646d2SAndroid Build Coastguard Worker 
1018*5e7646d2SAndroid Build Coastguard Worker 	if (m)
1019*5e7646d2SAndroid Build Coastguard Worker 	{
1020*5e7646d2SAndroid Build Coastguard Worker 	  if (m->str && (m->str[0] || (flags & _CUPS_MESSAGE_EMPTY)))
1021*5e7646d2SAndroid Build Coastguard Worker 	  {
1022*5e7646d2SAndroid Build Coastguard Worker 	    cupsArrayAdd(a, m);
1023*5e7646d2SAndroid Build Coastguard Worker 	  }
1024*5e7646d2SAndroid Build Coastguard Worker 	  else
1025*5e7646d2SAndroid Build Coastguard Worker 	  {
1026*5e7646d2SAndroid Build Coastguard Worker 	   /*
1027*5e7646d2SAndroid Build Coastguard Worker 	    * Translation is empty, don't add it... (STR #4033)
1028*5e7646d2SAndroid Build Coastguard Worker 	    */
1029*5e7646d2SAndroid Build Coastguard Worker 
1030*5e7646d2SAndroid Build Coastguard Worker 	    free(m->msg);
1031*5e7646d2SAndroid Build Coastguard Worker 	    if (m->str)
1032*5e7646d2SAndroid Build Coastguard Worker 	      free(m->str);
1033*5e7646d2SAndroid Build Coastguard Worker 	    free(m);
1034*5e7646d2SAndroid Build Coastguard Worker 	  }
1035*5e7646d2SAndroid Build Coastguard Worker 	}
1036*5e7646d2SAndroid Build Coastguard Worker 
1037*5e7646d2SAndroid Build Coastguard Worker        /*
1038*5e7646d2SAndroid Build Coastguard Worker 	* Create a new message with the given msgid string...
1039*5e7646d2SAndroid Build Coastguard Worker 	*/
1040*5e7646d2SAndroid Build Coastguard Worker 
1041*5e7646d2SAndroid Build Coastguard Worker 	if ((m = (_cups_message_t *)calloc(1, sizeof(_cups_message_t))) == NULL)
1042*5e7646d2SAndroid Build Coastguard Worker 	  break;
1043*5e7646d2SAndroid Build Coastguard Worker 
1044*5e7646d2SAndroid Build Coastguard Worker 	if ((m->msg = strdup(ptr)) == NULL)
1045*5e7646d2SAndroid Build Coastguard Worker 	{
1046*5e7646d2SAndroid Build Coastguard Worker 	  free(m);
1047*5e7646d2SAndroid Build Coastguard Worker 	  m = NULL;
1048*5e7646d2SAndroid Build Coastguard Worker 	  break;
1049*5e7646d2SAndroid Build Coastguard Worker 	}
1050*5e7646d2SAndroid Build Coastguard Worker       }
1051*5e7646d2SAndroid Build Coastguard Worker       else if (s[0] == '\"' && m)
1052*5e7646d2SAndroid Build Coastguard Worker       {
1053*5e7646d2SAndroid Build Coastguard Worker        /*
1054*5e7646d2SAndroid Build Coastguard Worker 	* Append to current string...
1055*5e7646d2SAndroid Build Coastguard Worker 	*/
1056*5e7646d2SAndroid Build Coastguard Worker 
1057*5e7646d2SAndroid Build Coastguard Worker 	length = strlen(m->str ? m->str : m->msg);
1058*5e7646d2SAndroid Build Coastguard Worker 	ptrlen = strlen(ptr);
1059*5e7646d2SAndroid Build Coastguard Worker 
1060*5e7646d2SAndroid Build Coastguard Worker 	if ((temp = realloc(m->str ? m->str : m->msg, length + ptrlen + 1)) == NULL)
1061*5e7646d2SAndroid Build Coastguard Worker 	{
1062*5e7646d2SAndroid Build Coastguard Worker 	  if (m->str)
1063*5e7646d2SAndroid Build Coastguard Worker 	    free(m->str);
1064*5e7646d2SAndroid Build Coastguard Worker 	  free(m->msg);
1065*5e7646d2SAndroid Build Coastguard Worker 	  free(m);
1066*5e7646d2SAndroid Build Coastguard Worker 	  m = NULL;
1067*5e7646d2SAndroid Build Coastguard Worker 	  break;
1068*5e7646d2SAndroid Build Coastguard Worker 	}
1069*5e7646d2SAndroid Build Coastguard Worker 
1070*5e7646d2SAndroid Build Coastguard Worker 	if (m->str)
1071*5e7646d2SAndroid Build Coastguard Worker 	{
1072*5e7646d2SAndroid Build Coastguard Worker 	 /*
1073*5e7646d2SAndroid Build Coastguard Worker 	  * Copy the new portion to the end of the msgstr string - safe
1074*5e7646d2SAndroid Build Coastguard Worker 	  * to use memcpy because the buffer is allocated to the correct
1075*5e7646d2SAndroid Build Coastguard Worker 	  * size...
1076*5e7646d2SAndroid Build Coastguard Worker 	  */
1077*5e7646d2SAndroid Build Coastguard Worker 
1078*5e7646d2SAndroid Build Coastguard Worker 	  m->str = temp;
1079*5e7646d2SAndroid Build Coastguard Worker 
1080*5e7646d2SAndroid Build Coastguard Worker 	  memcpy(m->str + length, ptr, ptrlen + 1);
1081*5e7646d2SAndroid Build Coastguard Worker 	}
1082*5e7646d2SAndroid Build Coastguard Worker 	else
1083*5e7646d2SAndroid Build Coastguard Worker 	{
1084*5e7646d2SAndroid Build Coastguard Worker 	 /*
1085*5e7646d2SAndroid Build Coastguard Worker 	  * Copy the new portion to the end of the msgid string - safe
1086*5e7646d2SAndroid Build Coastguard Worker 	  * to use memcpy because the buffer is allocated to the correct
1087*5e7646d2SAndroid Build Coastguard Worker 	  * size...
1088*5e7646d2SAndroid Build Coastguard Worker 	  */
1089*5e7646d2SAndroid Build Coastguard Worker 
1090*5e7646d2SAndroid Build Coastguard Worker 	  m->msg = temp;
1091*5e7646d2SAndroid Build Coastguard Worker 
1092*5e7646d2SAndroid Build Coastguard Worker 	  memcpy(m->msg + length, ptr, ptrlen + 1);
1093*5e7646d2SAndroid Build Coastguard Worker 	}
1094*5e7646d2SAndroid Build Coastguard Worker       }
1095*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(s, "msgstr", 6) && m)
1096*5e7646d2SAndroid Build Coastguard Worker       {
1097*5e7646d2SAndroid Build Coastguard Worker        /*
1098*5e7646d2SAndroid Build Coastguard Worker 	* Set the string...
1099*5e7646d2SAndroid Build Coastguard Worker 	*/
1100*5e7646d2SAndroid Build Coastguard Worker 
1101*5e7646d2SAndroid Build Coastguard Worker 	if ((m->str = strdup(ptr)) == NULL)
1102*5e7646d2SAndroid Build Coastguard Worker 	{
1103*5e7646d2SAndroid Build Coastguard Worker 	  free(m->msg);
1104*5e7646d2SAndroid Build Coastguard Worker 	  free(m);
1105*5e7646d2SAndroid Build Coastguard Worker 	  m = NULL;
1106*5e7646d2SAndroid Build Coastguard Worker           break;
1107*5e7646d2SAndroid Build Coastguard Worker 	}
1108*5e7646d2SAndroid Build Coastguard Worker       }
1109*5e7646d2SAndroid Build Coastguard Worker     }
1110*5e7646d2SAndroid Build Coastguard Worker 
1111*5e7646d2SAndroid Build Coastguard Worker    /*
1112*5e7646d2SAndroid Build Coastguard Worker     * Add the last message string to the array as needed...
1113*5e7646d2SAndroid Build Coastguard Worker     */
1114*5e7646d2SAndroid Build Coastguard Worker 
1115*5e7646d2SAndroid Build Coastguard Worker     if (m)
1116*5e7646d2SAndroid Build Coastguard Worker     {
1117*5e7646d2SAndroid Build Coastguard Worker       if (m->str && (m->str[0] || (flags & _CUPS_MESSAGE_EMPTY)))
1118*5e7646d2SAndroid Build Coastguard Worker       {
1119*5e7646d2SAndroid Build Coastguard Worker 	cupsArrayAdd(a, m);
1120*5e7646d2SAndroid Build Coastguard Worker       }
1121*5e7646d2SAndroid Build Coastguard Worker       else
1122*5e7646d2SAndroid Build Coastguard Worker       {
1123*5e7646d2SAndroid Build Coastguard Worker        /*
1124*5e7646d2SAndroid Build Coastguard Worker 	* Translation is empty, don't add it... (STR #4033)
1125*5e7646d2SAndroid Build Coastguard Worker 	*/
1126*5e7646d2SAndroid Build Coastguard Worker 
1127*5e7646d2SAndroid Build Coastguard Worker 	free(m->msg);
1128*5e7646d2SAndroid Build Coastguard Worker 	if (m->str)
1129*5e7646d2SAndroid Build Coastguard Worker 	  free(m->str);
1130*5e7646d2SAndroid Build Coastguard Worker 	free(m);
1131*5e7646d2SAndroid Build Coastguard Worker       }
1132*5e7646d2SAndroid Build Coastguard Worker     }
1133*5e7646d2SAndroid Build Coastguard Worker   }
1134*5e7646d2SAndroid Build Coastguard Worker 
1135*5e7646d2SAndroid Build Coastguard Worker  /*
1136*5e7646d2SAndroid Build Coastguard Worker   * Close the message catalog file and return the new array...
1137*5e7646d2SAndroid Build Coastguard Worker   */
1138*5e7646d2SAndroid Build Coastguard Worker 
1139*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(fp);
1140*5e7646d2SAndroid Build Coastguard Worker 
1141*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("5_cupsMessageLoad: Returning %d messages...", cupsArrayCount(a)));
1142*5e7646d2SAndroid Build Coastguard Worker 
1143*5e7646d2SAndroid Build Coastguard Worker   return (a);
1144*5e7646d2SAndroid Build Coastguard Worker }
1145*5e7646d2SAndroid Build Coastguard Worker 
1146*5e7646d2SAndroid Build Coastguard Worker 
1147*5e7646d2SAndroid Build Coastguard Worker /*
1148*5e7646d2SAndroid Build Coastguard Worker  * '_cupsMessageLookup()' - Lookup a message string.
1149*5e7646d2SAndroid Build Coastguard Worker  */
1150*5e7646d2SAndroid Build Coastguard Worker 
1151*5e7646d2SAndroid Build Coastguard Worker const char *				/* O - Localized message */
_cupsMessageLookup(cups_array_t * a,const char * m)1152*5e7646d2SAndroid Build Coastguard Worker _cupsMessageLookup(cups_array_t *a,	/* I - Message array */
1153*5e7646d2SAndroid Build Coastguard Worker                    const char   *m)	/* I - Message */
1154*5e7646d2SAndroid Build Coastguard Worker {
1155*5e7646d2SAndroid Build Coastguard Worker   _cups_message_t	key,		/* Search key */
1156*5e7646d2SAndroid Build Coastguard Worker 			*match;		/* Matching message */
1157*5e7646d2SAndroid Build Coastguard Worker 
1158*5e7646d2SAndroid Build Coastguard Worker 
1159*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("_cupsMessageLookup(a=%p, m=\"%s\")", (void *)a, m));
1160*5e7646d2SAndroid Build Coastguard Worker 
1161*5e7646d2SAndroid Build Coastguard Worker  /*
1162*5e7646d2SAndroid Build Coastguard Worker   * Lookup the message string; if it doesn't exist in the catalog,
1163*5e7646d2SAndroid Build Coastguard Worker   * then return the message that was passed to us...
1164*5e7646d2SAndroid Build Coastguard Worker   */
1165*5e7646d2SAndroid Build Coastguard Worker 
1166*5e7646d2SAndroid Build Coastguard Worker   key.msg = (char *)m;
1167*5e7646d2SAndroid Build Coastguard Worker   match   = (_cups_message_t *)cupsArrayFind(a, &key);
1168*5e7646d2SAndroid Build Coastguard Worker 
1169*5e7646d2SAndroid Build Coastguard Worker #if defined(__APPLE__) && defined(CUPS_BUNDLEDIR)
1170*5e7646d2SAndroid Build Coastguard Worker   if (!match && cupsArrayUserData(a))
1171*5e7646d2SAndroid Build Coastguard Worker   {
1172*5e7646d2SAndroid Build Coastguard Worker    /*
1173*5e7646d2SAndroid Build Coastguard Worker     * Try looking the string up in the cups.strings dictionary...
1174*5e7646d2SAndroid Build Coastguard Worker     */
1175*5e7646d2SAndroid Build Coastguard Worker 
1176*5e7646d2SAndroid Build Coastguard Worker     CFDictionaryRef	dict;		/* cups.strings dictionary */
1177*5e7646d2SAndroid Build Coastguard Worker     CFStringRef		cfm,		/* Message as a CF string */
1178*5e7646d2SAndroid Build Coastguard Worker 			cfstr;		/* Localized text as a CF string */
1179*5e7646d2SAndroid Build Coastguard Worker 
1180*5e7646d2SAndroid Build Coastguard Worker     dict       = (CFDictionaryRef)cupsArrayUserData(a);
1181*5e7646d2SAndroid Build Coastguard Worker     cfm        = CFStringCreateWithCString(kCFAllocatorDefault, m, kCFStringEncodingUTF8);
1182*5e7646d2SAndroid Build Coastguard Worker     match      = calloc(1, sizeof(_cups_message_t));
1183*5e7646d2SAndroid Build Coastguard Worker     match->msg = strdup(m);
1184*5e7646d2SAndroid Build Coastguard Worker     cfstr      = cfm ? CFDictionaryGetValue(dict, cfm) : NULL;
1185*5e7646d2SAndroid Build Coastguard Worker 
1186*5e7646d2SAndroid Build Coastguard Worker     if (cfstr)
1187*5e7646d2SAndroid Build Coastguard Worker     {
1188*5e7646d2SAndroid Build Coastguard Worker       char	buffer[1024];		/* Message buffer */
1189*5e7646d2SAndroid Build Coastguard Worker 
1190*5e7646d2SAndroid Build Coastguard Worker       CFStringGetCString(cfstr, buffer, sizeof(buffer), kCFStringEncodingUTF8);
1191*5e7646d2SAndroid Build Coastguard Worker       match->str = strdup(buffer);
1192*5e7646d2SAndroid Build Coastguard Worker 
1193*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("1_cupsMessageLookup: Found \"%s\" as \"%s\"...", m, buffer));
1194*5e7646d2SAndroid Build Coastguard Worker     }
1195*5e7646d2SAndroid Build Coastguard Worker     else
1196*5e7646d2SAndroid Build Coastguard Worker     {
1197*5e7646d2SAndroid Build Coastguard Worker       match->str = strdup(m);
1198*5e7646d2SAndroid Build Coastguard Worker 
1199*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("1_cupsMessageLookup: Did not find \"%s\"...", m));
1200*5e7646d2SAndroid Build Coastguard Worker     }
1201*5e7646d2SAndroid Build Coastguard Worker 
1202*5e7646d2SAndroid Build Coastguard Worker     cupsArrayAdd(a, match);
1203*5e7646d2SAndroid Build Coastguard Worker 
1204*5e7646d2SAndroid Build Coastguard Worker     if (cfm)
1205*5e7646d2SAndroid Build Coastguard Worker       CFRelease(cfm);
1206*5e7646d2SAndroid Build Coastguard Worker   }
1207*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ && CUPS_BUNDLEDIR */
1208*5e7646d2SAndroid Build Coastguard Worker 
1209*5e7646d2SAndroid Build Coastguard Worker   if (match && match->str)
1210*5e7646d2SAndroid Build Coastguard Worker     return (match->str);
1211*5e7646d2SAndroid Build Coastguard Worker   else
1212*5e7646d2SAndroid Build Coastguard Worker     return (m);
1213*5e7646d2SAndroid Build Coastguard Worker }
1214*5e7646d2SAndroid Build Coastguard Worker 
1215*5e7646d2SAndroid Build Coastguard Worker 
1216*5e7646d2SAndroid Build Coastguard Worker /*
1217*5e7646d2SAndroid Build Coastguard Worker  * '_cupsMessageNew()' - Make a new message catalog array.
1218*5e7646d2SAndroid Build Coastguard Worker  */
1219*5e7646d2SAndroid Build Coastguard Worker 
1220*5e7646d2SAndroid Build Coastguard Worker cups_array_t *				/* O - Array */
_cupsMessageNew(void * context)1221*5e7646d2SAndroid Build Coastguard Worker _cupsMessageNew(void *context)		/* I - User data */
1222*5e7646d2SAndroid Build Coastguard Worker {
1223*5e7646d2SAndroid Build Coastguard Worker   return (cupsArrayNew3((cups_array_func_t)cups_message_compare, context,
1224*5e7646d2SAndroid Build Coastguard Worker                         (cups_ahash_func_t)NULL, 0,
1225*5e7646d2SAndroid Build Coastguard Worker 			(cups_acopy_func_t)NULL,
1226*5e7646d2SAndroid Build Coastguard Worker 			(cups_afree_func_t)cups_message_free));
1227*5e7646d2SAndroid Build Coastguard Worker }
1228*5e7646d2SAndroid Build Coastguard Worker 
1229*5e7646d2SAndroid Build Coastguard Worker 
1230*5e7646d2SAndroid Build Coastguard Worker /*
1231*5e7646d2SAndroid Build Coastguard Worker  * '_cupsMessageSave()' - Save a message catalog array.
1232*5e7646d2SAndroid Build Coastguard Worker  */
1233*5e7646d2SAndroid Build Coastguard Worker 
1234*5e7646d2SAndroid Build Coastguard Worker int					/* O - 0 on success, -1 on failure */
_cupsMessageSave(const char * filename,int flags,cups_array_t * a)1235*5e7646d2SAndroid Build Coastguard Worker _cupsMessageSave(const char   *filename,/* I - Output filename */
1236*5e7646d2SAndroid Build Coastguard Worker                  int          flags,	/* I - Format flags */
1237*5e7646d2SAndroid Build Coastguard Worker                  cups_array_t *a)	/* I - Message array */
1238*5e7646d2SAndroid Build Coastguard Worker {
1239*5e7646d2SAndroid Build Coastguard Worker   cups_file_t		*fp;		/* Output file */
1240*5e7646d2SAndroid Build Coastguard Worker   _cups_message_t	*m;		/* Current message */
1241*5e7646d2SAndroid Build Coastguard Worker 
1242*5e7646d2SAndroid Build Coastguard Worker 
1243*5e7646d2SAndroid Build Coastguard Worker  /*
1244*5e7646d2SAndroid Build Coastguard Worker   * Output message catalog file...
1245*5e7646d2SAndroid Build Coastguard Worker   */
1246*5e7646d2SAndroid Build Coastguard Worker 
1247*5e7646d2SAndroid Build Coastguard Worker   if ((fp = cupsFileOpen(filename, "w")) == NULL)
1248*5e7646d2SAndroid Build Coastguard Worker     return (-1);
1249*5e7646d2SAndroid Build Coastguard Worker 
1250*5e7646d2SAndroid Build Coastguard Worker  /*
1251*5e7646d2SAndroid Build Coastguard Worker   * Write each message...
1252*5e7646d2SAndroid Build Coastguard Worker   */
1253*5e7646d2SAndroid Build Coastguard Worker 
1254*5e7646d2SAndroid Build Coastguard Worker   if (flags & _CUPS_MESSAGE_STRINGS)
1255*5e7646d2SAndroid Build Coastguard Worker   {
1256*5e7646d2SAndroid Build Coastguard Worker     for (m = (_cups_message_t *)cupsArrayFirst(a); m; m = (_cups_message_t *)cupsArrayNext(a))
1257*5e7646d2SAndroid Build Coastguard Worker     {
1258*5e7646d2SAndroid Build Coastguard Worker       cupsFilePuts(fp, "\"");
1259*5e7646d2SAndroid Build Coastguard Worker       cups_message_puts(fp, m->msg);
1260*5e7646d2SAndroid Build Coastguard Worker       cupsFilePuts(fp, "\" = \"");
1261*5e7646d2SAndroid Build Coastguard Worker       cups_message_puts(fp, m->str);
1262*5e7646d2SAndroid Build Coastguard Worker       cupsFilePuts(fp, "\";\n");
1263*5e7646d2SAndroid Build Coastguard Worker     }
1264*5e7646d2SAndroid Build Coastguard Worker   }
1265*5e7646d2SAndroid Build Coastguard Worker   else
1266*5e7646d2SAndroid Build Coastguard Worker   {
1267*5e7646d2SAndroid Build Coastguard Worker     for (m = (_cups_message_t *)cupsArrayFirst(a); m; m = (_cups_message_t *)cupsArrayNext(a))
1268*5e7646d2SAndroid Build Coastguard Worker     {
1269*5e7646d2SAndroid Build Coastguard Worker       cupsFilePuts(fp, "msgid \"");
1270*5e7646d2SAndroid Build Coastguard Worker       cups_message_puts(fp, m->msg);
1271*5e7646d2SAndroid Build Coastguard Worker       cupsFilePuts(fp, "\"\nmsgstr \"");
1272*5e7646d2SAndroid Build Coastguard Worker       cups_message_puts(fp, m->str);
1273*5e7646d2SAndroid Build Coastguard Worker       cupsFilePuts(fp, "\"\n");
1274*5e7646d2SAndroid Build Coastguard Worker     }
1275*5e7646d2SAndroid Build Coastguard Worker   }
1276*5e7646d2SAndroid Build Coastguard Worker 
1277*5e7646d2SAndroid Build Coastguard Worker   return (cupsFileClose(fp));
1278*5e7646d2SAndroid Build Coastguard Worker }
1279*5e7646d2SAndroid Build Coastguard Worker 
1280*5e7646d2SAndroid Build Coastguard Worker 
1281*5e7646d2SAndroid Build Coastguard Worker #ifdef __APPLE__
1282*5e7646d2SAndroid Build Coastguard Worker /*
1283*5e7646d2SAndroid Build Coastguard Worker  * 'appleLangDefault()' - Get the default locale string.
1284*5e7646d2SAndroid Build Coastguard Worker  */
1285*5e7646d2SAndroid Build Coastguard Worker 
1286*5e7646d2SAndroid Build Coastguard Worker static const char *			/* O - Locale string */
appleLangDefault(void)1287*5e7646d2SAndroid Build Coastguard Worker appleLangDefault(void)
1288*5e7646d2SAndroid Build Coastguard Worker {
1289*5e7646d2SAndroid Build Coastguard Worker   CFBundleRef		bundle;		/* Main bundle (if any) */
1290*5e7646d2SAndroid Build Coastguard Worker   CFArrayRef		bundleList;	/* List of localizations in bundle */
1291*5e7646d2SAndroid Build Coastguard Worker   CFPropertyListRef 	localizationList = NULL;
1292*5e7646d2SAndroid Build Coastguard Worker 					/* List of localization data */
1293*5e7646d2SAndroid Build Coastguard Worker   CFStringRef		languageName;	/* Current name */
1294*5e7646d2SAndroid Build Coastguard Worker   char			*lang;		/* LANG environment variable */
1295*5e7646d2SAndroid Build Coastguard Worker   _cups_globals_t	*cg = _cupsGlobals();
1296*5e7646d2SAndroid Build Coastguard Worker   					/* Pointer to library globals */
1297*5e7646d2SAndroid Build Coastguard Worker 
1298*5e7646d2SAndroid Build Coastguard Worker 
1299*5e7646d2SAndroid Build Coastguard Worker   DEBUG_puts("2appleLangDefault()");
1300*5e7646d2SAndroid Build Coastguard Worker 
1301*5e7646d2SAndroid Build Coastguard Worker  /*
1302*5e7646d2SAndroid Build Coastguard Worker   * Only do the lookup and translation the first time.
1303*5e7646d2SAndroid Build Coastguard Worker   */
1304*5e7646d2SAndroid Build Coastguard Worker 
1305*5e7646d2SAndroid Build Coastguard Worker   if (!cg->language[0])
1306*5e7646d2SAndroid Build Coastguard Worker   {
1307*5e7646d2SAndroid Build Coastguard Worker     if (getenv("SOFTWARE") != NULL && (lang = getenv("LANG")) != NULL)
1308*5e7646d2SAndroid Build Coastguard Worker     {
1309*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("3appleLangDefault: Using LANG=%s", lang));
1310*5e7646d2SAndroid Build Coastguard Worker       strlcpy(cg->language, lang, sizeof(cg->language));
1311*5e7646d2SAndroid Build Coastguard Worker       return (cg->language);
1312*5e7646d2SAndroid Build Coastguard Worker     }
1313*5e7646d2SAndroid Build Coastguard Worker     else if ((bundle = CFBundleGetMainBundle()) != NULL &&
1314*5e7646d2SAndroid Build Coastguard Worker              (bundleList = CFBundleCopyBundleLocalizations(bundle)) != NULL)
1315*5e7646d2SAndroid Build Coastguard Worker     {
1316*5e7646d2SAndroid Build Coastguard Worker       CFURLRef resources = CFBundleCopyResourcesDirectoryURL(bundle);
1317*5e7646d2SAndroid Build Coastguard Worker 
1318*5e7646d2SAndroid Build Coastguard Worker       DEBUG_puts("3appleLangDefault: Getting localizationList from bundle.");
1319*5e7646d2SAndroid Build Coastguard Worker 
1320*5e7646d2SAndroid Build Coastguard Worker       if (resources)
1321*5e7646d2SAndroid Build Coastguard Worker       {
1322*5e7646d2SAndroid Build Coastguard Worker         CFStringRef	cfpath = CFURLCopyPath(resources);
1323*5e7646d2SAndroid Build Coastguard Worker 	char		path[1024];
1324*5e7646d2SAndroid Build Coastguard Worker 
1325*5e7646d2SAndroid Build Coastguard Worker         if (cfpath)
1326*5e7646d2SAndroid Build Coastguard Worker 	{
1327*5e7646d2SAndroid Build Coastguard Worker 	 /*
1328*5e7646d2SAndroid Build Coastguard Worker 	  * See if we have an Info.plist file in the bundle...
1329*5e7646d2SAndroid Build Coastguard Worker 	  */
1330*5e7646d2SAndroid Build Coastguard Worker 
1331*5e7646d2SAndroid Build Coastguard Worker 	  CFStringGetCString(cfpath, path, sizeof(path), kCFStringEncodingUTF8);
1332*5e7646d2SAndroid Build Coastguard Worker 	  DEBUG_printf(("3appleLangDefault: Got a resource URL (\"%s\")", path));
1333*5e7646d2SAndroid Build Coastguard Worker 	  strlcat(path, "Contents/Info.plist", sizeof(path));
1334*5e7646d2SAndroid Build Coastguard Worker 
1335*5e7646d2SAndroid Build Coastguard Worker           if (!access(path, R_OK))
1336*5e7646d2SAndroid Build Coastguard Worker 	    localizationList = CFBundleCopyPreferredLocalizationsFromArray(bundleList);
1337*5e7646d2SAndroid Build Coastguard Worker 	  else
1338*5e7646d2SAndroid Build Coastguard Worker 	    DEBUG_puts("3appleLangDefault: No Info.plist, ignoring resource URL...");
1339*5e7646d2SAndroid Build Coastguard Worker 
1340*5e7646d2SAndroid Build Coastguard Worker 	  CFRelease(cfpath);
1341*5e7646d2SAndroid Build Coastguard Worker 	}
1342*5e7646d2SAndroid Build Coastguard Worker 
1343*5e7646d2SAndroid Build Coastguard Worker 	CFRelease(resources);
1344*5e7646d2SAndroid Build Coastguard Worker       }
1345*5e7646d2SAndroid Build Coastguard Worker       else
1346*5e7646d2SAndroid Build Coastguard Worker         DEBUG_puts("3appleLangDefault: No resource URL.");
1347*5e7646d2SAndroid Build Coastguard Worker 
1348*5e7646d2SAndroid Build Coastguard Worker       CFRelease(bundleList);
1349*5e7646d2SAndroid Build Coastguard Worker     }
1350*5e7646d2SAndroid Build Coastguard Worker 
1351*5e7646d2SAndroid Build Coastguard Worker     if (!localizationList)
1352*5e7646d2SAndroid Build Coastguard Worker     {
1353*5e7646d2SAndroid Build Coastguard Worker       DEBUG_puts("3appleLangDefault: Getting localizationList from preferences.");
1354*5e7646d2SAndroid Build Coastguard Worker 
1355*5e7646d2SAndroid Build Coastguard Worker       localizationList =
1356*5e7646d2SAndroid Build Coastguard Worker 	  CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
1357*5e7646d2SAndroid Build Coastguard Worker 				    kCFPreferencesCurrentApplication);
1358*5e7646d2SAndroid Build Coastguard Worker     }
1359*5e7646d2SAndroid Build Coastguard Worker 
1360*5e7646d2SAndroid Build Coastguard Worker     if (localizationList)
1361*5e7646d2SAndroid Build Coastguard Worker     {
1362*5e7646d2SAndroid Build Coastguard Worker #ifdef DEBUG
1363*5e7646d2SAndroid Build Coastguard Worker       if (CFGetTypeID(localizationList) == CFArrayGetTypeID())
1364*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("3appleLangDefault: Got localizationList, %d entries.",
1365*5e7646d2SAndroid Build Coastguard Worker                       (int)CFArrayGetCount(localizationList)));
1366*5e7646d2SAndroid Build Coastguard Worker       else
1367*5e7646d2SAndroid Build Coastguard Worker         DEBUG_puts("3appleLangDefault: Got localizationList but not an array.");
1368*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG */
1369*5e7646d2SAndroid Build Coastguard Worker 
1370*5e7646d2SAndroid Build Coastguard Worker       if (CFGetTypeID(localizationList) == CFArrayGetTypeID() &&
1371*5e7646d2SAndroid Build Coastguard Worker 	  CFArrayGetCount(localizationList) > 0)
1372*5e7646d2SAndroid Build Coastguard Worker       {
1373*5e7646d2SAndroid Build Coastguard Worker 	languageName = CFArrayGetValueAtIndex(localizationList, 0);
1374*5e7646d2SAndroid Build Coastguard Worker 
1375*5e7646d2SAndroid Build Coastguard Worker 	if (languageName &&
1376*5e7646d2SAndroid Build Coastguard Worker 	    CFGetTypeID(languageName) == CFStringGetTypeID())
1377*5e7646d2SAndroid Build Coastguard Worker 	{
1378*5e7646d2SAndroid Build Coastguard Worker 	  if (_cupsAppleLocale(languageName, cg->language, sizeof(cg->language)))
1379*5e7646d2SAndroid Build Coastguard Worker 	    DEBUG_printf(("3appleLangDefault: cg->language=\"%s\"",
1380*5e7646d2SAndroid Build Coastguard Worker 			  cg->language));
1381*5e7646d2SAndroid Build Coastguard Worker 	  else
1382*5e7646d2SAndroid Build Coastguard Worker 	    DEBUG_puts("3appleLangDefault: Unable to get locale.");
1383*5e7646d2SAndroid Build Coastguard Worker 	}
1384*5e7646d2SAndroid Build Coastguard Worker       }
1385*5e7646d2SAndroid Build Coastguard Worker 
1386*5e7646d2SAndroid Build Coastguard Worker       CFRelease(localizationList);
1387*5e7646d2SAndroid Build Coastguard Worker     }
1388*5e7646d2SAndroid Build Coastguard Worker 
1389*5e7646d2SAndroid Build Coastguard Worker    /*
1390*5e7646d2SAndroid Build Coastguard Worker     * If we didn't find the language, default to en_US...
1391*5e7646d2SAndroid Build Coastguard Worker     */
1392*5e7646d2SAndroid Build Coastguard Worker 
1393*5e7646d2SAndroid Build Coastguard Worker     if (!cg->language[0])
1394*5e7646d2SAndroid Build Coastguard Worker     {
1395*5e7646d2SAndroid Build Coastguard Worker       DEBUG_puts("3appleLangDefault: Defaulting to en_US.");
1396*5e7646d2SAndroid Build Coastguard Worker       strlcpy(cg->language, "en_US.UTF-8", sizeof(cg->language));
1397*5e7646d2SAndroid Build Coastguard Worker     }
1398*5e7646d2SAndroid Build Coastguard Worker   }
1399*5e7646d2SAndroid Build Coastguard Worker   else
1400*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("3appleLangDefault: Using previous locale \"%s\".", cg->language));
1401*5e7646d2SAndroid Build Coastguard Worker 
1402*5e7646d2SAndroid Build Coastguard Worker  /*
1403*5e7646d2SAndroid Build Coastguard Worker   * Return the cached locale...
1404*5e7646d2SAndroid Build Coastguard Worker   */
1405*5e7646d2SAndroid Build Coastguard Worker 
1406*5e7646d2SAndroid Build Coastguard Worker   return (cg->language);
1407*5e7646d2SAndroid Build Coastguard Worker }
1408*5e7646d2SAndroid Build Coastguard Worker 
1409*5e7646d2SAndroid Build Coastguard Worker 
1410*5e7646d2SAndroid Build Coastguard Worker #  ifdef CUPS_BUNDLEDIR
1411*5e7646d2SAndroid Build Coastguard Worker /*
1412*5e7646d2SAndroid Build Coastguard Worker  * 'appleMessageLoad()' - Load a message catalog from a localizable bundle.
1413*5e7646d2SAndroid Build Coastguard Worker  */
1414*5e7646d2SAndroid Build Coastguard Worker 
1415*5e7646d2SAndroid Build Coastguard Worker static cups_array_t *			/* O - Message catalog */
appleMessageLoad(const char * locale)1416*5e7646d2SAndroid Build Coastguard Worker appleMessageLoad(const char *locale)	/* I - Locale ID */
1417*5e7646d2SAndroid Build Coastguard Worker {
1418*5e7646d2SAndroid Build Coastguard Worker   char			filename[1024],	/* Path to cups.strings file */
1419*5e7646d2SAndroid Build Coastguard Worker 			applelang[256],	/* Apple language ID */
1420*5e7646d2SAndroid Build Coastguard Worker 			baselang[4];	/* Base language */
1421*5e7646d2SAndroid Build Coastguard Worker   CFURLRef		url;		/* URL to cups.strings file */
1422*5e7646d2SAndroid Build Coastguard Worker   CFReadStreamRef	stream = NULL;	/* File stream */
1423*5e7646d2SAndroid Build Coastguard Worker   CFPropertyListRef	plist = NULL;	/* Localization file */
1424*5e7646d2SAndroid Build Coastguard Worker #ifdef DEBUG
1425*5e7646d2SAndroid Build Coastguard Worker   const char            *cups_strings = getenv("CUPS_STRINGS");
1426*5e7646d2SAndroid Build Coastguard Worker                                         /* Test strings file */
1427*5e7646d2SAndroid Build Coastguard Worker   CFErrorRef		error = NULL;	/* Error when opening file */
1428*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG */
1429*5e7646d2SAndroid Build Coastguard Worker 
1430*5e7646d2SAndroid Build Coastguard Worker 
1431*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("appleMessageLoad(locale=\"%s\")", locale));
1432*5e7646d2SAndroid Build Coastguard Worker 
1433*5e7646d2SAndroid Build Coastguard Worker  /*
1434*5e7646d2SAndroid Build Coastguard Worker   * Load the cups.strings file...
1435*5e7646d2SAndroid Build Coastguard Worker   */
1436*5e7646d2SAndroid Build Coastguard Worker 
1437*5e7646d2SAndroid Build Coastguard Worker #ifdef DEBUG
1438*5e7646d2SAndroid Build Coastguard Worker   if (cups_strings)
1439*5e7646d2SAndroid Build Coastguard Worker   {
1440*5e7646d2SAndroid Build Coastguard Worker     DEBUG_puts("1appleMessageLoad: Using debug CUPS_STRINGS file.");
1441*5e7646d2SAndroid Build Coastguard Worker     strlcpy(filename, cups_strings, sizeof(filename));
1442*5e7646d2SAndroid Build Coastguard Worker   }
1443*5e7646d2SAndroid Build Coastguard Worker   else
1444*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG */
1445*5e7646d2SAndroid Build Coastguard Worker 
1446*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename),
1447*5e7646d2SAndroid Build Coastguard Worker            CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings",
1448*5e7646d2SAndroid Build Coastguard Worker 	   _cupsAppleLanguage(locale, applelang, sizeof(applelang)));
1449*5e7646d2SAndroid Build Coastguard Worker 
1450*5e7646d2SAndroid Build Coastguard Worker   if (access(filename, 0))
1451*5e7646d2SAndroid Build Coastguard Worker   {
1452*5e7646d2SAndroid Build Coastguard Worker    /*
1453*5e7646d2SAndroid Build Coastguard Worker     * <rdar://problem/22086642>
1454*5e7646d2SAndroid Build Coastguard Worker     *
1455*5e7646d2SAndroid Build Coastguard Worker     * Try with original locale string...
1456*5e7646d2SAndroid Build Coastguard Worker     */
1457*5e7646d2SAndroid Build Coastguard Worker 
1458*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1appleMessageLoad: \"%s\": %s", filename, strerror(errno)));
1459*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", locale);
1460*5e7646d2SAndroid Build Coastguard Worker   }
1461*5e7646d2SAndroid Build Coastguard Worker 
1462*5e7646d2SAndroid Build Coastguard Worker   if (access(filename, 0))
1463*5e7646d2SAndroid Build Coastguard Worker   {
1464*5e7646d2SAndroid Build Coastguard Worker    /*
1465*5e7646d2SAndroid Build Coastguard Worker     * <rdar://problem/25292403>
1466*5e7646d2SAndroid Build Coastguard Worker     *
1467*5e7646d2SAndroid Build Coastguard Worker     * Try with just the language code...
1468*5e7646d2SAndroid Build Coastguard Worker     */
1469*5e7646d2SAndroid Build Coastguard Worker 
1470*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1appleMessageLoad: \"%s\": %s", filename, strerror(errno)));
1471*5e7646d2SAndroid Build Coastguard Worker 
1472*5e7646d2SAndroid Build Coastguard Worker     strlcpy(baselang, locale, sizeof(baselang));
1473*5e7646d2SAndroid Build Coastguard Worker     if (baselang[3] == '-' || baselang[3] == '_')
1474*5e7646d2SAndroid Build Coastguard Worker       baselang[3] = '\0';
1475*5e7646d2SAndroid Build Coastguard Worker 
1476*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", baselang);
1477*5e7646d2SAndroid Build Coastguard Worker   }
1478*5e7646d2SAndroid Build Coastguard Worker 
1479*5e7646d2SAndroid Build Coastguard Worker   if (access(filename, 0))
1480*5e7646d2SAndroid Build Coastguard Worker   {
1481*5e7646d2SAndroid Build Coastguard Worker    /*
1482*5e7646d2SAndroid Build Coastguard Worker     * Try alternate lproj directory names...
1483*5e7646d2SAndroid Build Coastguard Worker     */
1484*5e7646d2SAndroid Build Coastguard Worker 
1485*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("1appleMessageLoad: \"%s\": %s", filename, strerror(errno)));
1486*5e7646d2SAndroid Build Coastguard Worker 
1487*5e7646d2SAndroid Build Coastguard Worker     if (!strncmp(locale, "en", 2))
1488*5e7646d2SAndroid Build Coastguard Worker       locale = "English";
1489*5e7646d2SAndroid Build Coastguard Worker     else if (!strncmp(locale, "nb", 2))
1490*5e7646d2SAndroid Build Coastguard Worker       locale = "no";
1491*5e7646d2SAndroid Build Coastguard Worker     else if (!strncmp(locale, "nl", 2))
1492*5e7646d2SAndroid Build Coastguard Worker       locale = "Dutch";
1493*5e7646d2SAndroid Build Coastguard Worker     else if (!strncmp(locale, "fr", 2))
1494*5e7646d2SAndroid Build Coastguard Worker       locale = "French";
1495*5e7646d2SAndroid Build Coastguard Worker     else if (!strncmp(locale, "de", 2))
1496*5e7646d2SAndroid Build Coastguard Worker       locale = "German";
1497*5e7646d2SAndroid Build Coastguard Worker     else if (!strncmp(locale, "it", 2))
1498*5e7646d2SAndroid Build Coastguard Worker       locale = "Italian";
1499*5e7646d2SAndroid Build Coastguard Worker     else if (!strncmp(locale, "ja", 2))
1500*5e7646d2SAndroid Build Coastguard Worker       locale = "Japanese";
1501*5e7646d2SAndroid Build Coastguard Worker     else if (!strncmp(locale, "es", 2))
1502*5e7646d2SAndroid Build Coastguard Worker       locale = "Spanish";
1503*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(locale, "zh_HK") || !strncasecmp(locale, "zh-Hant", 7) || !strncasecmp(locale, "zh_Hant", 7))
1504*5e7646d2SAndroid Build Coastguard Worker     {
1505*5e7646d2SAndroid Build Coastguard Worker      /*
1506*5e7646d2SAndroid Build Coastguard Worker       * <rdar://problem/22130168>
1507*5e7646d2SAndroid Build Coastguard Worker       * <rdar://problem/27245567>
1508*5e7646d2SAndroid Build Coastguard Worker       *
1509*5e7646d2SAndroid Build Coastguard Worker       * Try zh_TW first, then zh...  Sigh...
1510*5e7646d2SAndroid Build Coastguard Worker       */
1511*5e7646d2SAndroid Build Coastguard Worker 
1512*5e7646d2SAndroid Build Coastguard Worker       if (!access(CUPS_BUNDLEDIR "/Resources/zh_TW.lproj/cups.strings", 0))
1513*5e7646d2SAndroid Build Coastguard Worker         locale = "zh_TW";
1514*5e7646d2SAndroid Build Coastguard Worker       else
1515*5e7646d2SAndroid Build Coastguard Worker         locale = "zh";
1516*5e7646d2SAndroid Build Coastguard Worker     }
1517*5e7646d2SAndroid Build Coastguard Worker     else if (strstr(locale, "_") != NULL || strstr(locale, "-") != NULL)
1518*5e7646d2SAndroid Build Coastguard Worker     {
1519*5e7646d2SAndroid Build Coastguard Worker      /*
1520*5e7646d2SAndroid Build Coastguard Worker       * Drop country code, just try language...
1521*5e7646d2SAndroid Build Coastguard Worker       */
1522*5e7646d2SAndroid Build Coastguard Worker 
1523*5e7646d2SAndroid Build Coastguard Worker       strlcpy(baselang, locale, sizeof(baselang));
1524*5e7646d2SAndroid Build Coastguard Worker       if (baselang[2] == '-' || baselang[2] == '_')
1525*5e7646d2SAndroid Build Coastguard Worker         baselang[2] = '\0';
1526*5e7646d2SAndroid Build Coastguard Worker 
1527*5e7646d2SAndroid Build Coastguard Worker       locale = baselang;
1528*5e7646d2SAndroid Build Coastguard Worker     }
1529*5e7646d2SAndroid Build Coastguard Worker 
1530*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, sizeof(filename),
1531*5e7646d2SAndroid Build Coastguard Worker 	     CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", locale);
1532*5e7646d2SAndroid Build Coastguard Worker   }
1533*5e7646d2SAndroid Build Coastguard Worker 
1534*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("1appleMessageLoad: filename=\"%s\"", filename));
1535*5e7646d2SAndroid Build Coastguard Worker 
1536*5e7646d2SAndroid Build Coastguard Worker   url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
1537*5e7646d2SAndroid Build Coastguard Worker                                                 (UInt8 *)filename,
1538*5e7646d2SAndroid Build Coastguard Worker 						(CFIndex)strlen(filename), false);
1539*5e7646d2SAndroid Build Coastguard Worker   if (url)
1540*5e7646d2SAndroid Build Coastguard Worker   {
1541*5e7646d2SAndroid Build Coastguard Worker     stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
1542*5e7646d2SAndroid Build Coastguard Worker     if (stream)
1543*5e7646d2SAndroid Build Coastguard Worker     {
1544*5e7646d2SAndroid Build Coastguard Worker      /*
1545*5e7646d2SAndroid Build Coastguard Worker       * Read the property list containing the localization data.
1546*5e7646d2SAndroid Build Coastguard Worker       *
1547*5e7646d2SAndroid Build Coastguard Worker       * NOTE: This code currently generates a clang "potential leak"
1548*5e7646d2SAndroid Build Coastguard Worker       * warning, but the object is released in _cupsMessageFree().
1549*5e7646d2SAndroid Build Coastguard Worker       */
1550*5e7646d2SAndroid Build Coastguard Worker 
1551*5e7646d2SAndroid Build Coastguard Worker       CFReadStreamOpen(stream);
1552*5e7646d2SAndroid Build Coastguard Worker 
1553*5e7646d2SAndroid Build Coastguard Worker #ifdef DEBUG
1554*5e7646d2SAndroid Build Coastguard Worker       plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, stream, 0,
1555*5e7646d2SAndroid Build Coastguard Worker                                              kCFPropertyListImmutable, NULL,
1556*5e7646d2SAndroid Build Coastguard Worker                                              &error);
1557*5e7646d2SAndroid Build Coastguard Worker       if (error)
1558*5e7646d2SAndroid Build Coastguard Worker       {
1559*5e7646d2SAndroid Build Coastguard Worker         CFStringRef	msg = CFErrorCopyDescription(error);
1560*5e7646d2SAndroid Build Coastguard Worker     					/* Error message */
1561*5e7646d2SAndroid Build Coastguard Worker 
1562*5e7646d2SAndroid Build Coastguard Worker         CFStringGetCString(msg, filename, sizeof(filename),
1563*5e7646d2SAndroid Build Coastguard Worker                            kCFStringEncodingUTF8);
1564*5e7646d2SAndroid Build Coastguard Worker         DEBUG_printf(("1appleMessageLoad: %s", filename));
1565*5e7646d2SAndroid Build Coastguard Worker 
1566*5e7646d2SAndroid Build Coastguard Worker 	CFRelease(msg);
1567*5e7646d2SAndroid Build Coastguard Worker         CFRelease(error);
1568*5e7646d2SAndroid Build Coastguard Worker       }
1569*5e7646d2SAndroid Build Coastguard Worker 
1570*5e7646d2SAndroid Build Coastguard Worker #else
1571*5e7646d2SAndroid Build Coastguard Worker       plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, stream, 0,
1572*5e7646d2SAndroid Build Coastguard Worker                                              kCFPropertyListImmutable, NULL,
1573*5e7646d2SAndroid Build Coastguard Worker                                              NULL);
1574*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG */
1575*5e7646d2SAndroid Build Coastguard Worker 
1576*5e7646d2SAndroid Build Coastguard Worker       if (plist && CFGetTypeID(plist) != CFDictionaryGetTypeID())
1577*5e7646d2SAndroid Build Coastguard Worker       {
1578*5e7646d2SAndroid Build Coastguard Worker          CFRelease(plist);
1579*5e7646d2SAndroid Build Coastguard Worker          plist = NULL;
1580*5e7646d2SAndroid Build Coastguard Worker       }
1581*5e7646d2SAndroid Build Coastguard Worker 
1582*5e7646d2SAndroid Build Coastguard Worker       CFRelease(stream);
1583*5e7646d2SAndroid Build Coastguard Worker     }
1584*5e7646d2SAndroid Build Coastguard Worker 
1585*5e7646d2SAndroid Build Coastguard Worker     CFRelease(url);
1586*5e7646d2SAndroid Build Coastguard Worker   }
1587*5e7646d2SAndroid Build Coastguard Worker 
1588*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("1appleMessageLoad: url=%p, stream=%p, plist=%p", url, stream,
1589*5e7646d2SAndroid Build Coastguard Worker                 plist));
1590*5e7646d2SAndroid Build Coastguard Worker 
1591*5e7646d2SAndroid Build Coastguard Worker  /*
1592*5e7646d2SAndroid Build Coastguard Worker   * Create and return an empty array to act as a cache for messages, passing the
1593*5e7646d2SAndroid Build Coastguard Worker   * plist as the user data.
1594*5e7646d2SAndroid Build Coastguard Worker   */
1595*5e7646d2SAndroid Build Coastguard Worker 
1596*5e7646d2SAndroid Build Coastguard Worker   return (_cupsMessageNew((void *)plist));
1597*5e7646d2SAndroid Build Coastguard Worker }
1598*5e7646d2SAndroid Build Coastguard Worker #  endif /* CUPS_BUNDLEDIR */
1599*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ */
1600*5e7646d2SAndroid Build Coastguard Worker 
1601*5e7646d2SAndroid Build Coastguard Worker 
1602*5e7646d2SAndroid Build Coastguard Worker /*
1603*5e7646d2SAndroid Build Coastguard Worker  * 'cups_cache_lookup()' - Lookup a language in the cache...
1604*5e7646d2SAndroid Build Coastguard Worker  */
1605*5e7646d2SAndroid Build Coastguard Worker 
1606*5e7646d2SAndroid Build Coastguard Worker static cups_lang_t *			/* O - Language data or NULL */
cups_cache_lookup(const char * name,cups_encoding_t encoding)1607*5e7646d2SAndroid Build Coastguard Worker cups_cache_lookup(
1608*5e7646d2SAndroid Build Coastguard Worker     const char      *name,		/* I - Name of locale */
1609*5e7646d2SAndroid Build Coastguard Worker     cups_encoding_t encoding)		/* I - Encoding of locale */
1610*5e7646d2SAndroid Build Coastguard Worker {
1611*5e7646d2SAndroid Build Coastguard Worker   cups_lang_t	*lang;			/* Current language */
1612*5e7646d2SAndroid Build Coastguard Worker 
1613*5e7646d2SAndroid Build Coastguard Worker 
1614*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("7cups_cache_lookup(name=\"%s\", encoding=%d(%s))", name,
1615*5e7646d2SAndroid Build Coastguard Worker                 encoding, encoding == CUPS_AUTO_ENCODING ? "auto" :
1616*5e7646d2SAndroid Build Coastguard Worker 		              lang_encodings[encoding]));
1617*5e7646d2SAndroid Build Coastguard Worker 
1618*5e7646d2SAndroid Build Coastguard Worker  /*
1619*5e7646d2SAndroid Build Coastguard Worker   * Loop through the cache and return a match if found...
1620*5e7646d2SAndroid Build Coastguard Worker   */
1621*5e7646d2SAndroid Build Coastguard Worker 
1622*5e7646d2SAndroid Build Coastguard Worker   for (lang = lang_cache; lang != NULL; lang = lang->next)
1623*5e7646d2SAndroid Build Coastguard Worker   {
1624*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("9cups_cache_lookup: lang=%p, language=\"%s\", "
1625*5e7646d2SAndroid Build Coastguard Worker 		  "encoding=%d(%s)", (void *)lang, lang->language, lang->encoding,
1626*5e7646d2SAndroid Build Coastguard Worker 		  lang_encodings[lang->encoding]));
1627*5e7646d2SAndroid Build Coastguard Worker 
1628*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(lang->language, name) &&
1629*5e7646d2SAndroid Build Coastguard Worker         (encoding == CUPS_AUTO_ENCODING || encoding == lang->encoding))
1630*5e7646d2SAndroid Build Coastguard Worker     {
1631*5e7646d2SAndroid Build Coastguard Worker       lang->used ++;
1632*5e7646d2SAndroid Build Coastguard Worker 
1633*5e7646d2SAndroid Build Coastguard Worker       DEBUG_puts("8cups_cache_lookup: returning match!");
1634*5e7646d2SAndroid Build Coastguard Worker 
1635*5e7646d2SAndroid Build Coastguard Worker       return (lang);
1636*5e7646d2SAndroid Build Coastguard Worker     }
1637*5e7646d2SAndroid Build Coastguard Worker   }
1638*5e7646d2SAndroid Build Coastguard Worker 
1639*5e7646d2SAndroid Build Coastguard Worker   DEBUG_puts("8cups_cache_lookup: returning NULL!");
1640*5e7646d2SAndroid Build Coastguard Worker 
1641*5e7646d2SAndroid Build Coastguard Worker   return (NULL);
1642*5e7646d2SAndroid Build Coastguard Worker }
1643*5e7646d2SAndroid Build Coastguard Worker 
1644*5e7646d2SAndroid Build Coastguard Worker 
1645*5e7646d2SAndroid Build Coastguard Worker /*
1646*5e7646d2SAndroid Build Coastguard Worker  * 'cups_message_compare()' - Compare two messages.
1647*5e7646d2SAndroid Build Coastguard Worker  */
1648*5e7646d2SAndroid Build Coastguard Worker 
1649*5e7646d2SAndroid Build Coastguard Worker static int				/* O - Result of comparison */
cups_message_compare(_cups_message_t * m1,_cups_message_t * m2)1650*5e7646d2SAndroid Build Coastguard Worker cups_message_compare(
1651*5e7646d2SAndroid Build Coastguard Worker     _cups_message_t *m1,		/* I - First message */
1652*5e7646d2SAndroid Build Coastguard Worker     _cups_message_t *m2)		/* I - Second message */
1653*5e7646d2SAndroid Build Coastguard Worker {
1654*5e7646d2SAndroid Build Coastguard Worker   return (strcmp(m1->msg, m2->msg));
1655*5e7646d2SAndroid Build Coastguard Worker }
1656*5e7646d2SAndroid Build Coastguard Worker 
1657*5e7646d2SAndroid Build Coastguard Worker 
1658*5e7646d2SAndroid Build Coastguard Worker /*
1659*5e7646d2SAndroid Build Coastguard Worker  * 'cups_message_free()' - Free a message.
1660*5e7646d2SAndroid Build Coastguard Worker  */
1661*5e7646d2SAndroid Build Coastguard Worker 
1662*5e7646d2SAndroid Build Coastguard Worker static void
cups_message_free(_cups_message_t * m)1663*5e7646d2SAndroid Build Coastguard Worker cups_message_free(_cups_message_t *m)	/* I - Message */
1664*5e7646d2SAndroid Build Coastguard Worker {
1665*5e7646d2SAndroid Build Coastguard Worker   if (m->msg)
1666*5e7646d2SAndroid Build Coastguard Worker     free(m->msg);
1667*5e7646d2SAndroid Build Coastguard Worker 
1668*5e7646d2SAndroid Build Coastguard Worker   if (m->str)
1669*5e7646d2SAndroid Build Coastguard Worker     free(m->str);
1670*5e7646d2SAndroid Build Coastguard Worker 
1671*5e7646d2SAndroid Build Coastguard Worker   free(m);
1672*5e7646d2SAndroid Build Coastguard Worker }
1673*5e7646d2SAndroid Build Coastguard Worker 
1674*5e7646d2SAndroid Build Coastguard Worker 
1675*5e7646d2SAndroid Build Coastguard Worker /*
1676*5e7646d2SAndroid Build Coastguard Worker  * 'cups_message_load()' - Load the message catalog for a language.
1677*5e7646d2SAndroid Build Coastguard Worker  */
1678*5e7646d2SAndroid Build Coastguard Worker 
1679*5e7646d2SAndroid Build Coastguard Worker static void
cups_message_load(cups_lang_t * lang)1680*5e7646d2SAndroid Build Coastguard Worker cups_message_load(cups_lang_t *lang)	/* I - Language */
1681*5e7646d2SAndroid Build Coastguard Worker {
1682*5e7646d2SAndroid Build Coastguard Worker #if defined(__APPLE__) && defined(CUPS_BUNDLEDIR)
1683*5e7646d2SAndroid Build Coastguard Worker   lang->strings = appleMessageLoad(lang->language);
1684*5e7646d2SAndroid Build Coastguard Worker 
1685*5e7646d2SAndroid Build Coastguard Worker #else
1686*5e7646d2SAndroid Build Coastguard Worker   char			filename[1024];	/* Filename for language locale file */
1687*5e7646d2SAndroid Build Coastguard Worker   _cups_globals_t	*cg = _cupsGlobals();
1688*5e7646d2SAndroid Build Coastguard Worker   					/* Pointer to library globals */
1689*5e7646d2SAndroid Build Coastguard Worker 
1690*5e7646d2SAndroid Build Coastguard Worker 
1691*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/%s/cups_%s.po", cg->localedir,
1692*5e7646d2SAndroid Build Coastguard Worker 	   lang->language, lang->language);
1693*5e7646d2SAndroid Build Coastguard Worker 
1694*5e7646d2SAndroid Build Coastguard Worker   if (strchr(lang->language, '_') && access(filename, 0))
1695*5e7646d2SAndroid Build Coastguard Worker   {
1696*5e7646d2SAndroid Build Coastguard Worker    /*
1697*5e7646d2SAndroid Build Coastguard Worker     * Country localization not available, look for generic localization...
1698*5e7646d2SAndroid Build Coastguard Worker     */
1699*5e7646d2SAndroid Build Coastguard Worker 
1700*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, sizeof(filename), "%s/%.2s/cups_%.2s.po", cg->localedir,
1701*5e7646d2SAndroid Build Coastguard Worker              lang->language, lang->language);
1702*5e7646d2SAndroid Build Coastguard Worker 
1703*5e7646d2SAndroid Build Coastguard Worker     if (access(filename, 0))
1704*5e7646d2SAndroid Build Coastguard Worker     {
1705*5e7646d2SAndroid Build Coastguard Worker      /*
1706*5e7646d2SAndroid Build Coastguard Worker       * No generic localization, so use POSIX...
1707*5e7646d2SAndroid Build Coastguard Worker       */
1708*5e7646d2SAndroid Build Coastguard Worker 
1709*5e7646d2SAndroid Build Coastguard Worker       DEBUG_printf(("4cups_message_load: access(\"%s\", 0): %s", filename,
1710*5e7646d2SAndroid Build Coastguard Worker                     strerror(errno)));
1711*5e7646d2SAndroid Build Coastguard Worker 
1712*5e7646d2SAndroid Build Coastguard Worker       snprintf(filename, sizeof(filename), "%s/C/cups_C.po", cg->localedir);
1713*5e7646d2SAndroid Build Coastguard Worker     }
1714*5e7646d2SAndroid Build Coastguard Worker   }
1715*5e7646d2SAndroid Build Coastguard Worker 
1716*5e7646d2SAndroid Build Coastguard Worker  /*
1717*5e7646d2SAndroid Build Coastguard Worker   * Read the strings from the file...
1718*5e7646d2SAndroid Build Coastguard Worker   */
1719*5e7646d2SAndroid Build Coastguard Worker 
1720*5e7646d2SAndroid Build Coastguard Worker   lang->strings = _cupsMessageLoad(filename, _CUPS_MESSAGE_UNQUOTE);
1721*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ && CUPS_BUNDLEDIR */
1722*5e7646d2SAndroid Build Coastguard Worker }
1723*5e7646d2SAndroid Build Coastguard Worker 
1724*5e7646d2SAndroid Build Coastguard Worker 
1725*5e7646d2SAndroid Build Coastguard Worker /*
1726*5e7646d2SAndroid Build Coastguard Worker  * 'cups_message_puts()' - Write a message string with quoting.
1727*5e7646d2SAndroid Build Coastguard Worker  */
1728*5e7646d2SAndroid Build Coastguard Worker 
1729*5e7646d2SAndroid Build Coastguard Worker static void
cups_message_puts(cups_file_t * fp,const char * s)1730*5e7646d2SAndroid Build Coastguard Worker cups_message_puts(cups_file_t *fp,	/* I - File to write to */
1731*5e7646d2SAndroid Build Coastguard Worker                   const char  *s)	/* I - String to write */
1732*5e7646d2SAndroid Build Coastguard Worker {
1733*5e7646d2SAndroid Build Coastguard Worker   const char	*start,			/* Start of substring */
1734*5e7646d2SAndroid Build Coastguard Worker 		*ptr;			/* Pointer into string */
1735*5e7646d2SAndroid Build Coastguard Worker 
1736*5e7646d2SAndroid Build Coastguard Worker 
1737*5e7646d2SAndroid Build Coastguard Worker   for (start = s, ptr = s; *ptr; ptr ++)
1738*5e7646d2SAndroid Build Coastguard Worker   {
1739*5e7646d2SAndroid Build Coastguard Worker     if (strchr("\\\"\n\t", *ptr))
1740*5e7646d2SAndroid Build Coastguard Worker     {
1741*5e7646d2SAndroid Build Coastguard Worker       if (ptr > start)
1742*5e7646d2SAndroid Build Coastguard Worker       {
1743*5e7646d2SAndroid Build Coastguard Worker 	cupsFileWrite(fp, start, (size_t)(ptr - start));
1744*5e7646d2SAndroid Build Coastguard Worker 	start = ptr + 1;
1745*5e7646d2SAndroid Build Coastguard Worker       }
1746*5e7646d2SAndroid Build Coastguard Worker 
1747*5e7646d2SAndroid Build Coastguard Worker       if (*ptr == '\\')
1748*5e7646d2SAndroid Build Coastguard Worker         cupsFileWrite(fp, "\\\\", 2);
1749*5e7646d2SAndroid Build Coastguard Worker       else if (*ptr == '\"')
1750*5e7646d2SAndroid Build Coastguard Worker         cupsFileWrite(fp, "\\\"", 2);
1751*5e7646d2SAndroid Build Coastguard Worker       else if (*ptr == '\n')
1752*5e7646d2SAndroid Build Coastguard Worker         cupsFileWrite(fp, "\\n", 2);
1753*5e7646d2SAndroid Build Coastguard Worker       else /* if (*ptr == '\t') */
1754*5e7646d2SAndroid Build Coastguard Worker         cupsFileWrite(fp, "\\t", 2);
1755*5e7646d2SAndroid Build Coastguard Worker     }
1756*5e7646d2SAndroid Build Coastguard Worker   }
1757*5e7646d2SAndroid Build Coastguard Worker 
1758*5e7646d2SAndroid Build Coastguard Worker   if (ptr > start)
1759*5e7646d2SAndroid Build Coastguard Worker     cupsFileWrite(fp, start, (size_t)(ptr - start));
1760*5e7646d2SAndroid Build Coastguard Worker }
1761*5e7646d2SAndroid Build Coastguard Worker 
1762*5e7646d2SAndroid Build Coastguard Worker 
1763*5e7646d2SAndroid Build Coastguard Worker /*
1764*5e7646d2SAndroid Build Coastguard Worker  * 'cups_read_strings()' - Read a pair of strings from a .strings file.
1765*5e7646d2SAndroid Build Coastguard Worker  */
1766*5e7646d2SAndroid Build Coastguard Worker 
1767*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 1 on success, 0 on failure */
cups_read_strings(cups_file_t * fp,int flags,cups_array_t * a)1768*5e7646d2SAndroid Build Coastguard Worker cups_read_strings(cups_file_t  *fp,	/* I - .strings file */
1769*5e7646d2SAndroid Build Coastguard Worker                   int          flags,	/* I - CUPS_MESSAGE_xxx flags */
1770*5e7646d2SAndroid Build Coastguard Worker 		  cups_array_t *a)	/* I - Message catalog array */
1771*5e7646d2SAndroid Build Coastguard Worker {
1772*5e7646d2SAndroid Build Coastguard Worker   char			buffer[8192],	/* Line buffer */
1773*5e7646d2SAndroid Build Coastguard Worker 			*bufptr,	/* Pointer into buffer */
1774*5e7646d2SAndroid Build Coastguard Worker 			*msg,		/* Pointer to start of message */
1775*5e7646d2SAndroid Build Coastguard Worker 			*str;		/* Pointer to start of translation string */
1776*5e7646d2SAndroid Build Coastguard Worker   _cups_message_t	*m;		/* New message */
1777*5e7646d2SAndroid Build Coastguard Worker 
1778*5e7646d2SAndroid Build Coastguard Worker 
1779*5e7646d2SAndroid Build Coastguard Worker   while (cupsFileGets(fp, buffer, sizeof(buffer)))
1780*5e7646d2SAndroid Build Coastguard Worker   {
1781*5e7646d2SAndroid Build Coastguard Worker    /*
1782*5e7646d2SAndroid Build Coastguard Worker     * Skip any line (comments, blanks, etc.) that isn't:
1783*5e7646d2SAndroid Build Coastguard Worker     *
1784*5e7646d2SAndroid Build Coastguard Worker     *   "message" = "translation";
1785*5e7646d2SAndroid Build Coastguard Worker     */
1786*5e7646d2SAndroid Build Coastguard Worker 
1787*5e7646d2SAndroid Build Coastguard Worker     for (bufptr = buffer; *bufptr && isspace(*bufptr & 255); bufptr ++);
1788*5e7646d2SAndroid Build Coastguard Worker 
1789*5e7646d2SAndroid Build Coastguard Worker     if (*bufptr != '\"')
1790*5e7646d2SAndroid Build Coastguard Worker       continue;
1791*5e7646d2SAndroid Build Coastguard Worker 
1792*5e7646d2SAndroid Build Coastguard Worker    /*
1793*5e7646d2SAndroid Build Coastguard Worker     * Find the end of the message...
1794*5e7646d2SAndroid Build Coastguard Worker     */
1795*5e7646d2SAndroid Build Coastguard Worker 
1796*5e7646d2SAndroid Build Coastguard Worker     bufptr ++;
1797*5e7646d2SAndroid Build Coastguard Worker     for (msg = bufptr; *bufptr && *bufptr != '\"'; bufptr ++)
1798*5e7646d2SAndroid Build Coastguard Worker       if (*bufptr == '\\' && bufptr[1])
1799*5e7646d2SAndroid Build Coastguard Worker         bufptr ++;
1800*5e7646d2SAndroid Build Coastguard Worker 
1801*5e7646d2SAndroid Build Coastguard Worker     if (!*bufptr)
1802*5e7646d2SAndroid Build Coastguard Worker       continue;
1803*5e7646d2SAndroid Build Coastguard Worker 
1804*5e7646d2SAndroid Build Coastguard Worker     *bufptr++ = '\0';
1805*5e7646d2SAndroid Build Coastguard Worker 
1806*5e7646d2SAndroid Build Coastguard Worker     if (flags & _CUPS_MESSAGE_UNQUOTE)
1807*5e7646d2SAndroid Build Coastguard Worker       cups_unquote(msg, msg);
1808*5e7646d2SAndroid Build Coastguard Worker 
1809*5e7646d2SAndroid Build Coastguard Worker    /*
1810*5e7646d2SAndroid Build Coastguard Worker     * Find the start of the translation...
1811*5e7646d2SAndroid Build Coastguard Worker     */
1812*5e7646d2SAndroid Build Coastguard Worker 
1813*5e7646d2SAndroid Build Coastguard Worker     while (*bufptr && isspace(*bufptr & 255))
1814*5e7646d2SAndroid Build Coastguard Worker       bufptr ++;
1815*5e7646d2SAndroid Build Coastguard Worker 
1816*5e7646d2SAndroid Build Coastguard Worker     if (*bufptr != '=')
1817*5e7646d2SAndroid Build Coastguard Worker       continue;
1818*5e7646d2SAndroid Build Coastguard Worker 
1819*5e7646d2SAndroid Build Coastguard Worker     bufptr ++;
1820*5e7646d2SAndroid Build Coastguard Worker     while (*bufptr && isspace(*bufptr & 255))
1821*5e7646d2SAndroid Build Coastguard Worker       bufptr ++;
1822*5e7646d2SAndroid Build Coastguard Worker 
1823*5e7646d2SAndroid Build Coastguard Worker     if (*bufptr != '\"')
1824*5e7646d2SAndroid Build Coastguard Worker       continue;
1825*5e7646d2SAndroid Build Coastguard Worker 
1826*5e7646d2SAndroid Build Coastguard Worker    /*
1827*5e7646d2SAndroid Build Coastguard Worker     * Find the end of the translation...
1828*5e7646d2SAndroid Build Coastguard Worker     */
1829*5e7646d2SAndroid Build Coastguard Worker 
1830*5e7646d2SAndroid Build Coastguard Worker     bufptr ++;
1831*5e7646d2SAndroid Build Coastguard Worker     for (str = bufptr; *bufptr && *bufptr != '\"'; bufptr ++)
1832*5e7646d2SAndroid Build Coastguard Worker       if (*bufptr == '\\' && bufptr[1])
1833*5e7646d2SAndroid Build Coastguard Worker         bufptr ++;
1834*5e7646d2SAndroid Build Coastguard Worker 
1835*5e7646d2SAndroid Build Coastguard Worker     if (!*bufptr)
1836*5e7646d2SAndroid Build Coastguard Worker       continue;
1837*5e7646d2SAndroid Build Coastguard Worker 
1838*5e7646d2SAndroid Build Coastguard Worker     *bufptr++ = '\0';
1839*5e7646d2SAndroid Build Coastguard Worker 
1840*5e7646d2SAndroid Build Coastguard Worker     if (flags & _CUPS_MESSAGE_UNQUOTE)
1841*5e7646d2SAndroid Build Coastguard Worker       cups_unquote(str, str);
1842*5e7646d2SAndroid Build Coastguard Worker 
1843*5e7646d2SAndroid Build Coastguard Worker    /*
1844*5e7646d2SAndroid Build Coastguard Worker     * If we get this far we have a valid pair of strings, add them...
1845*5e7646d2SAndroid Build Coastguard Worker     */
1846*5e7646d2SAndroid Build Coastguard Worker 
1847*5e7646d2SAndroid Build Coastguard Worker     if ((m = malloc(sizeof(_cups_message_t))) == NULL)
1848*5e7646d2SAndroid Build Coastguard Worker       break;
1849*5e7646d2SAndroid Build Coastguard Worker 
1850*5e7646d2SAndroid Build Coastguard Worker     m->msg = strdup(msg);
1851*5e7646d2SAndroid Build Coastguard Worker     m->str = strdup(str);
1852*5e7646d2SAndroid Build Coastguard Worker 
1853*5e7646d2SAndroid Build Coastguard Worker     if (m->msg && m->str)
1854*5e7646d2SAndroid Build Coastguard Worker     {
1855*5e7646d2SAndroid Build Coastguard Worker       cupsArrayAdd(a, m);
1856*5e7646d2SAndroid Build Coastguard Worker     }
1857*5e7646d2SAndroid Build Coastguard Worker     else
1858*5e7646d2SAndroid Build Coastguard Worker     {
1859*5e7646d2SAndroid Build Coastguard Worker       if (m->msg)
1860*5e7646d2SAndroid Build Coastguard Worker 	free(m->msg);
1861*5e7646d2SAndroid Build Coastguard Worker 
1862*5e7646d2SAndroid Build Coastguard Worker       if (m->str)
1863*5e7646d2SAndroid Build Coastguard Worker 	free(m->str);
1864*5e7646d2SAndroid Build Coastguard Worker 
1865*5e7646d2SAndroid Build Coastguard Worker       free(m);
1866*5e7646d2SAndroid Build Coastguard Worker       break;
1867*5e7646d2SAndroid Build Coastguard Worker     }
1868*5e7646d2SAndroid Build Coastguard Worker 
1869*5e7646d2SAndroid Build Coastguard Worker     return (1);
1870*5e7646d2SAndroid Build Coastguard Worker   }
1871*5e7646d2SAndroid Build Coastguard Worker 
1872*5e7646d2SAndroid Build Coastguard Worker  /*
1873*5e7646d2SAndroid Build Coastguard Worker   * No more strings...
1874*5e7646d2SAndroid Build Coastguard Worker   */
1875*5e7646d2SAndroid Build Coastguard Worker 
1876*5e7646d2SAndroid Build Coastguard Worker   return (0);
1877*5e7646d2SAndroid Build Coastguard Worker }
1878*5e7646d2SAndroid Build Coastguard Worker 
1879*5e7646d2SAndroid Build Coastguard Worker 
1880*5e7646d2SAndroid Build Coastguard Worker /*
1881*5e7646d2SAndroid Build Coastguard Worker  * 'cups_unquote()' - Unquote characters in strings...
1882*5e7646d2SAndroid Build Coastguard Worker  */
1883*5e7646d2SAndroid Build Coastguard Worker 
1884*5e7646d2SAndroid Build Coastguard Worker static void
cups_unquote(char * d,const char * s)1885*5e7646d2SAndroid Build Coastguard Worker cups_unquote(char       *d,		/* O - Unquoted string */
1886*5e7646d2SAndroid Build Coastguard Worker              const char *s)		/* I - Original string */
1887*5e7646d2SAndroid Build Coastguard Worker {
1888*5e7646d2SAndroid Build Coastguard Worker   while (*s)
1889*5e7646d2SAndroid Build Coastguard Worker   {
1890*5e7646d2SAndroid Build Coastguard Worker     if (*s == '\\')
1891*5e7646d2SAndroid Build Coastguard Worker     {
1892*5e7646d2SAndroid Build Coastguard Worker       s ++;
1893*5e7646d2SAndroid Build Coastguard Worker       if (isdigit(*s))
1894*5e7646d2SAndroid Build Coastguard Worker       {
1895*5e7646d2SAndroid Build Coastguard Worker 	*d = 0;
1896*5e7646d2SAndroid Build Coastguard Worker 
1897*5e7646d2SAndroid Build Coastguard Worker 	while (isdigit(*s))
1898*5e7646d2SAndroid Build Coastguard Worker 	{
1899*5e7646d2SAndroid Build Coastguard Worker 	  *d = *d * 8 + *s - '0';
1900*5e7646d2SAndroid Build Coastguard Worker 	  s ++;
1901*5e7646d2SAndroid Build Coastguard Worker 	}
1902*5e7646d2SAndroid Build Coastguard Worker 
1903*5e7646d2SAndroid Build Coastguard Worker 	d ++;
1904*5e7646d2SAndroid Build Coastguard Worker       }
1905*5e7646d2SAndroid Build Coastguard Worker       else
1906*5e7646d2SAndroid Build Coastguard Worker       {
1907*5e7646d2SAndroid Build Coastguard Worker 	if (*s == 'n')
1908*5e7646d2SAndroid Build Coastguard Worker 	  *d ++ = '\n';
1909*5e7646d2SAndroid Build Coastguard Worker 	else if (*s == 'r')
1910*5e7646d2SAndroid Build Coastguard Worker 	  *d ++ = '\r';
1911*5e7646d2SAndroid Build Coastguard Worker 	else if (*s == 't')
1912*5e7646d2SAndroid Build Coastguard Worker 	  *d ++ = '\t';
1913*5e7646d2SAndroid Build Coastguard Worker 	else
1914*5e7646d2SAndroid Build Coastguard Worker 	  *d++ = *s;
1915*5e7646d2SAndroid Build Coastguard Worker 
1916*5e7646d2SAndroid Build Coastguard Worker 	s ++;
1917*5e7646d2SAndroid Build Coastguard Worker       }
1918*5e7646d2SAndroid Build Coastguard Worker     }
1919*5e7646d2SAndroid Build Coastguard Worker     else
1920*5e7646d2SAndroid Build Coastguard Worker       *d++ = *s++;
1921*5e7646d2SAndroid Build Coastguard Worker   }
1922*5e7646d2SAndroid Build Coastguard Worker 
1923*5e7646d2SAndroid Build Coastguard Worker   *d = '\0';
1924*5e7646d2SAndroid Build Coastguard Worker }
1925