Line data Source code
1 : /* locale.c - Miscellaneous internationalization functions. */
2 :
3 : /* Copyright (C) 1996-2009,2012 Free Software Foundation, Inc.
4 :
5 : This file is part of GNU Bash, the Bourne Again SHell.
6 :
7 : Bash is free software: you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation, either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : Bash is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with Bash. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 :
23 : #include "bashtypes.h"
24 :
25 : #if defined (HAVE_UNISTD_H)
26 : # include <unistd.h>
27 : #endif
28 :
29 : #if HAVE_LANGINFO_CODESET
30 : # include <langinfo.h>
31 : #endif
32 :
33 : #include "bashintl.h"
34 : #include "bashansi.h"
35 : #include <stdio.h>
36 : #include "chartypes.h"
37 : #include <errno.h>
38 :
39 : #include "shell.h"
40 : #include "input.h" /* For bash_input */
41 :
42 : #ifndef errno
43 : extern int errno;
44 : #endif
45 :
46 : int locale_utf8locale; /* unused for now */
47 : int locale_mb_cur_max; /* value of MB_CUR_MAX for current locale (LC_CTYPE) */
48 :
49 : extern int dump_translatable_strings, dump_po_strings;
50 :
51 : /* The current locale when the program begins */
52 : static char *default_locale;
53 :
54 : /* The current domain for textdomain(3). */
55 : static char *default_domain;
56 : static char *default_dir;
57 :
58 : /* tracks the value of LC_ALL; used to override values for other locale
59 : categories */
60 : static char *lc_all;
61 :
62 : /* tracks the value of LC_ALL; used to provide defaults for locale
63 : categories */
64 : static char *lang;
65 :
66 : /* Called to reset all of the locale variables to their appropriate values
67 : if (and only if) LC_ALL has not been assigned a value. */
68 : static int reset_locale_vars __P((void));
69 :
70 : static void locale_setblanks __P((void));
71 : #if 0
72 : static int locale_isutf8 __P((char *));
73 : #endif
74 :
75 : /* Set the value of default_locale and make the current locale the
76 : system default locale. This should be called very early in main(). */
77 : void
78 9542925 : set_default_locale ()
79 : {
80 : #if defined (HAVE_SETLOCALE)
81 9542925 : default_locale = setlocale (LC_ALL, "");
82 9542925 : if (default_locale)
83 9542925 : default_locale = savestring (default_locale);
84 : #endif /* HAVE_SETLOCALE */
85 9542925 : bindtextdomain (PACKAGE, LOCALEDIR);
86 9542925 : textdomain (PACKAGE);
87 :
88 9542925 : locale_mb_cur_max = MB_CUR_MAX;
89 9542925 : }
90 :
91 : /* Set default values for LC_CTYPE, LC_COLLATE, LC_MESSAGES, LC_NUMERIC and
92 : LC_TIME if they are not specified in the environment, but LC_ALL is. This
93 : should be called from main() after parsing the environment. */
94 : void
95 9542925 : set_default_locale_vars ()
96 : {
97 9542925 : char *val;
98 :
99 : #if defined (HAVE_SETLOCALE)
100 :
101 : # if defined (LC_CTYPE)
102 9542925 : val = get_string_value ("LC_CTYPE");
103 9542925 : if (val == 0 && lc_all && *lc_all)
104 : {
105 0 : setlocale (LC_CTYPE, lc_all);
106 0 : locale_setblanks ();
107 0 : locale_mb_cur_max = MB_CUR_MAX;
108 0 : u32reset ();
109 : }
110 : # endif
111 :
112 : # if defined (LC_COLLATE)
113 9542925 : val = get_string_value ("LC_COLLATE");
114 9542925 : if (val == 0 && lc_all && *lc_all)
115 0 : setlocale (LC_COLLATE, lc_all);
116 : # endif /* LC_COLLATE */
117 :
118 : # if defined (LC_MESSAGES)
119 9542925 : val = get_string_value ("LC_MESSAGES");
120 9542925 : if (val == 0 && lc_all && *lc_all)
121 0 : setlocale (LC_MESSAGES, lc_all);
122 : # endif /* LC_MESSAGES */
123 :
124 : # if defined (LC_NUMERIC)
125 9542925 : val = get_string_value ("LC_NUMERIC");
126 9542925 : if (val == 0 && lc_all && *lc_all)
127 0 : setlocale (LC_NUMERIC, lc_all);
128 : # endif /* LC_NUMERIC */
129 :
130 : # if defined (LC_TIME)
131 9542925 : val = get_string_value ("LC_TIME");
132 9542925 : if (val == 0 && lc_all && *lc_all)
133 0 : setlocale (LC_TIME, lc_all);
134 : # endif /* LC_TIME */
135 :
136 : #endif /* HAVE_SETLOCALE */
137 :
138 9542925 : val = get_string_value ("TEXTDOMAIN");
139 9542925 : if (val && *val)
140 : {
141 0 : FREE (default_domain);
142 0 : default_domain = savestring (val);
143 0 : if (default_dir && *default_dir)
144 0 : bindtextdomain (default_domain, default_dir);
145 : }
146 :
147 9542925 : val = get_string_value ("TEXTDOMAINDIR");
148 9542925 : if (val && *val)
149 : {
150 0 : FREE (default_dir);
151 0 : default_dir = savestring (val);
152 0 : if (default_domain && *default_domain)
153 0 : bindtextdomain (default_domain, default_dir);
154 : }
155 9542925 : }
156 :
157 : /* Set one of the locale categories (specified by VAR) to VALUE. Returns 1
158 : if successful, 0 otherwise. */
159 : int
160 9542925 : set_locale_var (var, value)
161 : char *var, *value;
162 : {
163 9542925 : int r;
164 9542925 : char *x;
165 :
166 9542925 : x = "";
167 9542925 : errno = 0;
168 9542925 : if (var[0] == 'T' && var[10] == 0) /* TEXTDOMAIN */
169 : {
170 0 : FREE (default_domain);
171 0 : default_domain = value ? savestring (value) : (char *)NULL;
172 0 : if (default_dir && *default_dir)
173 0 : bindtextdomain (default_domain, default_dir);
174 0 : return (1);
175 : }
176 9542925 : else if (var[0] == 'T') /* TEXTDOMAINDIR */
177 : {
178 0 : FREE (default_dir);
179 0 : default_dir = value ? savestring (value) : (char *)NULL;
180 0 : if (default_domain && *default_domain)
181 0 : bindtextdomain (default_domain, default_dir);
182 0 : return (1);
183 : }
184 :
185 : /* var[0] == 'L' && var[1] == 'C' && var[2] == '_' */
186 :
187 9542925 : else if (var[3] == 'A') /* LC_ALL */
188 : {
189 9542925 : FREE (lc_all);
190 9542925 : if (value)
191 0 : lc_all = savestring (value);
192 : else
193 : {
194 9542925 : lc_all = (char *)xmalloc (1);
195 9542925 : lc_all[0] = '\0';
196 : }
197 : #if defined (HAVE_SETLOCALE)
198 9542925 : r = *lc_all ? ((x = setlocale (LC_ALL, lc_all)) != 0) : reset_locale_vars ();
199 9542925 : if (x == 0)
200 : {
201 0 : if (errno == 0)
202 0 : internal_warning(_("setlocale: LC_ALL: cannot change locale (%s)"), lc_all);
203 : else
204 0 : internal_warning(_("setlocale: LC_ALL: cannot change locale (%s): %s"), lc_all, strerror (errno));
205 : }
206 9542925 : locale_setblanks ();
207 9542925 : locale_mb_cur_max = MB_CUR_MAX;
208 9542925 : u32reset ();
209 9542925 : return r;
210 : #else
211 : return (1);
212 : #endif
213 : }
214 :
215 : #if defined (HAVE_SETLOCALE)
216 0 : else if (var[3] == 'C' && var[4] == 'T') /* LC_CTYPE */
217 : {
218 : # if defined (LC_CTYPE)
219 0 : if (lc_all == 0 || *lc_all == '\0')
220 : {
221 0 : x = setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE"));
222 0 : locale_setblanks ();
223 0 : locale_mb_cur_max = MB_CUR_MAX;
224 0 : u32reset ();
225 : }
226 : # endif
227 : }
228 0 : else if (var[3] == 'C' && var[4] == 'O') /* LC_COLLATE */
229 : {
230 : # if defined (LC_COLLATE)
231 0 : if (lc_all == 0 || *lc_all == '\0')
232 0 : x = setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE"));
233 : # endif /* LC_COLLATE */
234 : }
235 0 : else if (var[3] == 'M' && var[4] == 'E') /* LC_MESSAGES */
236 : {
237 : # if defined (LC_MESSAGES)
238 0 : if (lc_all == 0 || *lc_all == '\0')
239 0 : x = setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES"));
240 : # endif /* LC_MESSAGES */
241 : }
242 0 : else if (var[3] == 'N' && var[4] == 'U') /* LC_NUMERIC */
243 : {
244 : # if defined (LC_NUMERIC)
245 0 : if (lc_all == 0 || *lc_all == '\0')
246 0 : x = setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC"));
247 : # endif /* LC_NUMERIC */
248 : }
249 0 : else if (var[3] == 'T' && var[4] == 'I') /* LC_TIME */
250 : {
251 : # if defined (LC_TIME)
252 0 : if (lc_all == 0 || *lc_all == '\0')
253 0 : x = setlocale (LC_TIME, get_locale_var ("LC_TIME"));
254 : # endif /* LC_TIME */
255 : }
256 : #endif /* HAVE_SETLOCALE */
257 :
258 0 : if (x == 0)
259 : {
260 0 : if (errno == 0)
261 0 : internal_warning(_("setlocale: %s: cannot change locale (%s)"), var, get_locale_var (var));
262 : else
263 0 : internal_warning(_("setlocale: %s: cannot change locale (%s): %s"), var, get_locale_var (var), strerror (errno));
264 : }
265 :
266 0 : return (x != 0);
267 : }
268 :
269 : /* Called when LANG is assigned a value. Tracks value in `lang'. Calls
270 : reset_locale_vars() to reset any default values if LC_ALL is unset or
271 : null. */
272 : int
273 9542925 : set_lang (var, value)
274 : char *var, *value;
275 : {
276 9542925 : FREE (lang);
277 9542925 : if (value)
278 9542925 : lang = savestring (value);
279 : else
280 : {
281 0 : lang = (char *)xmalloc (1);
282 0 : lang[0] = '\0';
283 : }
284 :
285 9542925 : return ((lc_all == 0 || *lc_all == 0) ? reset_locale_vars () : 0);
286 : }
287 :
288 : /* Set default values for LANG and LC_ALL. Default values for all other
289 : locale-related variables depend on these. */
290 : void
291 9542925 : set_default_lang ()
292 : {
293 9542925 : char *v;
294 :
295 9542925 : v = get_string_value ("LC_ALL");
296 9542925 : set_locale_var ("LC_ALL", v);
297 :
298 9542925 : v = get_string_value ("LANG");
299 9542925 : set_lang ("LANG", v);
300 9542925 : }
301 :
302 : /* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE).
303 : The precedence is as POSIX.2 specifies: LC_ALL has precedence over
304 : the specific locale variables, and LANG, if set, is used as the default. */
305 : char *
306 95429454 : get_locale_var (var)
307 : char *var;
308 : {
309 95429454 : char *locale;
310 :
311 95429454 : locale = lc_all;
312 :
313 95429454 : if (locale == 0 || *locale == 0)
314 95429454 : locale = get_string_value (var); /* XXX - no mem leak */
315 95429454 : if (locale == 0 || *locale == 0)
316 95429454 : locale = lang;
317 95429454 : if (locale == 0 || *locale == 0)
318 : #if 0
319 : locale = default_locale; /* system-dependent; not really portable. should it be "C"? */
320 : #else
321 47714625 : locale = "";
322 : #endif
323 95429454 : return (locale);
324 : }
325 :
326 : /* Called to reset all of the locale variables to their appropriate values
327 : if (and only if) LC_ALL has not been assigned a value. DO NOT CALL THIS
328 : IF LC_ALL HAS BEEN ASSIGNED A VALUE. */
329 : static int
330 19085850 : reset_locale_vars ()
331 : {
332 : #if defined (HAVE_SETLOCALE)
333 19085850 : if (lang == 0 || *lang == '\0')
334 9542925 : maybe_make_export_env (); /* trust that this will change environment for setlocale */
335 28628775 : if (setlocale (LC_ALL, lang ? lang : "") == 0)
336 : return 0;
337 :
338 : # if defined (LC_CTYPE)
339 19085850 : setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE"));
340 : # endif
341 : # if defined (LC_COLLATE)
342 19085850 : setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE"));
343 : # endif
344 : # if defined (LC_MESSAGES)
345 19085850 : setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES"));
346 : # endif
347 : # if defined (LC_NUMERIC)
348 19085850 : setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC"));
349 : # endif
350 : # if defined (LC_TIME)
351 19085850 : setlocale (LC_TIME, get_locale_var ("LC_TIME"));
352 : # endif
353 :
354 19085850 : locale_setblanks ();
355 19085850 : locale_mb_cur_max = MB_CUR_MAX;
356 19085850 : u32reset ();
357 :
358 : #endif
359 19085850 : return 1;
360 : }
361 :
362 : /* Translate the contents of STRING, a $"..." quoted string, according
363 : to the current locale. In the `C' or `POSIX' locale, or if gettext()
364 : is not available, the passed string is returned unchanged. The
365 : length of the translated string is returned in LENP, if non-null. */
366 : char *
367 204 : localetrans (string, len, lenp)
368 : char *string;
369 : int len, *lenp;
370 : {
371 204 : char *locale, *t;
372 204 : char *translated;
373 204 : int tlen;
374 :
375 : /* Don't try to translate null strings. */
376 204 : if (string == 0 || *string == 0)
377 : {
378 0 : if (lenp)
379 0 : *lenp = 0;
380 0 : return ((char *)NULL);
381 : }
382 :
383 204 : locale = get_locale_var ("LC_MESSAGES");
384 :
385 : /* If we don't have setlocale() or the current locale is `C' or `POSIX',
386 : just return the string. If we don't have gettext(), there's no use
387 : doing anything else. */
388 204 : if (locale == 0 || locale[0] == '\0' ||
389 204 : (locale[0] == 'C' && locale[1] == '\0') || STREQ (locale, "POSIX"))
390 : {
391 0 : t = (char *)xmalloc (len + 1);
392 0 : strcpy (t, string);
393 0 : if (lenp)
394 0 : *lenp = len;
395 0 : return (t);
396 : }
397 :
398 : /* Now try to translate it. */
399 204 : if (default_domain && *default_domain)
400 0 : translated = dgettext (default_domain, string);
401 : else
402 : translated = string;
403 :
404 204 : if (translated == string) /* gettext returns its argument if untranslatable */
405 : {
406 204 : t = (char *)xmalloc (len + 1);
407 204 : strcpy (t, string);
408 204 : if (lenp)
409 204 : *lenp = len;
410 : }
411 : else
412 : {
413 0 : tlen = strlen (translated);
414 0 : t = (char *)xmalloc (tlen + 1);
415 0 : strcpy (t, translated);
416 0 : if (lenp)
417 0 : *lenp = tlen;
418 : }
419 : return (t);
420 : }
421 :
422 : /* Change a bash string into a string suitable for inclusion in a `po' file.
423 : This backslash-escapes `"' and `\' and changes newlines into \\\n"\n". */
424 : char *
425 0 : mk_msgstr (string, foundnlp)
426 : char *string;
427 : int *foundnlp;
428 : {
429 0 : register int c, len;
430 0 : char *result, *r, *s;
431 :
432 0 : for (len = 0, s = string; s && *s; s++)
433 : {
434 0 : len++;
435 0 : if (*s == '"' || *s == '\\')
436 0 : len++;
437 0 : else if (*s == '\n')
438 0 : len += 5;
439 : }
440 :
441 0 : r = result = (char *)xmalloc (len + 3);
442 0 : *r++ = '"';
443 :
444 0 : for (s = string; s && (c = *s); s++)
445 : {
446 0 : if (c == '\n') /* <NL> -> \n"<NL>" */
447 : {
448 0 : *r++ = '\\';
449 0 : *r++ = 'n';
450 0 : *r++ = '"';
451 0 : *r++ = '\n';
452 0 : *r++ = '"';
453 0 : if (foundnlp)
454 0 : *foundnlp = 1;
455 0 : continue;
456 : }
457 0 : if (c == '"' || c == '\\')
458 0 : *r++ = '\\';
459 0 : *r++ = c;
460 : }
461 :
462 0 : *r++ = '"';
463 0 : *r++ = '\0';
464 :
465 0 : return result;
466 : }
467 :
468 : /* $"..." -- Translate the portion of STRING between START and END
469 : according to current locale using gettext (if available) and return
470 : the result. The caller will take care of leaving the quotes intact.
471 : The string will be left without the leading `$' by the caller.
472 : If translation is performed, the translated string will be double-quoted
473 : by the caller. The length of the translated string is returned in LENP,
474 : if non-null. */
475 : char *
476 213 : localeexpand (string, start, end, lineno, lenp)
477 : char *string;
478 : int start, end, lineno, *lenp;
479 : {
480 213 : int len, tlen, foundnl;
481 213 : char *temp, *t, *t2;
482 :
483 213 : temp = (char *)xmalloc (end - start + 1);
484 7489 : for (tlen = 0, len = start; len < end; )
485 7276 : temp[tlen++] = string[len++];
486 213 : temp[tlen] = '\0';
487 :
488 : /* If we're just dumping translatable strings, don't do anything with the
489 : string itself, but if we're dumping in `po' file format, convert it into
490 : a form more palatable to gettext(3) and friends by quoting `"' and `\'
491 : with backslashes and converting <NL> into `\n"<NL>"'. If we find a
492 : newline in TEMP, we first output a `msgid ""' line and then the
493 : translated string; otherwise we output the `msgid' and translated
494 : string all on one line. */
495 213 : if (dump_translatable_strings)
496 : {
497 0 : if (dump_po_strings)
498 : {
499 0 : foundnl = 0;
500 0 : t = mk_msgstr (temp, &foundnl);
501 0 : t2 = foundnl ? "\"\"\n" : "";
502 :
503 0 : printf ("#: %s:%d\nmsgid %s%s\nmsgstr \"\"\n",
504 : yy_input_name (), lineno, t2, t);
505 0 : free (t);
506 : }
507 : else
508 0 : printf ("\"%s\"\n", temp);
509 :
510 0 : if (lenp)
511 0 : *lenp = tlen;
512 0 : return (temp);
513 : }
514 213 : else if (*temp)
515 : {
516 204 : t = localetrans (temp, tlen, &len);
517 204 : free (temp);
518 204 : if (lenp)
519 204 : *lenp = len;
520 204 : return (t);
521 : }
522 : else
523 : {
524 9 : if (lenp)
525 9 : *lenp = 0;
526 9 : return (temp);
527 : }
528 : }
529 :
530 : /* Set every character in the <blank> character class to be a shell break
531 : character for the lexical analyzer when the locale changes. */
532 : static void
533 28628775 : locale_setblanks ()
534 : {
535 28628775 : int x;
536 :
537 7357595175 : for (x = 0; x < sh_syntabsiz; x++)
538 : {
539 7328966400 : if (isblank ((unsigned char)x))
540 57257550 : sh_syntaxtab[x] |= CSHBRK|CBLANK;
541 7271708850 : else if (member (x, shell_break_chars))
542 : {
543 229030200 : sh_syntaxtab[x] |= CSHBRK;
544 229030200 : sh_syntaxtab[x] &= ~CBLANK;
545 : }
546 : else
547 7042678650 : sh_syntaxtab[x] &= ~(CSHBRK|CBLANK);
548 : }
549 28628775 : }
550 :
551 : #if 0
552 : static int
553 : locale_isutf8 (lspec)
554 : char *lspec;
555 : {
556 : char *cp;
557 :
558 : #if HAVE_LANGINFO_CODESET
559 : cp = nl_langinfo (CODESET);
560 : return (STREQ (cp, "UTF-8") || STREQ (cp, "utf8"));
561 : #else
562 : /* Take a shot */
563 : return (strstr (lspec, "UTF-8") || strstr (lspec, "utf8"));
564 : #endif
565 : }
566 : #endif
|