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