source: trunk/third/bash/locale.c @ 21276

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