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