]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/language.c
Mirror 1.1.x changes...
[thirdparty/cups.git] / cups / language.c
1 /*
2 * "$Id: language.c,v 1.20.2.12 2003/01/24 20:45:13 mike Exp $"
3 *
4 * I18N/language support for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2003 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * cupsEncodingName() - Return the character encoding name string
29 * for the given encoding enumeration.
30 * cupsLangEncoding() - Return the character encoding (us-ascii, etc.)
31 * for the given language.
32 * cupsLangFlush() - Flush all language data out of the cache.
33 * cupsLangFree() - Free language data.
34 * cupsLangGet() - Get a language.
35 */
36
37 /*
38 * Include necessary headers...
39 */
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <ctype.h>
44 #include "string.h"
45 #include "language.h"
46
47
48 /*
49 * Local globals...
50 */
51
52 static cups_lang_t *lang_cache = NULL; /* Language string cache */
53 static const char *lang_blank = ""; /* Blank constant string */
54 static const char * const lang_encodings[] = /* Encoding strings */
55 {
56 "us-ascii", "iso-8859-1",
57 "iso-8859-2", "iso-8859-3",
58 "iso-8859-4", "iso-8859-5",
59 "iso-8859-6", "iso-8859-7",
60 "iso-8859-8", "iso-8859-9",
61 "iso-8859-10", "utf-8",
62 "iso-8859-13", "iso-8859-14",
63 "iso-8859-15", "windows-874",
64 "windows-1250", "windows-1251",
65 "windows-1252", "windows-1253",
66 "windows-1254", "windows-1255",
67 "windows-1256", "windows-1257",
68 "windows-1258", "koi8-r",
69 "koi8-u", "iso-8859-11",
70 "iso-8859-16", "unknown",
71 "unknown", "unknown",
72 "unknown", "unknown",
73 "unknown", "unknown",
74 "unknown", "unknown",
75 "unknown", "unknown",
76 "unknown", "unknown",
77 "unknown", "unknown",
78 "unknown", "unknown",
79 "unknown", "unknown",
80 "unknown", "unknown",
81 "unknown", "unknown",
82 "unknown", "unknown",
83 "unknown", "unknown",
84 "unknown", "unknown",
85 "unknown", "unknown",
86 "unknown", "unknown",
87 "unknown", "unknown",
88 "windows-932", "windows-936",
89 "windows-949", "windows-950",
90 "windows-1361", "unknown",
91 "unknown", "unknown",
92 "unknown", "unknown",
93 "unknown", "unknown",
94 "unknown", "unknown",
95 "unknown", "unknown",
96 "unknown", "unknown",
97 "unknown", "unknown",
98 "unknown", "unknown",
99 "unknown", "unknown",
100 "unknown", "unknown",
101 "unknown", "unknown",
102 "unknown", "unknown",
103 "unknown", "unknown",
104 "unknown", "unknown",
105 "unknown", "unknown",
106 "unknown", "unknown",
107 "unknown", "unknown",
108 "unknown", "unknown",
109 "unknown", "unknown",
110 "unknown", "unknown",
111 "unknown", "unknown",
112 "unknown", "unknown",
113 "unknown", "unknown",
114 "unknown", "unknown",
115 "unknown", "unknown",
116 "unknown", "unknown",
117 "unknown", "unknown",
118 "unknown", "unknown",
119 "unknown", "unknown",
120 "euc-cn", "euc-jp",
121 "euc-kr", "euc-tw"
122 };
123 static const char *const lang_default[] = /* Default POSIX locale */
124 {
125 #include "cups_C.h"
126 NULL
127 };
128
129
130 /*
131 * 'cupsEncodingName()' - Return the character encoding name string
132 * for the given encoding enumeration.
133 */
134
135 const char * /* O - Character encoding */
136 cupsEncodingName(cups_encoding_t encoding)
137 /* I - Encoding enum */
138 {
139 if (encoding < 0 ||
140 encoding >= (sizeof(lang_encodings) / sizeof(const char *)))
141 return (lang_encodings[0]);
142 else
143 return (lang_encodings[encoding]);
144 }
145
146
147 /*
148 * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.)
149 * for the given language.
150 */
151
152 const char * /* O - Character encoding */
153 cupsLangEncoding(cups_lang_t *lang) /* I - Language data */
154 {
155 if (lang == NULL)
156 return ((char*)lang_encodings[0]);
157 else
158 return ((char*)lang_encodings[lang->encoding]);
159 }
160
161
162 /*
163 * 'cupsLangFlush()' - Flush all language data out of the cache.
164 */
165
166 void
167 cupsLangFlush(void)
168 {
169 int i; /* Looping var */
170 cups_lang_t *lang, /* Current language */
171 *next; /* Next language */
172
173
174 for (lang = lang_cache; lang != NULL; lang = next)
175 {
176 for (i = 0; i < CUPS_MSG_MAX; i ++)
177 if (lang->messages[i] != NULL && lang->messages[i] != lang_blank)
178 free(lang->messages[i]);
179
180 next = lang->next;
181 free(lang);
182 }
183 }
184
185
186 /*
187 * 'cupsLangFree()' - Free language data.
188 *
189 * This does not actually free anything; use cupsLangFlush() for that.
190 */
191
192 void
193 cupsLangFree(cups_lang_t *lang) /* I - Language to free */
194 {
195 if (lang != NULL && lang->used > 0)
196 lang->used --;
197 }
198
199
200 /*
201 * 'cupsLangGet()' - Get a language.
202 */
203
204 cups_lang_t * /* O - Language data */
205 cupsLangGet(const char *language) /* I - Language or locale */
206 {
207 int i, count; /* Looping vars */
208 char langname[32], /* Requested language name */
209 *langptr, /* Pointer into language name */
210 real[32], /* Real language name */
211 *realptr, /* Pointer into real language name */
212 filename[1024], /* Filename for language locale file */
213 *localedir; /* Directory for locale files */
214 FILE *fp; /* Language locale file pointer */
215 char line[1024]; /* Line from file */
216 cups_msg_t msg; /* Message number */
217 char *text; /* Message text */
218 cups_lang_t *lang; /* Current language... */
219
220
221 /*
222 * Convert the language string passed in to a locale string. "C" is the
223 * standard POSIX locale and is copied unchanged. Otherwise the
224 * language string is converted from ll-cc (language-country) to ll_cc
225 * to match the file naming convention used by all POSIX-compliant
226 * operating systems.
227 */
228
229 if (language == NULL || language[0] == '\0' ||
230 strcmp(language, "POSIX") == 0)
231 strcpy(langname, "C");
232 else
233 {
234 /*
235 * Copy the locale string over safely...
236 */
237
238 strlcpy(langname, language, sizeof(langname));
239 }
240
241 if (strlen(langname) < 2)
242 strcpy(real, "C");
243 else
244 {
245 /*
246 * Convert the language name to a normalized form, e.g.:
247 *
248 * ll[_CC[.charset]]
249 */
250
251 real[0] = tolower(langname[0]);
252 real[1] = tolower(langname[1]);
253 realptr = real + 2;
254 langptr = langname + 2;
255
256 if (*langptr == '_' || *langptr == '-')
257 {
258 /*
259 * Add country code...
260 */
261
262 *realptr++ = '_';
263 langptr ++;
264
265 *realptr++ = toupper(*langptr++);
266 *realptr++ = toupper(*langptr++);
267 }
268
269 if (*langptr == '.')
270 {
271 /*
272 * Add charset...
273 */
274
275 *langptr++ = '\0';
276 *realptr++ = '.';
277
278 while (*langptr)
279 {
280 if ((realptr - real) < (sizeof(real) - 1) &&
281 *langptr != '-' && *langptr != '_')
282 *realptr++ = tolower(*langptr++);
283 else
284 langptr ++;
285 }
286 }
287
288 *realptr = '\0';
289 }
290
291 /*
292 * See if we already have this language loaded...
293 */
294
295 for (lang = lang_cache; lang != NULL; lang = lang->next)
296 if (strcmp(lang->language, langname) == 0)
297 {
298 lang->used ++;
299
300 return (lang);
301 }
302
303
304 /*
305 * Next try to open a locale file; we will try the charset-localized
306 * file first, then the country-localized file, and finally look for
307 * a generic language file. If all else fails we will use the POSIX
308 * locale.
309 */
310
311 if ((localedir = getenv("LOCALEDIR")) == NULL)
312 localedir = CUPS_LOCALEDIR;
313
314 do
315 {
316 snprintf(filename, sizeof(filename), "%s/%s/cups_%s", localedir,
317 real, real);
318
319 if ((fp = fopen(filename, "r")) == NULL)
320 {
321 if ((realptr = strchr(real, '.')) != NULL)
322 *realptr = '\0';
323 else if ((realptr = strchr(real, '_')) != NULL)
324 *realptr = '\0';
325 }
326 }
327 while (fp == NULL && strchr(real, '_') != NULL && strchr(real, '.') != NULL);
328
329 /*
330 * OK, we have an open messages file; the first line will contain the
331 * language encoding (us-ascii, iso-8859-1, etc.), and the rest will
332 * be messages consisting of:
333 *
334 * #### SP message text
335 *
336 * or:
337 *
338 * message text
339 *
340 * If the line starts with a number, then message processing picks up
341 * where the number indicates. Otherwise the last message number is
342 * incremented.
343 *
344 * All leading whitespace is deleted.
345 */
346
347 if (fp == NULL)
348 strlcpy(line, lang_default[0], sizeof(line));
349 else if (fgets(line, sizeof(line), fp) == NULL)
350 {
351 /*
352 * Can't read encoding!
353 */
354
355 fclose(fp);
356 return (NULL);
357 }
358
359 i = strlen(line) - 1;
360 if (line[i] == '\n')
361 line[i] = '\0'; /* Strip LF */
362
363 /*
364 * See if there is a free language available; if so, use that
365 * record...
366 */
367
368 for (lang = lang_cache; lang != NULL; lang = lang->next)
369 if (lang->used == 0)
370 break;
371
372 if (lang == NULL)
373 {
374 /*
375 * Allocate memory for the language and add it to the cache.
376 */
377
378 if ((lang = calloc(sizeof(cups_lang_t), 1)) == NULL)
379 {
380 fclose(fp);
381 return (NULL);
382 }
383
384 lang->next = lang_cache;
385 lang_cache = lang;
386 }
387
388 /*
389 * Free all old strings as needed...
390 */
391
392 for (i = 0; i < CUPS_MSG_MAX; i ++)
393 {
394 if (lang->messages[i] != NULL && lang->messages[i] != lang_blank)
395 free(lang->messages[i]);
396
397 lang->messages[i] = (char *)lang_blank;
398 }
399
400 /*
401 * Then assign the language and encoding fields...
402 */
403
404 lang->used ++;
405 strlcpy(lang->language, langname, sizeof(lang->language));
406
407 for (i = 0; i < (sizeof(lang_encodings) / sizeof(lang_encodings[0])); i ++)
408 if (strcmp(lang_encodings[i], line) == 0)
409 {
410 lang->encoding = (cups_encoding_t)i;
411 break;
412 }
413
414 /*
415 * Read the strings from the file...
416 */
417
418 msg = (cups_msg_t)-1;
419 count = 1;
420
421 for (;;)
422 {
423 /*
424 * Read a line from memory or from a file...
425 */
426
427 if (fp == NULL)
428 {
429 if (lang_default[count] == NULL)
430 break;
431
432 strlcpy(line, lang_default[count], sizeof(line));
433 }
434 else if (fgets(line, sizeof(line), fp) == NULL)
435 break;
436
437 count ++;
438
439 /*
440 * Ignore blank lines...
441 */
442
443 i = strlen(line) - 1;
444 if (line[i] == '\n')
445 line[i] = '\0'; /* Strip LF */
446
447 if (line[0] == '\0')
448 continue;
449
450 /*
451 * Grab the message number and text...
452 */
453
454 if (isdigit(line[0]))
455 msg = (cups_msg_t)atoi(line);
456 else
457 msg ++;
458
459 if (msg < 0 || msg >= CUPS_MSG_MAX)
460 continue;
461
462 text = line;
463 while (isdigit(*text))
464 text ++;
465 while (isspace(*text))
466 text ++;
467
468 lang->messages[msg] = strdup(text);
469 }
470
471 /*
472 * Close the file and return...
473 */
474
475 if (fp != NULL)
476 fclose(fp);
477
478 return (lang);
479 }
480
481
482 /*
483 * End of "$Id: language.c,v 1.20.2.12 2003/01/24 20:45:13 mike Exp $".
484 */