]> git.ipfire.org Git - thirdparty/bash.git/blame - locale.c
Imported from ../bash-2.05b.tar.gz.
[thirdparty/bash.git] / locale.c
CommitLineData
ccc6cda3
JA
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
bb70624e 19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
ccc6cda3
JA
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>
f73dda09 32#include "chartypes.h"
ccc6cda3
JA
33
34#include "shell.h"
7117c2d2
JA
35#include "input.h" /* For bash_input */
36
37extern int dump_translatable_strings, dump_po_strings;
ccc6cda3
JA
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/* Set the value of default_locale and make the current locale the
51 system default locale. This should be called very early in main(). */
52void
53set_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. */
65void
66set_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
bb70624e
JA
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
ccc6cda3
JA
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. */
114int
115set_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);
e8ce775d
JA
138 if (value)
139 lc_all = savestring (value);
140 else if (default_locale)
141 lc_all = savestring (default_locale);
142 else
143 {
f73dda09 144 lc_all = (char *)xmalloc (1);
e8ce775d
JA
145 lc_all[0] = '\0';
146 }
ccc6cda3 147#if defined (HAVE_SETLOCALE)
bb70624e 148 return (setlocale (LC_ALL, lc_all) != 0);
ccc6cda3
JA
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')
bb70624e 158 return (setlocale (LC_CTYPE, value ? value : "") != 0);
ccc6cda3
JA
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')
bb70624e 164 return (setlocale (LC_COLLATE, value ? value : "") != 0);
ccc6cda3
JA
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')
bb70624e 171 return (setlocale (LC_MESSAGES, value ? value : "") != 0);
ccc6cda3
JA
172# endif /* LC_MESSAGES */
173 }
f73dda09 174 else if (var[3] == 'N' && var[4] == 'U') /* LC_NUMERIC */
bb70624e
JA
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 }
ccc6cda3
JA
181#endif /* HAVE_SETLOCALE */
182
183 return (0);
184}
185
7117c2d2
JA
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. */
ccc6cda3
JA
189int
190set_lang (var, value)
191 char *var, *value;
192{
7117c2d2 193 return ((lc_all == 0 || *lc_all == 0) ? setlocale (LC_ALL, value?value:"") != NULL : 0);
ccc6cda3
JA
194}
195
196/* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE) */
197char *
198get_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. */
217char *
218localetrans (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)
28ef6c31 232 *lenp = 0;
ccc6cda3
JA
233 return ((char *)NULL);
234 }
235
ccc6cda3
JA
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 {
f73dda09 246 t = (char *)xmalloc (len + 1);
ccc6cda3
JA
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 {
f73dda09 258 t = (char *)xmalloc (len + 1);
ccc6cda3
JA
259 strcpy (t, string);
260 if (lenp)
261 *lenp = len;
262 }
263 else
264 {
ccc6cda3 265 tlen = strlen (translated);
f73dda09 266 t = (char *)xmalloc (tlen + 1);
ccc6cda3
JA
267 strcpy (t, translated);
268 if (lenp)
269 *lenp = tlen;
270 }
271 return (t);
272#endif /* HAVE_GETTEXT */
273}
7117c2d2
JA
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". */
277char *
278mk_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. */
328char *
329localeexpand (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}