xref: /aosp_15_r20/external/libcups/cups/ppd-localize.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * PPD localization routines for CUPS.
3*5e7646d2SAndroid Build Coastguard Worker  *
4*5e7646d2SAndroid Build Coastguard Worker  * Copyright 2007-2018 by Apple Inc.
5*5e7646d2SAndroid Build Coastguard Worker  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
6*5e7646d2SAndroid Build Coastguard Worker  *
7*5e7646d2SAndroid Build Coastguard Worker  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
8*5e7646d2SAndroid Build Coastguard Worker  * information.
9*5e7646d2SAndroid Build Coastguard Worker  *
10*5e7646d2SAndroid Build Coastguard Worker  * PostScript is a trademark of Adobe Systems, Inc.
11*5e7646d2SAndroid Build Coastguard Worker  */
12*5e7646d2SAndroid Build Coastguard Worker 
13*5e7646d2SAndroid Build Coastguard Worker /*
14*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers.
15*5e7646d2SAndroid Build Coastguard Worker  */
16*5e7646d2SAndroid Build Coastguard Worker 
17*5e7646d2SAndroid Build Coastguard Worker #include "cups-private.h"
18*5e7646d2SAndroid Build Coastguard Worker #include "ppd-private.h"
19*5e7646d2SAndroid Build Coastguard Worker #include "debug-internal.h"
20*5e7646d2SAndroid Build Coastguard Worker 
21*5e7646d2SAndroid Build Coastguard Worker 
22*5e7646d2SAndroid Build Coastguard Worker /*
23*5e7646d2SAndroid Build Coastguard Worker  * Local functions...
24*5e7646d2SAndroid Build Coastguard Worker  */
25*5e7646d2SAndroid Build Coastguard Worker 
26*5e7646d2SAndroid Build Coastguard Worker static cups_lang_t	*ppd_ll_CC(char *ll_CC, size_t ll_CC_size);
27*5e7646d2SAndroid Build Coastguard Worker 
28*5e7646d2SAndroid Build Coastguard Worker 
29*5e7646d2SAndroid Build Coastguard Worker /*
30*5e7646d2SAndroid Build Coastguard Worker  * 'ppdLocalize()' - Localize the PPD file to the current locale.
31*5e7646d2SAndroid Build Coastguard Worker  *
32*5e7646d2SAndroid Build Coastguard Worker  * All groups, options, and choices are localized, as are ICC profile
33*5e7646d2SAndroid Build Coastguard Worker  * descriptions, printer presets, and custom option parameters.  Each
34*5e7646d2SAndroid Build Coastguard Worker  * localized string uses the UTF-8 character encoding.
35*5e7646d2SAndroid Build Coastguard Worker  *
36*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.2/macOS 10.5@
37*5e7646d2SAndroid Build Coastguard Worker  */
38*5e7646d2SAndroid Build Coastguard Worker 
39*5e7646d2SAndroid Build Coastguard Worker int					/* O - 0 on success, -1 on error */
ppdLocalize(ppd_file_t * ppd)40*5e7646d2SAndroid Build Coastguard Worker ppdLocalize(ppd_file_t *ppd)		/* I - PPD file */
41*5e7646d2SAndroid Build Coastguard Worker {
42*5e7646d2SAndroid Build Coastguard Worker   int		i, j, k;		/* Looping vars */
43*5e7646d2SAndroid Build Coastguard Worker   ppd_group_t	*group;			/* Current group */
44*5e7646d2SAndroid Build Coastguard Worker   ppd_option_t	*option;		/* Current option */
45*5e7646d2SAndroid Build Coastguard Worker   ppd_choice_t	*choice;		/* Current choice */
46*5e7646d2SAndroid Build Coastguard Worker   ppd_coption_t	*coption;		/* Current custom option */
47*5e7646d2SAndroid Build Coastguard Worker   ppd_cparam_t	*cparam;		/* Current custom parameter */
48*5e7646d2SAndroid Build Coastguard Worker   ppd_attr_t	*attr,			/* Current attribute */
49*5e7646d2SAndroid Build Coastguard Worker 		*locattr;		/* Localized attribute */
50*5e7646d2SAndroid Build Coastguard Worker   char		ckeyword[PPD_MAX_NAME],	/* Custom keyword */
51*5e7646d2SAndroid Build Coastguard Worker 		ll_CC[6];		/* Language + country locale */
52*5e7646d2SAndroid Build Coastguard Worker 
53*5e7646d2SAndroid Build Coastguard Worker 
54*5e7646d2SAndroid Build Coastguard Worker  /*
55*5e7646d2SAndroid Build Coastguard Worker   * Range check input...
56*5e7646d2SAndroid Build Coastguard Worker   */
57*5e7646d2SAndroid Build Coastguard Worker 
58*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("ppdLocalize(ppd=%p)", ppd));
59*5e7646d2SAndroid Build Coastguard Worker 
60*5e7646d2SAndroid Build Coastguard Worker   if (!ppd)
61*5e7646d2SAndroid Build Coastguard Worker     return (-1);
62*5e7646d2SAndroid Build Coastguard Worker 
63*5e7646d2SAndroid Build Coastguard Worker  /*
64*5e7646d2SAndroid Build Coastguard Worker   * Get the default language...
65*5e7646d2SAndroid Build Coastguard Worker   */
66*5e7646d2SAndroid Build Coastguard Worker 
67*5e7646d2SAndroid Build Coastguard Worker   ppd_ll_CC(ll_CC, sizeof(ll_CC));
68*5e7646d2SAndroid Build Coastguard Worker 
69*5e7646d2SAndroid Build Coastguard Worker  /*
70*5e7646d2SAndroid Build Coastguard Worker   * Now lookup all of the groups, options, choices, etc.
71*5e7646d2SAndroid Build Coastguard Worker   */
72*5e7646d2SAndroid Build Coastguard Worker 
73*5e7646d2SAndroid Build Coastguard Worker   for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
74*5e7646d2SAndroid Build Coastguard Worker   {
75*5e7646d2SAndroid Build Coastguard Worker     if ((locattr = _ppdLocalizedAttr(ppd, "Translation", group->name,
76*5e7646d2SAndroid Build Coastguard Worker                                      ll_CC)) != NULL)
77*5e7646d2SAndroid Build Coastguard Worker       strlcpy(group->text, locattr->text, sizeof(group->text));
78*5e7646d2SAndroid Build Coastguard Worker 
79*5e7646d2SAndroid Build Coastguard Worker     for (j = group->num_options, option = group->options; j > 0; j --, option ++)
80*5e7646d2SAndroid Build Coastguard Worker     {
81*5e7646d2SAndroid Build Coastguard Worker       if ((locattr = _ppdLocalizedAttr(ppd, "Translation", option->keyword,
82*5e7646d2SAndroid Build Coastguard Worker                                        ll_CC)) != NULL)
83*5e7646d2SAndroid Build Coastguard Worker 	strlcpy(option->text, locattr->text, sizeof(option->text));
84*5e7646d2SAndroid Build Coastguard Worker 
85*5e7646d2SAndroid Build Coastguard Worker       for (k = option->num_choices, choice = option->choices;
86*5e7646d2SAndroid Build Coastguard Worker            k > 0;
87*5e7646d2SAndroid Build Coastguard Worker 	   k --, choice ++)
88*5e7646d2SAndroid Build Coastguard Worker       {
89*5e7646d2SAndroid Build Coastguard Worker         if (strcmp(choice->choice, "Custom") ||
90*5e7646d2SAndroid Build Coastguard Worker 	    !ppdFindCustomOption(ppd, option->keyword))
91*5e7646d2SAndroid Build Coastguard Worker 	  locattr = _ppdLocalizedAttr(ppd, option->keyword, choice->choice,
92*5e7646d2SAndroid Build Coastguard Worker 	                              ll_CC);
93*5e7646d2SAndroid Build Coastguard Worker 	else
94*5e7646d2SAndroid Build Coastguard Worker 	{
95*5e7646d2SAndroid Build Coastguard Worker 	  snprintf(ckeyword, sizeof(ckeyword), "Custom%s", option->keyword);
96*5e7646d2SAndroid Build Coastguard Worker 
97*5e7646d2SAndroid Build Coastguard Worker 	  locattr = _ppdLocalizedAttr(ppd, ckeyword, "True", ll_CC);
98*5e7646d2SAndroid Build Coastguard Worker 	}
99*5e7646d2SAndroid Build Coastguard Worker 
100*5e7646d2SAndroid Build Coastguard Worker         if (locattr)
101*5e7646d2SAndroid Build Coastguard Worker 	  strlcpy(choice->text, locattr->text, sizeof(choice->text));
102*5e7646d2SAndroid Build Coastguard Worker       }
103*5e7646d2SAndroid Build Coastguard Worker     }
104*5e7646d2SAndroid Build Coastguard Worker   }
105*5e7646d2SAndroid Build Coastguard Worker 
106*5e7646d2SAndroid Build Coastguard Worker  /*
107*5e7646d2SAndroid Build Coastguard Worker   * Translate any custom parameters...
108*5e7646d2SAndroid Build Coastguard Worker   */
109*5e7646d2SAndroid Build Coastguard Worker 
110*5e7646d2SAndroid Build Coastguard Worker   for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
111*5e7646d2SAndroid Build Coastguard Worker        coption;
112*5e7646d2SAndroid Build Coastguard Worker        coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
113*5e7646d2SAndroid Build Coastguard Worker   {
114*5e7646d2SAndroid Build Coastguard Worker     for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
115*5e7646d2SAndroid Build Coastguard Worker 	 cparam;
116*5e7646d2SAndroid Build Coastguard Worker 	 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
117*5e7646d2SAndroid Build Coastguard Worker     {
118*5e7646d2SAndroid Build Coastguard Worker       snprintf(ckeyword, sizeof(ckeyword), "ParamCustom%s", coption->keyword);
119*5e7646d2SAndroid Build Coastguard Worker 
120*5e7646d2SAndroid Build Coastguard Worker       if ((locattr = _ppdLocalizedAttr(ppd, ckeyword, cparam->name,
121*5e7646d2SAndroid Build Coastguard Worker                                        ll_CC)) != NULL)
122*5e7646d2SAndroid Build Coastguard Worker         strlcpy(cparam->text, locattr->text, sizeof(cparam->text));
123*5e7646d2SAndroid Build Coastguard Worker     }
124*5e7646d2SAndroid Build Coastguard Worker   }
125*5e7646d2SAndroid Build Coastguard Worker 
126*5e7646d2SAndroid Build Coastguard Worker  /*
127*5e7646d2SAndroid Build Coastguard Worker   * Translate ICC profile names...
128*5e7646d2SAndroid Build Coastguard Worker   */
129*5e7646d2SAndroid Build Coastguard Worker 
130*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ppdFindAttr(ppd, "APCustomColorMatchingName", NULL)) != NULL)
131*5e7646d2SAndroid Build Coastguard Worker   {
132*5e7646d2SAndroid Build Coastguard Worker     if ((locattr = _ppdLocalizedAttr(ppd, "APCustomColorMatchingName",
133*5e7646d2SAndroid Build Coastguard Worker                                      attr->spec, ll_CC)) != NULL)
134*5e7646d2SAndroid Build Coastguard Worker       strlcpy(attr->text, locattr->text, sizeof(attr->text));
135*5e7646d2SAndroid Build Coastguard Worker   }
136*5e7646d2SAndroid Build Coastguard Worker 
137*5e7646d2SAndroid Build Coastguard Worker   for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
138*5e7646d2SAndroid Build Coastguard Worker        attr;
139*5e7646d2SAndroid Build Coastguard Worker        attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
140*5e7646d2SAndroid Build Coastguard Worker   {
141*5e7646d2SAndroid Build Coastguard Worker     cupsArraySave(ppd->sorted_attrs);
142*5e7646d2SAndroid Build Coastguard Worker 
143*5e7646d2SAndroid Build Coastguard Worker     if ((locattr = _ppdLocalizedAttr(ppd, "cupsICCProfile", attr->spec,
144*5e7646d2SAndroid Build Coastguard Worker                                      ll_CC)) != NULL)
145*5e7646d2SAndroid Build Coastguard Worker       strlcpy(attr->text, locattr->text, sizeof(attr->text));
146*5e7646d2SAndroid Build Coastguard Worker 
147*5e7646d2SAndroid Build Coastguard Worker     cupsArrayRestore(ppd->sorted_attrs);
148*5e7646d2SAndroid Build Coastguard Worker   }
149*5e7646d2SAndroid Build Coastguard Worker 
150*5e7646d2SAndroid Build Coastguard Worker  /*
151*5e7646d2SAndroid Build Coastguard Worker   * Translate printer presets...
152*5e7646d2SAndroid Build Coastguard Worker   */
153*5e7646d2SAndroid Build Coastguard Worker 
154*5e7646d2SAndroid Build Coastguard Worker   for (attr = ppdFindAttr(ppd, "APPrinterPreset", NULL);
155*5e7646d2SAndroid Build Coastguard Worker        attr;
156*5e7646d2SAndroid Build Coastguard Worker        attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL))
157*5e7646d2SAndroid Build Coastguard Worker   {
158*5e7646d2SAndroid Build Coastguard Worker     cupsArraySave(ppd->sorted_attrs);
159*5e7646d2SAndroid Build Coastguard Worker 
160*5e7646d2SAndroid Build Coastguard Worker     if ((locattr = _ppdLocalizedAttr(ppd, "APPrinterPreset", attr->spec,
161*5e7646d2SAndroid Build Coastguard Worker                                      ll_CC)) != NULL)
162*5e7646d2SAndroid Build Coastguard Worker       strlcpy(attr->text, locattr->text, sizeof(attr->text));
163*5e7646d2SAndroid Build Coastguard Worker 
164*5e7646d2SAndroid Build Coastguard Worker     cupsArrayRestore(ppd->sorted_attrs);
165*5e7646d2SAndroid Build Coastguard Worker   }
166*5e7646d2SAndroid Build Coastguard Worker 
167*5e7646d2SAndroid Build Coastguard Worker   return (0);
168*5e7646d2SAndroid Build Coastguard Worker }
169*5e7646d2SAndroid Build Coastguard Worker 
170*5e7646d2SAndroid Build Coastguard Worker 
171*5e7646d2SAndroid Build Coastguard Worker /*
172*5e7646d2SAndroid Build Coastguard Worker  * 'ppdLocalizeAttr()' - Localize an attribute.
173*5e7646d2SAndroid Build Coastguard Worker  *
174*5e7646d2SAndroid Build Coastguard Worker  * This function uses the current locale to find the localized attribute for
175*5e7646d2SAndroid Build Coastguard Worker  * the given main and option keywords.  If no localized version of the
176*5e7646d2SAndroid Build Coastguard Worker  * attribute exists for the current locale, the unlocalized version is returned.
177*5e7646d2SAndroid Build Coastguard Worker  */
178*5e7646d2SAndroid Build Coastguard Worker 
179*5e7646d2SAndroid Build Coastguard Worker ppd_attr_t *				/* O - Localized attribute or @code NULL@ if none exists */
ppdLocalizeAttr(ppd_file_t * ppd,const char * keyword,const char * spec)180*5e7646d2SAndroid Build Coastguard Worker ppdLocalizeAttr(ppd_file_t *ppd,	/* I - PPD file */
181*5e7646d2SAndroid Build Coastguard Worker 		const char *keyword,	/* I - Main keyword */
182*5e7646d2SAndroid Build Coastguard Worker 		const char *spec)	/* I - Option keyword or @code NULL@ for none */
183*5e7646d2SAndroid Build Coastguard Worker {
184*5e7646d2SAndroid Build Coastguard Worker   ppd_attr_t	*locattr;		/* Localized attribute */
185*5e7646d2SAndroid Build Coastguard Worker   char		ll_CC[6];		/* Language + country locale */
186*5e7646d2SAndroid Build Coastguard Worker 
187*5e7646d2SAndroid Build Coastguard Worker 
188*5e7646d2SAndroid Build Coastguard Worker  /*
189*5e7646d2SAndroid Build Coastguard Worker   * Get the default language...
190*5e7646d2SAndroid Build Coastguard Worker   */
191*5e7646d2SAndroid Build Coastguard Worker 
192*5e7646d2SAndroid Build Coastguard Worker   ppd_ll_CC(ll_CC, sizeof(ll_CC));
193*5e7646d2SAndroid Build Coastguard Worker 
194*5e7646d2SAndroid Build Coastguard Worker  /*
195*5e7646d2SAndroid Build Coastguard Worker   * Find the localized attribute...
196*5e7646d2SAndroid Build Coastguard Worker   */
197*5e7646d2SAndroid Build Coastguard Worker 
198*5e7646d2SAndroid Build Coastguard Worker   if (spec)
199*5e7646d2SAndroid Build Coastguard Worker     locattr = _ppdLocalizedAttr(ppd, keyword, spec, ll_CC);
200*5e7646d2SAndroid Build Coastguard Worker   else
201*5e7646d2SAndroid Build Coastguard Worker     locattr = _ppdLocalizedAttr(ppd, "Translation", keyword, ll_CC);
202*5e7646d2SAndroid Build Coastguard Worker 
203*5e7646d2SAndroid Build Coastguard Worker   if (!locattr)
204*5e7646d2SAndroid Build Coastguard Worker     locattr = ppdFindAttr(ppd, keyword, spec);
205*5e7646d2SAndroid Build Coastguard Worker 
206*5e7646d2SAndroid Build Coastguard Worker   return (locattr);
207*5e7646d2SAndroid Build Coastguard Worker }
208*5e7646d2SAndroid Build Coastguard Worker 
209*5e7646d2SAndroid Build Coastguard Worker 
210*5e7646d2SAndroid Build Coastguard Worker /*
211*5e7646d2SAndroid Build Coastguard Worker  * 'ppdLocalizeIPPReason()' - Get the localized version of a cupsIPPReason
212*5e7646d2SAndroid Build Coastguard Worker  *                            attribute.
213*5e7646d2SAndroid Build Coastguard Worker  *
214*5e7646d2SAndroid Build Coastguard Worker  * This function uses the current locale to find the corresponding reason
215*5e7646d2SAndroid Build Coastguard Worker  * text or URI from the attribute value. If "scheme" is NULL or "text",
216*5e7646d2SAndroid Build Coastguard Worker  * the returned value contains human-readable (UTF-8) text from the translation
217*5e7646d2SAndroid Build Coastguard Worker  * string or attribute value. Otherwise the corresponding URI is returned.
218*5e7646d2SAndroid Build Coastguard Worker  *
219*5e7646d2SAndroid Build Coastguard Worker  * If no value of the requested scheme can be found, NULL is returned.
220*5e7646d2SAndroid Build Coastguard Worker  *
221*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.3/macOS 10.5@
222*5e7646d2SAndroid Build Coastguard Worker  */
223*5e7646d2SAndroid Build Coastguard Worker 
224*5e7646d2SAndroid Build Coastguard Worker const char *				/* O - Value or NULL if not found */
ppdLocalizeIPPReason(ppd_file_t * ppd,const char * reason,const char * scheme,char * buffer,size_t bufsize)225*5e7646d2SAndroid Build Coastguard Worker ppdLocalizeIPPReason(
226*5e7646d2SAndroid Build Coastguard Worker     ppd_file_t *ppd,			/* I - PPD file */
227*5e7646d2SAndroid Build Coastguard Worker     const char *reason,			/* I - IPP reason keyword to look up */
228*5e7646d2SAndroid Build Coastguard Worker     const char *scheme,			/* I - URI scheme or NULL for text */
229*5e7646d2SAndroid Build Coastguard Worker     char       *buffer,			/* I - Value buffer */
230*5e7646d2SAndroid Build Coastguard Worker     size_t     bufsize)			/* I - Size of value buffer */
231*5e7646d2SAndroid Build Coastguard Worker {
232*5e7646d2SAndroid Build Coastguard Worker   cups_lang_t	*lang;			/* Current language */
233*5e7646d2SAndroid Build Coastguard Worker   ppd_attr_t	*locattr;		/* Localized attribute */
234*5e7646d2SAndroid Build Coastguard Worker   char		ll_CC[6],		/* Language + country locale */
235*5e7646d2SAndroid Build Coastguard Worker 		*bufptr,		/* Pointer into buffer */
236*5e7646d2SAndroid Build Coastguard Worker 		*bufend,		/* Pointer to end of buffer */
237*5e7646d2SAndroid Build Coastguard Worker 		*valptr;		/* Pointer into value */
238*5e7646d2SAndroid Build Coastguard Worker   int		ch;			/* Hex-encoded character */
239*5e7646d2SAndroid Build Coastguard Worker   size_t	schemelen;		/* Length of scheme name */
240*5e7646d2SAndroid Build Coastguard Worker 
241*5e7646d2SAndroid Build Coastguard Worker 
242*5e7646d2SAndroid Build Coastguard Worker  /*
243*5e7646d2SAndroid Build Coastguard Worker   * Range check input...
244*5e7646d2SAndroid Build Coastguard Worker   */
245*5e7646d2SAndroid Build Coastguard Worker 
246*5e7646d2SAndroid Build Coastguard Worker   if (buffer)
247*5e7646d2SAndroid Build Coastguard Worker     *buffer = '\0';
248*5e7646d2SAndroid Build Coastguard Worker 
249*5e7646d2SAndroid Build Coastguard Worker   if (!ppd || !reason || (scheme && !*scheme) ||
250*5e7646d2SAndroid Build Coastguard Worker       !buffer || bufsize < PPD_MAX_TEXT)
251*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
252*5e7646d2SAndroid Build Coastguard Worker 
253*5e7646d2SAndroid Build Coastguard Worker  /*
254*5e7646d2SAndroid Build Coastguard Worker   * Get the default language...
255*5e7646d2SAndroid Build Coastguard Worker   */
256*5e7646d2SAndroid Build Coastguard Worker 
257*5e7646d2SAndroid Build Coastguard Worker   lang = ppd_ll_CC(ll_CC, sizeof(ll_CC));
258*5e7646d2SAndroid Build Coastguard Worker 
259*5e7646d2SAndroid Build Coastguard Worker  /*
260*5e7646d2SAndroid Build Coastguard Worker   * Find the localized attribute...
261*5e7646d2SAndroid Build Coastguard Worker   */
262*5e7646d2SAndroid Build Coastguard Worker 
263*5e7646d2SAndroid Build Coastguard Worker   if ((locattr = _ppdLocalizedAttr(ppd, "cupsIPPReason", reason,
264*5e7646d2SAndroid Build Coastguard Worker                                    ll_CC)) == NULL)
265*5e7646d2SAndroid Build Coastguard Worker     locattr = ppdFindAttr(ppd, "cupsIPPReason", reason);
266*5e7646d2SAndroid Build Coastguard Worker 
267*5e7646d2SAndroid Build Coastguard Worker   if (!locattr)
268*5e7646d2SAndroid Build Coastguard Worker   {
269*5e7646d2SAndroid Build Coastguard Worker     if (lang && (!scheme || !strcmp(scheme, "text")) && strcmp(reason, "none"))
270*5e7646d2SAndroid Build Coastguard Worker     {
271*5e7646d2SAndroid Build Coastguard Worker      /*
272*5e7646d2SAndroid Build Coastguard Worker       * Try to localize a standard printer-state-reason keyword...
273*5e7646d2SAndroid Build Coastguard Worker       */
274*5e7646d2SAndroid Build Coastguard Worker 
275*5e7646d2SAndroid Build Coastguard Worker       char	msgid[1024],		/* State message identifier */
276*5e7646d2SAndroid Build Coastguard Worker 		*ptr;			/* Pointer to state suffix */
277*5e7646d2SAndroid Build Coastguard Worker       const char *message = NULL;	/* Localized message */
278*5e7646d2SAndroid Build Coastguard Worker 
279*5e7646d2SAndroid Build Coastguard Worker       snprintf(msgid, sizeof(msgid), "printer-state-reasons.%s", reason);
280*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = strrchr(msgid, '-')) != NULL && (!strcmp(ptr, "-error") || !strcmp(ptr, "-report") || !strcmp(ptr, "-warning")))
281*5e7646d2SAndroid Build Coastguard Worker         *ptr = '\0';
282*5e7646d2SAndroid Build Coastguard Worker 
283*5e7646d2SAndroid Build Coastguard Worker       message = _cupsLangString(lang, msgid);
284*5e7646d2SAndroid Build Coastguard Worker 
285*5e7646d2SAndroid Build Coastguard Worker       if (message && strcmp(message, msgid))
286*5e7646d2SAndroid Build Coastguard Worker       {
287*5e7646d2SAndroid Build Coastguard Worker         strlcpy(buffer, _cupsLangString(lang, message), bufsize);
288*5e7646d2SAndroid Build Coastguard Worker 	return (buffer);
289*5e7646d2SAndroid Build Coastguard Worker       }
290*5e7646d2SAndroid Build Coastguard Worker     }
291*5e7646d2SAndroid Build Coastguard Worker 
292*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
293*5e7646d2SAndroid Build Coastguard Worker   }
294*5e7646d2SAndroid Build Coastguard Worker 
295*5e7646d2SAndroid Build Coastguard Worker  /*
296*5e7646d2SAndroid Build Coastguard Worker   * Now find the value we need...
297*5e7646d2SAndroid Build Coastguard Worker   */
298*5e7646d2SAndroid Build Coastguard Worker 
299*5e7646d2SAndroid Build Coastguard Worker   bufend = buffer + bufsize - 1;
300*5e7646d2SAndroid Build Coastguard Worker 
301*5e7646d2SAndroid Build Coastguard Worker   if (!scheme || !strcmp(scheme, "text"))
302*5e7646d2SAndroid Build Coastguard Worker   {
303*5e7646d2SAndroid Build Coastguard Worker    /*
304*5e7646d2SAndroid Build Coastguard Worker     * Copy a text value (either the translation text or text:... URIs from
305*5e7646d2SAndroid Build Coastguard Worker     * the value...
306*5e7646d2SAndroid Build Coastguard Worker     */
307*5e7646d2SAndroid Build Coastguard Worker 
308*5e7646d2SAndroid Build Coastguard Worker     strlcpy(buffer, locattr->text, bufsize);
309*5e7646d2SAndroid Build Coastguard Worker 
310*5e7646d2SAndroid Build Coastguard Worker     for (valptr = locattr->value, bufptr = buffer; *valptr && bufptr < bufend;)
311*5e7646d2SAndroid Build Coastguard Worker     {
312*5e7646d2SAndroid Build Coastguard Worker       if (!strncmp(valptr, "text:", 5))
313*5e7646d2SAndroid Build Coastguard Worker       {
314*5e7646d2SAndroid Build Coastguard Worker        /*
315*5e7646d2SAndroid Build Coastguard Worker         * Decode text: URI and add to the buffer...
316*5e7646d2SAndroid Build Coastguard Worker 	*/
317*5e7646d2SAndroid Build Coastguard Worker 
318*5e7646d2SAndroid Build Coastguard Worker 	valptr += 5;
319*5e7646d2SAndroid Build Coastguard Worker 
320*5e7646d2SAndroid Build Coastguard Worker         while (*valptr && !_cups_isspace(*valptr) && bufptr < bufend)
321*5e7646d2SAndroid Build Coastguard Worker 	{
322*5e7646d2SAndroid Build Coastguard Worker 	  if (*valptr == '%' && isxdigit(valptr[1] & 255) &&
323*5e7646d2SAndroid Build Coastguard Worker 	      isxdigit(valptr[2] & 255))
324*5e7646d2SAndroid Build Coastguard Worker 	  {
325*5e7646d2SAndroid Build Coastguard Worker 	   /*
326*5e7646d2SAndroid Build Coastguard Worker 	    * Pull a hex-encoded character from the URI...
327*5e7646d2SAndroid Build Coastguard Worker 	    */
328*5e7646d2SAndroid Build Coastguard Worker 
329*5e7646d2SAndroid Build Coastguard Worker             valptr ++;
330*5e7646d2SAndroid Build Coastguard Worker 
331*5e7646d2SAndroid Build Coastguard Worker 	    if (isdigit(*valptr & 255))
332*5e7646d2SAndroid Build Coastguard Worker 	      ch = (*valptr - '0') << 4;
333*5e7646d2SAndroid Build Coastguard Worker 	    else
334*5e7646d2SAndroid Build Coastguard Worker 	      ch = (tolower(*valptr) - 'a' + 10) << 4;
335*5e7646d2SAndroid Build Coastguard Worker 	    valptr ++;
336*5e7646d2SAndroid Build Coastguard Worker 
337*5e7646d2SAndroid Build Coastguard Worker 	    if (isdigit(*valptr & 255))
338*5e7646d2SAndroid Build Coastguard Worker 	      *bufptr++ = (char)(ch | (*valptr - '0'));
339*5e7646d2SAndroid Build Coastguard Worker 	    else
340*5e7646d2SAndroid Build Coastguard Worker 	      *bufptr++ = (char)(ch | (tolower(*valptr) - 'a' + 10));
341*5e7646d2SAndroid Build Coastguard Worker 	    valptr ++;
342*5e7646d2SAndroid Build Coastguard Worker 	  }
343*5e7646d2SAndroid Build Coastguard Worker 	  else if (*valptr == '+')
344*5e7646d2SAndroid Build Coastguard Worker 	  {
345*5e7646d2SAndroid Build Coastguard Worker 	    *bufptr++ = ' ';
346*5e7646d2SAndroid Build Coastguard Worker 	    valptr ++;
347*5e7646d2SAndroid Build Coastguard Worker 	  }
348*5e7646d2SAndroid Build Coastguard Worker 	  else
349*5e7646d2SAndroid Build Coastguard Worker 	    *bufptr++ = *valptr++;
350*5e7646d2SAndroid Build Coastguard Worker         }
351*5e7646d2SAndroid Build Coastguard Worker       }
352*5e7646d2SAndroid Build Coastguard Worker       else
353*5e7646d2SAndroid Build Coastguard Worker       {
354*5e7646d2SAndroid Build Coastguard Worker        /*
355*5e7646d2SAndroid Build Coastguard Worker         * Skip this URI...
356*5e7646d2SAndroid Build Coastguard Worker 	*/
357*5e7646d2SAndroid Build Coastguard Worker 
358*5e7646d2SAndroid Build Coastguard Worker         while (*valptr && !_cups_isspace(*valptr))
359*5e7646d2SAndroid Build Coastguard Worker           valptr++;
360*5e7646d2SAndroid Build Coastguard Worker       }
361*5e7646d2SAndroid Build Coastguard Worker 
362*5e7646d2SAndroid Build Coastguard Worker      /*
363*5e7646d2SAndroid Build Coastguard Worker       * Skip whitespace...
364*5e7646d2SAndroid Build Coastguard Worker       */
365*5e7646d2SAndroid Build Coastguard Worker 
366*5e7646d2SAndroid Build Coastguard Worker       while (_cups_isspace(*valptr))
367*5e7646d2SAndroid Build Coastguard Worker 	valptr ++;
368*5e7646d2SAndroid Build Coastguard Worker     }
369*5e7646d2SAndroid Build Coastguard Worker 
370*5e7646d2SAndroid Build Coastguard Worker     if (bufptr > buffer)
371*5e7646d2SAndroid Build Coastguard Worker       *bufptr = '\0';
372*5e7646d2SAndroid Build Coastguard Worker 
373*5e7646d2SAndroid Build Coastguard Worker     return (buffer);
374*5e7646d2SAndroid Build Coastguard Worker   }
375*5e7646d2SAndroid Build Coastguard Worker   else
376*5e7646d2SAndroid Build Coastguard Worker   {
377*5e7646d2SAndroid Build Coastguard Worker    /*
378*5e7646d2SAndroid Build Coastguard Worker     * Copy a URI...
379*5e7646d2SAndroid Build Coastguard Worker     */
380*5e7646d2SAndroid Build Coastguard Worker 
381*5e7646d2SAndroid Build Coastguard Worker     schemelen = strlen(scheme);
382*5e7646d2SAndroid Build Coastguard Worker     if (scheme[schemelen - 1] == ':')	/* Force scheme to be just the name */
383*5e7646d2SAndroid Build Coastguard Worker       schemelen --;
384*5e7646d2SAndroid Build Coastguard Worker 
385*5e7646d2SAndroid Build Coastguard Worker     for (valptr = locattr->value, bufptr = buffer; *valptr && bufptr < bufend;)
386*5e7646d2SAndroid Build Coastguard Worker     {
387*5e7646d2SAndroid Build Coastguard Worker       if ((!strncmp(valptr, scheme, schemelen) && valptr[schemelen] == ':') ||
388*5e7646d2SAndroid Build Coastguard Worker           (*valptr == '/' && !strcmp(scheme, "file")))
389*5e7646d2SAndroid Build Coastguard Worker       {
390*5e7646d2SAndroid Build Coastguard Worker        /*
391*5e7646d2SAndroid Build Coastguard Worker         * Copy URI...
392*5e7646d2SAndroid Build Coastguard Worker 	*/
393*5e7646d2SAndroid Build Coastguard Worker 
394*5e7646d2SAndroid Build Coastguard Worker         while (*valptr && !_cups_isspace(*valptr) && bufptr < bufend)
395*5e7646d2SAndroid Build Coastguard Worker 	  *bufptr++ = *valptr++;
396*5e7646d2SAndroid Build Coastguard Worker 
397*5e7646d2SAndroid Build Coastguard Worker 	*bufptr = '\0';
398*5e7646d2SAndroid Build Coastguard Worker 
399*5e7646d2SAndroid Build Coastguard Worker 	return (buffer);
400*5e7646d2SAndroid Build Coastguard Worker       }
401*5e7646d2SAndroid Build Coastguard Worker       else
402*5e7646d2SAndroid Build Coastguard Worker       {
403*5e7646d2SAndroid Build Coastguard Worker        /*
404*5e7646d2SAndroid Build Coastguard Worker         * Skip this URI...
405*5e7646d2SAndroid Build Coastguard Worker 	*/
406*5e7646d2SAndroid Build Coastguard Worker 
407*5e7646d2SAndroid Build Coastguard Worker 	while (*valptr && !_cups_isspace(*valptr))
408*5e7646d2SAndroid Build Coastguard Worker 	  valptr++;
409*5e7646d2SAndroid Build Coastguard Worker       }
410*5e7646d2SAndroid Build Coastguard Worker 
411*5e7646d2SAndroid Build Coastguard Worker      /*
412*5e7646d2SAndroid Build Coastguard Worker       * Skip whitespace...
413*5e7646d2SAndroid Build Coastguard Worker       */
414*5e7646d2SAndroid Build Coastguard Worker 
415*5e7646d2SAndroid Build Coastguard Worker       while (_cups_isspace(*valptr))
416*5e7646d2SAndroid Build Coastguard Worker 	valptr ++;
417*5e7646d2SAndroid Build Coastguard Worker     }
418*5e7646d2SAndroid Build Coastguard Worker 
419*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
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 /*
425*5e7646d2SAndroid Build Coastguard Worker  * 'ppdLocalizeMarkerName()' - Get the localized version of a marker-names
426*5e7646d2SAndroid Build Coastguard Worker  *                             attribute value.
427*5e7646d2SAndroid Build Coastguard Worker  *
428*5e7646d2SAndroid Build Coastguard Worker  * This function uses the current locale to find the corresponding name
429*5e7646d2SAndroid Build Coastguard Worker  * text from the attribute value. If no localized text for the requested
430*5e7646d2SAndroid Build Coastguard Worker  * name can be found, @code NULL@ is returned.
431*5e7646d2SAndroid Build Coastguard Worker  *
432*5e7646d2SAndroid Build Coastguard Worker  * @since CUPS 1.4/macOS 10.6@
433*5e7646d2SAndroid Build Coastguard Worker  */
434*5e7646d2SAndroid Build Coastguard Worker 
435*5e7646d2SAndroid Build Coastguard Worker const char *				/* O - Value or @code NULL@ if not found */
ppdLocalizeMarkerName(ppd_file_t * ppd,const char * name)436*5e7646d2SAndroid Build Coastguard Worker ppdLocalizeMarkerName(
437*5e7646d2SAndroid Build Coastguard Worker     ppd_file_t *ppd,			/* I - PPD file */
438*5e7646d2SAndroid Build Coastguard Worker     const char *name)			/* I - Marker name to look up */
439*5e7646d2SAndroid Build Coastguard Worker {
440*5e7646d2SAndroid Build Coastguard Worker   ppd_attr_t	*locattr;		/* Localized attribute */
441*5e7646d2SAndroid Build Coastguard Worker   char		ll_CC[6];		/* Language + country locale */
442*5e7646d2SAndroid Build Coastguard Worker 
443*5e7646d2SAndroid Build Coastguard Worker 
444*5e7646d2SAndroid Build Coastguard Worker  /*
445*5e7646d2SAndroid Build Coastguard Worker   * Range check input...
446*5e7646d2SAndroid Build Coastguard Worker   */
447*5e7646d2SAndroid Build Coastguard Worker 
448*5e7646d2SAndroid Build Coastguard Worker   if (!ppd || !name)
449*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
450*5e7646d2SAndroid Build Coastguard Worker 
451*5e7646d2SAndroid Build Coastguard Worker  /*
452*5e7646d2SAndroid Build Coastguard Worker   * Get the default language...
453*5e7646d2SAndroid Build Coastguard Worker   */
454*5e7646d2SAndroid Build Coastguard Worker 
455*5e7646d2SAndroid Build Coastguard Worker   ppd_ll_CC(ll_CC, sizeof(ll_CC));
456*5e7646d2SAndroid Build Coastguard Worker 
457*5e7646d2SAndroid Build Coastguard Worker  /*
458*5e7646d2SAndroid Build Coastguard Worker   * Find the localized attribute...
459*5e7646d2SAndroid Build Coastguard Worker   */
460*5e7646d2SAndroid Build Coastguard Worker 
461*5e7646d2SAndroid Build Coastguard Worker   if ((locattr = _ppdLocalizedAttr(ppd, "cupsMarkerName", name,
462*5e7646d2SAndroid Build Coastguard Worker                                    ll_CC)) == NULL)
463*5e7646d2SAndroid Build Coastguard Worker     locattr = ppdFindAttr(ppd, "cupsMarkerName", name);
464*5e7646d2SAndroid Build Coastguard Worker 
465*5e7646d2SAndroid Build Coastguard Worker   return (locattr ? locattr->text : NULL);
466*5e7646d2SAndroid Build Coastguard Worker }
467*5e7646d2SAndroid Build Coastguard Worker 
468*5e7646d2SAndroid Build Coastguard Worker 
469*5e7646d2SAndroid Build Coastguard Worker /*
470*5e7646d2SAndroid Build Coastguard Worker  * '_ppdFreeLanguages()' - Free an array of languages from _ppdGetLanguages.
471*5e7646d2SAndroid Build Coastguard Worker  */
472*5e7646d2SAndroid Build Coastguard Worker 
473*5e7646d2SAndroid Build Coastguard Worker void
_ppdFreeLanguages(cups_array_t * languages)474*5e7646d2SAndroid Build Coastguard Worker _ppdFreeLanguages(
475*5e7646d2SAndroid Build Coastguard Worker     cups_array_t *languages)		/* I - Languages array */
476*5e7646d2SAndroid Build Coastguard Worker {
477*5e7646d2SAndroid Build Coastguard Worker   char	*language;			/* Current language */
478*5e7646d2SAndroid Build Coastguard Worker 
479*5e7646d2SAndroid Build Coastguard Worker 
480*5e7646d2SAndroid Build Coastguard Worker   for (language = (char *)cupsArrayFirst(languages);
481*5e7646d2SAndroid Build Coastguard Worker        language;
482*5e7646d2SAndroid Build Coastguard Worker        language = (char *)cupsArrayNext(languages))
483*5e7646d2SAndroid Build Coastguard Worker     free(language);
484*5e7646d2SAndroid Build Coastguard Worker 
485*5e7646d2SAndroid Build Coastguard Worker   cupsArrayDelete(languages);
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  * '_ppdGetLanguages()' - Get an array of languages from a PPD file.
491*5e7646d2SAndroid Build Coastguard Worker  */
492*5e7646d2SAndroid Build Coastguard Worker 
493*5e7646d2SAndroid Build Coastguard Worker cups_array_t *				/* O - Languages array */
_ppdGetLanguages(ppd_file_t * ppd)494*5e7646d2SAndroid Build Coastguard Worker _ppdGetLanguages(ppd_file_t *ppd)	/* I - PPD file */
495*5e7646d2SAndroid Build Coastguard Worker {
496*5e7646d2SAndroid Build Coastguard Worker   cups_array_t	*languages;		/* Languages array */
497*5e7646d2SAndroid Build Coastguard Worker   ppd_attr_t	*attr;			/* cupsLanguages attribute */
498*5e7646d2SAndroid Build Coastguard Worker   char		*value,			/* Copy of attribute value */
499*5e7646d2SAndroid Build Coastguard Worker 		*start,			/* Start of current language */
500*5e7646d2SAndroid Build Coastguard Worker 		*ptr;			/* Pointer into languages */
501*5e7646d2SAndroid Build Coastguard Worker 
502*5e7646d2SAndroid Build Coastguard Worker 
503*5e7646d2SAndroid Build Coastguard Worker  /*
504*5e7646d2SAndroid Build Coastguard Worker   * See if we have a cupsLanguages attribute...
505*5e7646d2SAndroid Build Coastguard Worker   */
506*5e7646d2SAndroid Build Coastguard Worker 
507*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) == NULL || !attr->value)
508*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
509*5e7646d2SAndroid Build Coastguard Worker 
510*5e7646d2SAndroid Build Coastguard Worker  /*
511*5e7646d2SAndroid Build Coastguard Worker   * Yes, load the list...
512*5e7646d2SAndroid Build Coastguard Worker   */
513*5e7646d2SAndroid Build Coastguard Worker 
514*5e7646d2SAndroid Build Coastguard Worker   if ((languages = cupsArrayNew((cups_array_func_t)strcmp, NULL)) == NULL)
515*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
516*5e7646d2SAndroid Build Coastguard Worker 
517*5e7646d2SAndroid Build Coastguard Worker   if ((value = strdup(attr->value)) == NULL)
518*5e7646d2SAndroid Build Coastguard Worker   {
519*5e7646d2SAndroid Build Coastguard Worker     cupsArrayDelete(languages);
520*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
521*5e7646d2SAndroid Build Coastguard Worker   }
522*5e7646d2SAndroid Build Coastguard Worker 
523*5e7646d2SAndroid Build Coastguard Worker   for (ptr = value; *ptr;)
524*5e7646d2SAndroid Build Coastguard Worker   {
525*5e7646d2SAndroid Build Coastguard Worker    /*
526*5e7646d2SAndroid Build Coastguard Worker     * Skip leading whitespace...
527*5e7646d2SAndroid Build Coastguard Worker     */
528*5e7646d2SAndroid Build Coastguard Worker 
529*5e7646d2SAndroid Build Coastguard Worker     while (_cups_isspace(*ptr))
530*5e7646d2SAndroid Build Coastguard Worker       ptr ++;
531*5e7646d2SAndroid Build Coastguard Worker 
532*5e7646d2SAndroid Build Coastguard Worker     if (!*ptr)
533*5e7646d2SAndroid Build Coastguard Worker       break;
534*5e7646d2SAndroid Build Coastguard Worker 
535*5e7646d2SAndroid Build Coastguard Worker    /*
536*5e7646d2SAndroid Build Coastguard Worker     * Find the end of this language name...
537*5e7646d2SAndroid Build Coastguard Worker     */
538*5e7646d2SAndroid Build Coastguard Worker 
539*5e7646d2SAndroid Build Coastguard Worker     for (start = ptr; *ptr && !_cups_isspace(*ptr); ptr ++);
540*5e7646d2SAndroid Build Coastguard Worker 
541*5e7646d2SAndroid Build Coastguard Worker     if (*ptr)
542*5e7646d2SAndroid Build Coastguard Worker       *ptr++ = '\0';
543*5e7646d2SAndroid Build Coastguard Worker 
544*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(start, "en"))
545*5e7646d2SAndroid Build Coastguard Worker       continue;
546*5e7646d2SAndroid Build Coastguard Worker 
547*5e7646d2SAndroid Build Coastguard Worker     cupsArrayAdd(languages, strdup(start));
548*5e7646d2SAndroid Build Coastguard Worker   }
549*5e7646d2SAndroid Build Coastguard Worker 
550*5e7646d2SAndroid Build Coastguard Worker  /*
551*5e7646d2SAndroid Build Coastguard Worker   * Free the temporary string and return either an array with one or more
552*5e7646d2SAndroid Build Coastguard Worker   * values or a NULL pointer...
553*5e7646d2SAndroid Build Coastguard Worker   */
554*5e7646d2SAndroid Build Coastguard Worker 
555*5e7646d2SAndroid Build Coastguard Worker   free(value);
556*5e7646d2SAndroid Build Coastguard Worker 
557*5e7646d2SAndroid Build Coastguard Worker   if (cupsArrayCount(languages) == 0)
558*5e7646d2SAndroid Build Coastguard Worker   {
559*5e7646d2SAndroid Build Coastguard Worker     cupsArrayDelete(languages);
560*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
561*5e7646d2SAndroid Build Coastguard Worker   }
562*5e7646d2SAndroid Build Coastguard Worker   else
563*5e7646d2SAndroid Build Coastguard Worker     return (languages);
564*5e7646d2SAndroid Build Coastguard Worker }
565*5e7646d2SAndroid Build Coastguard Worker 
566*5e7646d2SAndroid Build Coastguard Worker 
567*5e7646d2SAndroid Build Coastguard Worker /*
568*5e7646d2SAndroid Build Coastguard Worker  * '_ppdHashName()' - Generate a hash value for a device or profile name.
569*5e7646d2SAndroid Build Coastguard Worker  *
570*5e7646d2SAndroid Build Coastguard Worker  * This function is primarily used on macOS, but is generally accessible
571*5e7646d2SAndroid Build Coastguard Worker  * since cupstestppd needs to check for profile name collisions in PPD files...
572*5e7646d2SAndroid Build Coastguard Worker  */
573*5e7646d2SAndroid Build Coastguard Worker 
574*5e7646d2SAndroid Build Coastguard Worker unsigned				/* O - Hash value */
_ppdHashName(const char * name)575*5e7646d2SAndroid Build Coastguard Worker _ppdHashName(const char *name)		/* I - Name to hash */
576*5e7646d2SAndroid Build Coastguard Worker {
577*5e7646d2SAndroid Build Coastguard Worker   unsigned	mult,			/* Multiplier */
578*5e7646d2SAndroid Build Coastguard Worker 		hash = 0;		/* Hash value */
579*5e7646d2SAndroid Build Coastguard Worker 
580*5e7646d2SAndroid Build Coastguard Worker 
581*5e7646d2SAndroid Build Coastguard Worker   for (mult = 1; *name && mult <= 128; mult ++, name ++)
582*5e7646d2SAndroid Build Coastguard Worker     hash += (*name & 255) * mult;
583*5e7646d2SAndroid Build Coastguard Worker 
584*5e7646d2SAndroid Build Coastguard Worker   return (hash);
585*5e7646d2SAndroid Build Coastguard Worker }
586*5e7646d2SAndroid Build Coastguard Worker 
587*5e7646d2SAndroid Build Coastguard Worker 
588*5e7646d2SAndroid Build Coastguard Worker /*
589*5e7646d2SAndroid Build Coastguard Worker  * '_ppdLocalizedAttr()' - Find a localized attribute.
590*5e7646d2SAndroid Build Coastguard Worker  */
591*5e7646d2SAndroid Build Coastguard Worker 
592*5e7646d2SAndroid Build Coastguard Worker ppd_attr_t *				/* O - Localized attribute or NULL */
_ppdLocalizedAttr(ppd_file_t * ppd,const char * keyword,const char * spec,const char * ll_CC)593*5e7646d2SAndroid Build Coastguard Worker _ppdLocalizedAttr(ppd_file_t *ppd,	/* I - PPD file */
594*5e7646d2SAndroid Build Coastguard Worker 		  const char *keyword,	/* I - Main keyword */
595*5e7646d2SAndroid Build Coastguard Worker 		  const char *spec,	/* I - Option keyword */
596*5e7646d2SAndroid Build Coastguard Worker 		  const char *ll_CC)	/* I - Language + country locale */
597*5e7646d2SAndroid Build Coastguard Worker {
598*5e7646d2SAndroid Build Coastguard Worker   char		lkeyword[PPD_MAX_NAME];	/* Localization keyword */
599*5e7646d2SAndroid Build Coastguard Worker   ppd_attr_t	*attr;			/* Current attribute */
600*5e7646d2SAndroid Build Coastguard Worker 
601*5e7646d2SAndroid Build Coastguard Worker 
602*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("4_ppdLocalizedAttr(ppd=%p, keyword=\"%s\", spec=\"%s\", "
603*5e7646d2SAndroid Build Coastguard Worker                 "ll_CC=\"%s\")", ppd, keyword, spec, ll_CC));
604*5e7646d2SAndroid Build Coastguard Worker 
605*5e7646d2SAndroid Build Coastguard Worker  /*
606*5e7646d2SAndroid Build Coastguard Worker   * Look for Keyword.ll_CC, then Keyword.ll...
607*5e7646d2SAndroid Build Coastguard Worker   */
608*5e7646d2SAndroid Build Coastguard Worker 
609*5e7646d2SAndroid Build Coastguard Worker   snprintf(lkeyword, sizeof(lkeyword), "%s.%s", ll_CC, keyword);
610*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ppdFindAttr(ppd, lkeyword, spec)) == NULL)
611*5e7646d2SAndroid Build Coastguard Worker   {
612*5e7646d2SAndroid Build Coastguard Worker    /*
613*5e7646d2SAndroid Build Coastguard Worker     * <rdar://problem/22130168>
614*5e7646d2SAndroid Build Coastguard Worker     *
615*5e7646d2SAndroid Build Coastguard Worker     * Multiple locales need special handling...  Sigh...
616*5e7646d2SAndroid Build Coastguard Worker     */
617*5e7646d2SAndroid Build Coastguard Worker 
618*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(ll_CC, "zh_HK"))
619*5e7646d2SAndroid Build Coastguard Worker     {
620*5e7646d2SAndroid Build Coastguard Worker       snprintf(lkeyword, sizeof(lkeyword), "zh_TW.%s", keyword);
621*5e7646d2SAndroid Build Coastguard Worker       attr = ppdFindAttr(ppd, lkeyword, spec);
622*5e7646d2SAndroid Build Coastguard Worker     }
623*5e7646d2SAndroid Build Coastguard Worker 
624*5e7646d2SAndroid Build Coastguard Worker     if (!attr)
625*5e7646d2SAndroid Build Coastguard Worker     {
626*5e7646d2SAndroid Build Coastguard Worker       snprintf(lkeyword, sizeof(lkeyword), "%2.2s.%s", ll_CC, keyword);
627*5e7646d2SAndroid Build Coastguard Worker       attr = ppdFindAttr(ppd, lkeyword, spec);
628*5e7646d2SAndroid Build Coastguard Worker     }
629*5e7646d2SAndroid Build Coastguard Worker 
630*5e7646d2SAndroid Build Coastguard Worker     if (!attr)
631*5e7646d2SAndroid Build Coastguard Worker     {
632*5e7646d2SAndroid Build Coastguard Worker       if (!strncmp(ll_CC, "ja", 2))
633*5e7646d2SAndroid Build Coastguard Worker       {
634*5e7646d2SAndroid Build Coastguard Worker        /*
635*5e7646d2SAndroid Build Coastguard Worker 	* Due to a bug in the CUPS DDK 1.1.0 ppdmerge program, Japanese
636*5e7646d2SAndroid Build Coastguard Worker 	* PPD files were incorrectly assigned "jp" as the locale name
637*5e7646d2SAndroid Build Coastguard Worker 	* instead of "ja".  Support both the old (incorrect) and new
638*5e7646d2SAndroid Build Coastguard Worker 	* locale names for Japanese...
639*5e7646d2SAndroid Build Coastguard Worker 	*/
640*5e7646d2SAndroid Build Coastguard Worker 
641*5e7646d2SAndroid Build Coastguard Worker 	snprintf(lkeyword, sizeof(lkeyword), "jp.%s", keyword);
642*5e7646d2SAndroid Build Coastguard Worker 	attr = ppdFindAttr(ppd, lkeyword, spec);
643*5e7646d2SAndroid Build Coastguard Worker       }
644*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(ll_CC, "nb", 2))
645*5e7646d2SAndroid Build Coastguard Worker       {
646*5e7646d2SAndroid Build Coastguard Worker        /*
647*5e7646d2SAndroid Build Coastguard Worker 	* Norway has two languages, "Bokmal" (the primary one)
648*5e7646d2SAndroid Build Coastguard Worker 	* and "Nynorsk" (new Norwegian); this code maps from the (currently)
649*5e7646d2SAndroid Build Coastguard Worker 	* recommended "nb" to the previously recommended "no"...
650*5e7646d2SAndroid Build Coastguard Worker 	*/
651*5e7646d2SAndroid Build Coastguard Worker 
652*5e7646d2SAndroid Build Coastguard Worker 	snprintf(lkeyword, sizeof(lkeyword), "no.%s", keyword);
653*5e7646d2SAndroid Build Coastguard Worker 	attr = ppdFindAttr(ppd, lkeyword, spec);
654*5e7646d2SAndroid Build Coastguard Worker       }
655*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(ll_CC, "no", 2))
656*5e7646d2SAndroid Build Coastguard Worker       {
657*5e7646d2SAndroid Build Coastguard Worker        /*
658*5e7646d2SAndroid Build Coastguard Worker 	* Norway has two languages, "Bokmal" (the primary one)
659*5e7646d2SAndroid Build Coastguard Worker 	* and "Nynorsk" (new Norwegian); we map "no" to "nb" here as
660*5e7646d2SAndroid Build Coastguard Worker 	* recommended by the locale folks...
661*5e7646d2SAndroid Build Coastguard Worker 	*/
662*5e7646d2SAndroid Build Coastguard Worker 
663*5e7646d2SAndroid Build Coastguard Worker 	snprintf(lkeyword, sizeof(lkeyword), "nb.%s", keyword);
664*5e7646d2SAndroid Build Coastguard Worker 	attr = ppdFindAttr(ppd, lkeyword, spec);
665*5e7646d2SAndroid Build Coastguard Worker       }
666*5e7646d2SAndroid Build Coastguard Worker     }
667*5e7646d2SAndroid Build Coastguard Worker   }
668*5e7646d2SAndroid Build Coastguard Worker 
669*5e7646d2SAndroid Build Coastguard Worker #ifdef DEBUG
670*5e7646d2SAndroid Build Coastguard Worker   if (attr)
671*5e7646d2SAndroid Build Coastguard Worker     DEBUG_printf(("5_ppdLocalizedAttr: *%s %s/%s: \"%s\"\n", attr->name,
672*5e7646d2SAndroid Build Coastguard Worker                   attr->spec, attr->text, attr->value ? attr->value : ""));
673*5e7646d2SAndroid Build Coastguard Worker   else
674*5e7646d2SAndroid Build Coastguard Worker     DEBUG_puts("5_ppdLocalizedAttr: NOT FOUND");
675*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG */
676*5e7646d2SAndroid Build Coastguard Worker 
677*5e7646d2SAndroid Build Coastguard Worker   return (attr);
678*5e7646d2SAndroid Build Coastguard Worker }
679*5e7646d2SAndroid Build Coastguard Worker 
680*5e7646d2SAndroid Build Coastguard Worker 
681*5e7646d2SAndroid Build Coastguard Worker /*
682*5e7646d2SAndroid Build Coastguard Worker  * 'ppd_ll_CC()' - Get the current locale names.
683*5e7646d2SAndroid Build Coastguard Worker  */
684*5e7646d2SAndroid Build Coastguard Worker 
685*5e7646d2SAndroid Build Coastguard Worker static cups_lang_t *			/* O - Current language */
ppd_ll_CC(char * ll_CC,size_t ll_CC_size)686*5e7646d2SAndroid Build Coastguard Worker ppd_ll_CC(char   *ll_CC,		/* O - Country-specific locale name */
687*5e7646d2SAndroid Build Coastguard Worker           size_t ll_CC_size)		/* I - Size of country-specific name */
688*5e7646d2SAndroid Build Coastguard Worker {
689*5e7646d2SAndroid Build Coastguard Worker   cups_lang_t	*lang;			/* Current language */
690*5e7646d2SAndroid Build Coastguard Worker 
691*5e7646d2SAndroid Build Coastguard Worker 
692*5e7646d2SAndroid Build Coastguard Worker  /*
693*5e7646d2SAndroid Build Coastguard Worker   * Get the current locale...
694*5e7646d2SAndroid Build Coastguard Worker   */
695*5e7646d2SAndroid Build Coastguard Worker 
696*5e7646d2SAndroid Build Coastguard Worker   if ((lang = cupsLangDefault()) == NULL)
697*5e7646d2SAndroid Build Coastguard Worker   {
698*5e7646d2SAndroid Build Coastguard Worker     strlcpy(ll_CC, "en_US", ll_CC_size);
699*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
700*5e7646d2SAndroid Build Coastguard Worker   }
701*5e7646d2SAndroid Build Coastguard Worker 
702*5e7646d2SAndroid Build Coastguard Worker  /*
703*5e7646d2SAndroid Build Coastguard Worker   * Copy the locale name...
704*5e7646d2SAndroid Build Coastguard Worker   */
705*5e7646d2SAndroid Build Coastguard Worker 
706*5e7646d2SAndroid Build Coastguard Worker   strlcpy(ll_CC, lang->language, ll_CC_size);
707*5e7646d2SAndroid Build Coastguard Worker 
708*5e7646d2SAndroid Build Coastguard Worker   if (strlen(ll_CC) == 2)
709*5e7646d2SAndroid Build Coastguard Worker   {
710*5e7646d2SAndroid Build Coastguard Worker    /*
711*5e7646d2SAndroid Build Coastguard Worker     * Map "ll" to primary/origin country locales to have the best
712*5e7646d2SAndroid Build Coastguard Worker     * chance of finding a match...
713*5e7646d2SAndroid Build Coastguard Worker     */
714*5e7646d2SAndroid Build Coastguard Worker 
715*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(ll_CC, "cs"))
716*5e7646d2SAndroid Build Coastguard Worker       strlcpy(ll_CC, "cs_CZ", ll_CC_size);
717*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(ll_CC, "en"))
718*5e7646d2SAndroid Build Coastguard Worker       strlcpy(ll_CC, "en_US", ll_CC_size);
719*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(ll_CC, "ja"))
720*5e7646d2SAndroid Build Coastguard Worker       strlcpy(ll_CC, "ja_JP", ll_CC_size);
721*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(ll_CC, "sv"))
722*5e7646d2SAndroid Build Coastguard Worker       strlcpy(ll_CC, "sv_SE", ll_CC_size);
723*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(ll_CC, "zh"))	/* Simplified Chinese */
724*5e7646d2SAndroid Build Coastguard Worker       strlcpy(ll_CC, "zh_CN", ll_CC_size);
725*5e7646d2SAndroid Build Coastguard Worker   }
726*5e7646d2SAndroid Build Coastguard Worker 
727*5e7646d2SAndroid Build Coastguard Worker   DEBUG_printf(("8ppd_ll_CC: lang->language=\"%s\", ll_CC=\"%s\"...",
728*5e7646d2SAndroid Build Coastguard Worker                 lang->language, ll_CC));
729*5e7646d2SAndroid Build Coastguard Worker   return (lang);
730*5e7646d2SAndroid Build Coastguard Worker }
731