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