Imported from ../bash-3.2.48.tar.gz.
[platform/upstream/bash.git] / locale.c
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
37 extern int dump_translatable_strings, dump_po_strings;
38
39 /* The current locale when the program begins */
40 static char *default_locale;
41
42 /* The current domain for textdomain(3). */
43 static char *default_domain;
44 static char *default_dir;
45
46 /* tracks the value of LC_ALL; used to override values for other locale
47    categories */
48 static char *lc_all;
49
50 /* tracks the value of LC_ALL; used to provide defaults for locale
51    categories */
52 static 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. */
56 static int reset_locale_vars __P((void));
57
58 static 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(). */
62 void
63 set_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. */
77 void
78 set_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. */
142 int
143 set_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. */
237 int
238 set_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. */
255 void
256 set_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. */
270 char *
271 get_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. */
291 static int
292 reset_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. */
326 char *
327 localetrans (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". */
384 char *
385 mk_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. */
435 char *
436 localeexpand (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. */
492 static void
493 locale_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 }