1/* locale.c - Miscellaneous internationalization functions. */ 2 3/* Copyright (C) 1996-2009 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#include "bashintl.h" 30#include "bashansi.h" 31#include <stdio.h> 32#include "chartypes.h" 33#include <errno.h> 34 35#include "shell.h" 36#include "input.h" /* For bash_input */ 37 38#ifndef errno 39extern int errno; 40#endif 41 42extern int dump_translatable_strings, dump_po_strings; 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 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 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 */ 75 bindtextdomain (PACKAGE, LOCALEDIR); 76 textdomain (PACKAGE); 77} 78 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 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) 88 89# if defined (LC_CTYPE) 90 val = get_string_value ("LC_CTYPE"); 91 if (val == 0 && lc_all && *lc_all) 92 { 93 setlocale (LC_CTYPE, lc_all); 94 locale_setblanks (); 95 } 96# endif 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 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 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 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); 129#if 0 130 /* Don't want to override the shell's textdomain as the default */ 131 textdomain (default_domain); 132#endif 133 } 134 135 val = get_string_value ("TEXTDOMAINDIR"); 136 if (val && *val) 137 { 138 FREE (default_dir); 139 default_dir = savestring (val); 140 if (default_domain && *default_domain) 141 bindtextdomain (default_domain, default_dir); 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{ 151 int r; 152 char *x; 153 154 x = ""; 155 errno = 0; 156 if (var[0] == 'T' && var[10] == 0) /* TEXTDOMAIN */ 157 { 158 FREE (default_domain); 159 default_domain = value ? savestring (value) : (char *)NULL; 160#if 0 161 /* Don't want to override the shell's textdomain as the default */ 162 textdomain (default_domain); 163#endif 164 return (1); 165 } 166 else if (var[0] == 'T') /* TEXTDOMAINDIR */ 167 { 168 FREE (default_dir); 169 default_dir = value ? savestring (value) : (char *)NULL; 170 if (default_domain && *default_domain) 171 bindtextdomain (default_domain, default_dir); 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); 180 if (value) 181 lc_all = savestring (value); 182 else 183 { 184 lc_all = (char *)xmalloc (1); 185 lc_all[0] = '\0'; 186 } 187#if defined (HAVE_SETLOCALE) 188 r = *lc_all ? ((x = setlocale (LC_ALL, lc_all)) != 0) : reset_locale_vars (); 189 if (x == 0) 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 } 196 locale_setblanks (); 197 return r; 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 { 206# if defined (LC_CTYPE) 207 if (lc_all == 0 || *lc_all == '\0') 208 { 209 x = setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE")); 210 locale_setblanks (); 211 } 212# endif 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') 218 x = setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE")); 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') 225 x = setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES")); 226# endif /* LC_MESSAGES */ 227 } 228 else if (var[3] == 'N' && var[4] == 'U') /* LC_NUMERIC */ 229 { 230# if defined (LC_NUMERIC) 231 if (lc_all == 0 || *lc_all == '\0') 232 x = setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC")); 233# endif /* LC_NUMERIC */ 234 } 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') 239 x = setlocale (LC_TIME, get_locale_var ("LC_TIME")); 240# endif /* LC_TIME */ 241 } 242#endif /* HAVE_SETLOCALE */ 243 244 if (x == 0) 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 } 251 252 return (x != 0); 253} 254 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. */ 258int 259set_lang (var, value) 260 char *var, *value; 261{ 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); 272} 273 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 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. */ 291char * 292get_locale_var (var) 293 char *var; 294{ 295 char *locale; 296 297 locale = lc_all; 298 299 if (locale == 0 || *locale == 0) 300 locale = get_string_value (var); 301 if (locale == 0 || *locale == 0) 302 locale = lang; 303 if (locale == 0 || *locale == 0) 304#if 0 305 locale = default_locale; /* system-dependent; not really portable. should it be "C"? */ 306#else 307 locale = ""; 308#endif 309 return (locale); 310} 311 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{ 318 char *t; 319#if defined (HAVE_SETLOCALE) 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) 323 return 0; 324 325# if defined (LC_CTYPE) 326 t = setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE")); 327# endif 328# if defined (LC_COLLATE) 329 t = setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE")); 330# endif 331# if defined (LC_MESSAGES) 332 t = setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES")); 333# endif 334# if defined (LC_NUMERIC) 335 t = setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC")); 336# endif 337# if defined (LC_TIME) 338 t = setlocale (LC_TIME, get_locale_var ("LC_TIME")); 339# endif 340 341 locale_setblanks (); 342 343#endif 344 return 1; 345} 346 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; 357 char *translated; 358 int tlen; 359 360 /* Don't try to translate null strings. */ 361 if (string == 0 || *string == 0) 362 { 363 if (lenp) 364 *lenp = 0; 365 return ((char *)NULL); 366 } 367 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. */ 373 if (locale == 0 || locale[0] == '\0' || 374 (locale[0] == 'C' && locale[1] == '\0') || STREQ (locale, "POSIX")) 375 { 376 t = (char *)xmalloc (len + 1); 377 strcpy (t, string); 378 if (lenp) 379 *lenp = len; 380 return (t); 381 } 382 383 /* Now try to translate it. */ 384 if (default_domain && *default_domain) 385 translated = dgettext (default_domain, string); 386 else 387 translated = string; 388 389 if (translated == string) /* gettext returns its argument if untranslatable */ 390 { 391 t = (char *)xmalloc (len + 1); 392 strcpy (t, string); 393 if (lenp) 394 *lenp = len; 395 } 396 else 397 { 398 tlen = strlen (translated); 399 t = (char *)xmalloc (tlen + 1); 400 strcpy (t, translated); 401 if (lenp) 402 *lenp = tlen; 403 } 404 return (t); 405} 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 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. */ 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} 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)) 525 sh_syntaxtab[x] |= CSHBRK|CBLANK; 526 else if (member (x, shell_break_chars)) 527 { 528 sh_syntaxtab[x] |= CSHBRK; 529 sh_syntaxtab[x] &= ~CBLANK; 530 } 531 else 532 sh_syntaxtab[x] &= ~(CSHBRK|CBLANK); 533 } 534} 535