Imported from ../bash-2.05b.tar.gz.
[platform/upstream/bash.git] / locale.c
1 /* locale.c - Miscellaneous internationalization functions. */
2
3 /* Copyright (C) 1996 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 /* Set the value of default_locale and make the current locale the
51    system default locale.  This should be called very early in main(). */
52 void
53 set_default_locale ()
54 {
55 #if defined (HAVE_SETLOCALE)
56   default_locale = setlocale (LC_ALL, "");
57   if (default_locale)
58     default_locale = savestring (default_locale);
59 #endif /* HAVE_SETLOCALE */
60 }
61
62 /* Set default values for LC_CTYPE, LC_COLLATE, and LC_MESSAGES if they
63    are not specified in the environment, but LANG or LC_ALL is.  This
64    should be called from main() after parsing the environment. */
65 void
66 set_default_locale_vars ()
67 {
68   char *val;
69
70 #if defined (HAVE_SETLOCALE)
71   val = get_string_value ("LC_CTYPE");
72   if (val == 0 && lc_all && *lc_all)
73     setlocale (LC_CTYPE, lc_all);
74
75 #  if defined (LC_COLLATE)
76   val = get_string_value ("LC_COLLATE");
77   if (val == 0 && lc_all && *lc_all)
78     setlocale (LC_COLLATE, lc_all);
79 #  endif /* LC_COLLATE */
80
81 #  if defined (LC_MESSAGES)
82   val = get_string_value ("LC_MESSAGES");
83   if (val == 0 && lc_all && *lc_all)
84     setlocale (LC_MESSAGES, lc_all);
85 #  endif /* LC_MESSAGES */
86
87 #  if defined (LC_NUMERIC)
88   val = get_string_value ("LC_NUMERIC");
89   if (val == 0 && lc_all && *lc_all)
90     setlocale (LC_NUMERIC, lc_all);
91 #  endif /* LC_NUMERIC */
92
93 #endif /* HAVE_SETLOCALE */
94
95   val = get_string_value ("TEXTDOMAIN");
96   if (val && *val)
97     {
98       FREE (default_domain);
99       default_domain = savestring (val);
100       textdomain (default_domain);
101     }
102
103   val = get_string_value ("TEXTDOMAINDIR");
104   if (val && *val)
105     {
106       FREE (default_dir);
107       default_dir = savestring (val);
108       bindtextdomain (default_domain, default_dir);
109     }
110 }
111
112 /* Set one of the locale categories (specified by VAR) to VALUE.  Returns 1
113   if successful, 0 otherwise. */
114 int
115 set_locale_var (var, value)
116      char *var, *value;
117 {
118   if (var[0] == 'T' && var[10] == 0)            /* TEXTDOMAIN */
119     {
120       FREE (default_domain);
121       default_domain = value ? savestring (value) : (char *)NULL;
122       textdomain (default_domain);
123       return (1);
124     }
125   else if (var[0] == 'T')                       /* TEXTDOMAINDIR */
126     {
127       FREE (default_dir);
128       default_dir = value ? savestring (value) : (char *)NULL;
129       bindtextdomain (default_domain, default_dir);
130       return (1);
131     }
132
133   /* var[0] == 'L' && var[1] == 'C' && var[2] == '_' */
134
135   else if (var[3] == 'A')                       /* LC_ALL */
136     {
137       FREE (lc_all);
138       if (value)
139         lc_all = savestring (value);
140       else if (default_locale)
141         lc_all = savestring (default_locale);
142       else
143         {
144           lc_all = (char *)xmalloc (1);
145           lc_all[0] = '\0';
146         }
147 #if defined (HAVE_SETLOCALE)
148       return (setlocale (LC_ALL, lc_all) != 0);
149 #else
150       return (1);
151 #endif
152     }
153
154 #if defined (HAVE_SETLOCALE)
155   else if (var[3] == 'C' && var[4] == 'T')      /* LC_CTYPE */
156     {
157       if (lc_all == 0 || *lc_all == '\0')
158         return (setlocale (LC_CTYPE, value ? value : "") != 0);
159     }
160   else if (var[3] == 'C' && var[4] == 'O')      /* LC_COLLATE */
161     {
162 #  if defined (LC_COLLATE)
163       if (lc_all == 0 || *lc_all == '\0')
164         return (setlocale (LC_COLLATE, value ? value : "") != 0);
165 #  endif /* LC_COLLATE */
166     }
167   else if (var[3] == 'M' && var[4] == 'E')      /* LC_MESSAGES */
168     {
169 #  if defined (LC_MESSAGES)
170       if (lc_all == 0 || *lc_all == '\0')
171         return (setlocale (LC_MESSAGES, value ? value : "") != 0);
172 #  endif /* LC_MESSAGES */
173     }
174   else if (var[3] == 'N' && var[4] == 'U')      /* LC_NUMERIC */
175     {
176 #  if defined (LC_NUMERIC)
177       if (lc_all == 0 || *lc_all == '\0')
178         return (setlocale (LC_NUMERIC, value ? value : "") != 0);
179 #  endif /* LC_NUMERIC */
180     }
181 #endif /* HAVE_SETLOCALE */
182
183   return (0);
184 }
185
186 /* Called when LANG is assigned a value.  Sets LC_ALL category with
187    setlocale(3) if that has not already been set.  Doesn't change any
188    shell variables. */
189 int
190 set_lang (var, value)
191      char *var, *value;
192 {
193   return ((lc_all == 0 || *lc_all == 0) ? setlocale (LC_ALL, value?value:"") != NULL : 0);
194 }
195
196 /* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE) */
197 char *
198 get_locale_var (var)
199      char *var;
200 {
201   char *locale;
202
203   locale = lc_all;
204
205   if (locale == 0)
206     locale = get_string_value (var);
207   if (locale == 0)
208     locale = default_locale;
209
210   return (locale);
211 }
212
213 /* Translate the contents of STRING, a $"..." quoted string, according
214    to the current locale.  In the `C' or `POSIX' locale, or if gettext()
215    is not available, the passed string is returned unchanged.  The
216    length of the translated string is returned in LENP, if non-null. */
217 char *
218 localetrans (string, len, lenp)
219      char *string;
220      int len, *lenp;
221 {
222   char *locale, *t;
223 #if defined (HAVE_GETTEXT)
224   char *translated;
225   int tlen;
226 #endif
227
228   /* Don't try to translate null strings. */
229   if (string == 0 || *string == 0)
230     {
231       if (lenp)
232         *lenp = 0;
233       return ((char *)NULL);
234     }
235
236   locale = get_locale_var ("LC_MESSAGES");
237
238   /* If we don't have setlocale() or the current locale is `C' or `POSIX',
239      just return the string.  If we don't have gettext(), there's no use
240      doing anything else. */
241 #if defined (HAVE_GETTEXT)
242   if (locale == 0 || locale[0] == '\0' ||
243       (locale[0] == 'C' && locale[1] == '\0') || STREQ (locale, "POSIX"))
244 #endif
245     {
246       t = (char *)xmalloc (len + 1);
247       strcpy (t, string);
248       if (lenp)
249         *lenp = len;
250       return (t);
251     }
252
253 #if defined (HAVE_GETTEXT)
254   /* Now try to translate it. */
255   translated = gettext (string);
256   if (translated == string)     /* gettext returns its argument if untranslatable */
257     {
258       t = (char *)xmalloc (len + 1);
259       strcpy (t, string);
260       if (lenp)
261         *lenp = len;
262     }
263   else
264     {
265       tlen = strlen (translated);
266       t = (char *)xmalloc (tlen + 1);
267       strcpy (t, translated);
268       if (lenp)
269         *lenp = tlen;
270     }
271   return (t);
272 #endif /* HAVE_GETTEXT */
273 }
274
275 /* Change a bash string into a string suitable for inclusion in a `po' file.
276    This backslash-escapes `"' and `\' and changes newlines into \\\n"\n". */
277 char *
278 mk_msgstr (string, foundnlp)
279      char *string;
280      int *foundnlp;
281 {
282   register int c, len;
283   char *result, *r, *s;
284
285   for (len = 0, s = string; s && *s; s++)
286     {
287       len++;
288       if (*s == '"' || *s == '\\')
289         len++;
290       else if (*s == '\n')
291         len += 5;
292     }
293   
294   r = result = (char *)xmalloc (len + 3);
295   *r++ = '"';
296
297   for (s = string; s && (c = *s); s++)
298     {
299       if (c == '\n')    /* <NL> -> \n"<NL>" */
300         {
301           *r++ = '\\';
302           *r++ = 'n';
303           *r++ = '"';
304           *r++ = '\n';
305           *r++ = '"';
306           if (foundnlp)
307             *foundnlp = 1;
308           continue;
309         }
310       if (c == '"' || c == '\\')
311         *r++ = '\\';
312       *r++ = c;
313     }
314
315   *r++ = '"';
316   *r++ = '\0';
317
318   return result;
319 }
320
321 /* $"..." -- Translate the portion of STRING between START and END
322    according to current locale using gettext (if available) and return
323    the result.  The caller will take care of leaving the quotes intact.
324    The string will be left without the leading `$' by the caller.
325    If translation is performed, the translated string will be double-quoted
326    by the caller.  The length of the translated string is returned in LENP,
327    if non-null. */
328 char *
329 localeexpand (string, start, end, lineno, lenp)
330      char *string;
331      int start, end, lineno, *lenp;
332 {
333   int len, tlen, foundnl;
334   char *temp, *t, *t2;
335
336   temp = (char *)xmalloc (end - start + 1);
337   for (tlen = 0, len = start; len < end; )
338     temp[tlen++] = string[len++];
339   temp[tlen] = '\0';
340
341   /* If we're just dumping translatable strings, don't do anything with the
342      string itself, but if we're dumping in `po' file format, convert it into a form more palatable to gettext(3)
343      and friends by quoting `"' and `\' with backslashes and converting <NL>
344      into `\n"<NL>"'.  If we find a newline in TEMP, we first output a
345      `msgid ""' line and then the translated string; otherwise we output the
346      `msgid' and translated string all on one line. */
347   if (dump_translatable_strings)
348     {
349       if (dump_po_strings)
350         {
351           foundnl = 0;
352           t = mk_msgstr (temp, &foundnl);
353           t2 = foundnl ? "\"\"\n" : "";
354
355           printf ("#: %s:%d\nmsgid %s%s\nmsgstr \"\"\n",
356                         yy_input_name (), lineno, t2, t);
357           free (t);
358         }
359       else
360         printf ("\"%s\"\n", temp);
361
362       if (lenp)
363         *lenp = tlen;
364       return (temp);
365     }
366   else if (*temp)
367     {
368       t = localetrans (temp, tlen, &len);
369       free (temp);
370       if (lenp)
371         *lenp = len;
372       return (t);
373     }
374   else
375     {
376       if (lenp)
377         *lenp = 0;
378       return (temp);
379     }
380 }