source: vendor/bash/3.1/locale.c

Last change on this file was 3228, checked in by bird, 18 years ago

bash 3.1

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