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