Bash-4.3 distribution sources and documentation
[platform/upstream/bash.git] / lib / readline / nls.c
1 /* nls.c -- skeletal internationalization code. */
2
3 /* Copyright (C) 1996-2009 Free Software Foundation, Inc.
4
5    This file is part of the GNU Readline Library (Readline), a library
6    for reading lines of text with interactive input and history editing.      
7
8    Readline is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation, either version 3 of the License, or
11    (at your option) any later version.
12
13    Readline is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with Readline.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #define READLINE_LIBRARY
23
24 #if defined (HAVE_CONFIG_H)
25 #  include <config.h>
26 #endif
27
28 #include <sys/types.h>
29
30 #include <stdio.h>
31
32 #if defined (HAVE_UNISTD_H)
33 #  include <unistd.h>
34 #endif /* HAVE_UNISTD_H */
35
36 #if defined (HAVE_STDLIB_H)
37 #  include <stdlib.h>
38 #else
39 #  include "ansi_stdlib.h"
40 #endif /* HAVE_STDLIB_H */
41
42 #if defined (HAVE_LOCALE_H)
43 #  include <locale.h>
44 #endif
45
46 #if defined (HAVE_LANGINFO_CODESET)
47 #  include <langinfo.h>
48 #endif
49
50 #include <ctype.h>
51
52 #include "rldefs.h"
53 #include "readline.h"
54 #include "rlshell.h"
55 #include "rlprivate.h"
56
57 static int utf8locale PARAMS((char *));
58
59 #if !defined (HAVE_SETLOCALE)    
60 /* A list of legal values for the LANG or LC_CTYPE environment variables.
61    If a locale name in this list is the value for the LC_ALL, LC_CTYPE,
62    or LANG environment variable (using the first of those with a value),
63    readline eight-bit mode is enabled. */
64 static char *legal_lang_values[] =
65 {
66  "iso88591",
67  "iso88592",
68  "iso88593",
69  "iso88594",
70  "iso88595",
71  "iso88596",
72  "iso88597",
73  "iso88598",
74  "iso88599",
75  "iso885910",
76  "koi8r",
77   0
78 };
79
80 static char *normalize_codeset PARAMS((char *));
81 #endif /* !HAVE_SETLOCALE */
82
83 static char *find_codeset PARAMS((char *, size_t *));
84
85 static char *_rl_get_locale_var PARAMS((const char *));
86
87 static char *
88 _rl_get_locale_var (v)
89      const char *v;
90 {
91   char *lspec;
92
93   lspec = sh_get_env_value ("LC_ALL");
94   if (lspec == 0 || *lspec == 0)
95     lspec = sh_get_env_value (v);
96   if (lspec == 0 || *lspec == 0)
97     lspec = sh_get_env_value ("LANG");
98
99   return lspec;
100 }
101
102 static int
103 utf8locale (lspec)
104      char *lspec;
105 {
106   char *cp;
107   size_t len;
108
109 #if HAVE_LANGINFO_CODESET
110   cp = nl_langinfo (CODESET);
111   return (STREQ (cp, "UTF-8") || STREQ (cp, "utf8"));
112 #else
113   cp = find_codeset (lspec, &len);
114
115   if (cp == 0 || len < 4 || len > 5)
116     return 0;
117   return ((len == 5) ? strncmp (cp, "UTF-8", len) == 0 : strncmp (cp, "utf8", 4) == 0);
118 #endif
119 }
120
121 /* Check for LC_ALL, LC_CTYPE, and LANG and use the first with a value
122    to decide the defaults for 8-bit character input and output.  Returns
123    1 if we set eight-bit mode. */
124 int
125 _rl_init_eightbit ()
126 {
127 /* If we have setlocale(3), just check the current LC_CTYPE category
128    value, and go into eight-bit mode if it's not C or POSIX. */
129 #if defined (HAVE_SETLOCALE)
130   char *lspec, *t;
131
132   /* Set the LC_CTYPE locale category from environment variables. */
133   lspec = _rl_get_locale_var ("LC_CTYPE");
134   /* Since _rl_get_locale_var queries the right environment variables,
135      we query the current locale settings with setlocale(), and, if
136      that doesn't return anything, we set lspec to the empty string to
137      force the subsequent call to setlocale() to define the `native'
138      environment. */
139   if (lspec == 0 || *lspec == 0)
140     lspec = setlocale (LC_CTYPE, (char *)NULL);
141   if (lspec == 0)
142     lspec = "";
143   t = setlocale (LC_CTYPE, lspec);
144
145   if (t && *t)
146     _rl_utf8locale = utf8locale (t);
147
148   if (t && *t && (t[0] != 'C' || t[1]) && (STREQ (t, "POSIX") == 0))
149     {
150       _rl_meta_flag = 1;
151       _rl_convert_meta_chars_to_ascii = 0;
152       _rl_output_meta_chars = 1;
153       return (1);
154     }
155   else
156     return (0);
157
158 #else /* !HAVE_SETLOCALE */
159   char *lspec, *t;
160   int i;
161
162   /* We don't have setlocale.  Finesse it.  Check the environment for the
163      appropriate variables and set eight-bit mode if they have the right
164      values. */
165   lspec = _rl_get_locale_var ("LC_CTYPE");
166
167   if (lspec == 0 || (t = normalize_codeset (lspec)) == 0)
168     return (0);
169   for (i = 0; t && legal_lang_values[i]; i++)
170     if (STREQ (t, legal_lang_values[i]))
171       {
172         _rl_meta_flag = 1;
173         _rl_convert_meta_chars_to_ascii = 0;
174         _rl_output_meta_chars = 1;
175         break;
176       }
177   xfree (t);
178   return (legal_lang_values[i] ? 1 : 0);
179
180 #endif /* !HAVE_SETLOCALE */
181 }
182
183 #if !defined (HAVE_SETLOCALE)
184 static char *
185 normalize_codeset (codeset)
186      char *codeset;
187 {
188   size_t namelen, i;
189   int len, all_digits;
190   char *wp, *retval;
191
192   codeset = find_codeset (codeset, &namelen);
193
194   if (codeset == 0)
195     return (codeset);
196
197   all_digits = 1;
198   for (len = 0, i = 0; i < namelen; i++)
199     {
200       if (ISALNUM ((unsigned char)codeset[i]))
201         {
202           len++;
203           all_digits &= _rl_digit_p (codeset[i]);
204         }
205     }
206
207   retval = (char *)malloc ((all_digits ? 3 : 0) + len + 1);
208   if (retval == 0)
209     return ((char *)0);
210
211   wp = retval;
212   /* Add `iso' to beginning of an all-digit codeset */
213   if (all_digits)
214     {
215       *wp++ = 'i';
216       *wp++ = 's';
217       *wp++ = 'o';
218     }
219
220   for (i = 0; i < namelen; i++)
221     if (ISALPHA ((unsigned char)codeset[i]))
222       *wp++ = _rl_to_lower (codeset[i]);
223     else if (_rl_digit_p (codeset[i]))
224       *wp++ = codeset[i];
225   *wp = '\0';
226
227   return retval;
228 }
229 #endif /* !HAVE_SETLOCALE */
230
231 /* Isolate codeset portion of locale specification. */
232 static char *
233 find_codeset (name, lenp)
234      char *name;
235      size_t *lenp;
236 {
237   char *cp, *language, *result;
238
239   cp = language = name;
240   result = (char *)0;
241
242   while (*cp && *cp != '_' && *cp != '@' && *cp != '+' && *cp != ',')
243     cp++;
244
245   /* This does not make sense: language has to be specified.  As
246      an exception we allow the variable to contain only the codeset
247      name.  Perhaps there are funny codeset names.  */
248   if (language == cp) 
249     {
250       *lenp = strlen (language);
251       result = language;
252     }
253   else
254     {
255       /* Next is the territory. */
256       if (*cp == '_')
257         do
258           ++cp;
259         while (*cp && *cp != '.' && *cp != '@' && *cp != '+' && *cp != ',' && *cp != '_');
260
261       /* Now, finally, is the codeset. */
262       result = cp;
263       if (*cp == '.')
264         do
265           ++cp;
266         while (*cp && *cp != '@');
267
268       if (cp - result > 2)
269         {
270           result++;
271           *lenp = cp - result;
272         }
273       else
274         {
275           *lenp = strlen (language);
276           result = language;
277         }
278     }
279
280   return result;
281 }