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