Automatic date update in version.in
[external/binutils.git] / readline / nls.c
1 /* nls.c -- skeletal internationalization code. */
2
3 /* Copyright (C) 1996-2017 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  "utf8",
78   0
79 };
80
81 static char *normalize_codeset PARAMS((char *));
82 #endif /* !HAVE_SETLOCALE */
83
84 static char *find_codeset PARAMS((char *, size_t *));
85
86 static char *_rl_get_locale_var PARAMS((const char *));
87
88 static char *
89 _rl_get_locale_var (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 (char *lspec)
104 {
105   char *cp;
106   size_t len;
107
108 #if HAVE_LANGINFO_CODESET
109   cp = nl_langinfo (CODESET);
110   return (STREQ (cp, "UTF-8") || STREQ (cp, "utf8"));
111 #else
112   cp = find_codeset (lspec, &len);
113
114   if (cp == 0 || len < 4 || len > 5)
115     return 0;
116   return ((len == 5) ? strncmp (cp, "UTF-8", len) == 0 : strncmp (cp, "utf8", 4) == 0);
117 #endif
118 }
119
120 /* Query the right environment variables and call setlocale() to initialize
121    the C library locale settings. */
122 char *
123 _rl_init_locale (void)
124 {
125   char *ret, *lspec;
126
127   /* Set the LC_CTYPE locale category from environment variables. */
128   lspec = _rl_get_locale_var ("LC_CTYPE");
129   /* Since _rl_get_locale_var queries the right environment variables,
130      we query the current locale settings with setlocale(), and, if
131      that doesn't return anything, we set lspec to the empty string to
132      force the subsequent call to setlocale() to define the `native'
133      environment. */
134   if (lspec == 0 || *lspec == 0)
135     lspec = setlocale (LC_CTYPE, (char *)NULL);
136   if (lspec == 0)
137     lspec = "";
138   ret = setlocale (LC_CTYPE, lspec);    /* ok, since it does not change locale */
139
140   _rl_utf8locale = (ret && *ret) ? utf8locale (ret) : 0;
141
142   return ret;
143 }
144
145 /* Check for LC_ALL, LC_CTYPE, and LANG and use the first with a value
146    to decide the defaults for 8-bit character input and output.  Returns
147    1 if we set eight-bit mode. */
148 int
149 _rl_init_eightbit (void)
150 {
151 /* If we have setlocale(3), just check the current LC_CTYPE category
152    value, and go into eight-bit mode if it's not C or POSIX. */
153 #if defined (HAVE_SETLOCALE)
154   char *lspec, *t;
155
156   t = _rl_init_locale ();       /* returns static pointer */
157
158   if (t && *t && (t[0] != 'C' || t[1]) && (STREQ (t, "POSIX") == 0))
159     {
160       _rl_meta_flag = 1;
161       _rl_convert_meta_chars_to_ascii = 0;
162       _rl_output_meta_chars = 1;
163       return (1);
164     }
165   else
166     return (0);
167
168 #else /* !HAVE_SETLOCALE */
169   char *lspec, *t;
170   int i;
171
172   /* We don't have setlocale.  Finesse it.  Check the environment for the
173      appropriate variables and set eight-bit mode if they have the right
174      values. */
175   lspec = _rl_get_locale_var ("LC_CTYPE");
176
177   if (lspec == 0 || (t = normalize_codeset (lspec)) == 0)
178     return (0);
179   for (i = 0; t && legal_lang_values[i]; i++)
180     if (STREQ (t, legal_lang_values[i]))
181       {
182         _rl_meta_flag = 1;
183         _rl_convert_meta_chars_to_ascii = 0;
184         _rl_output_meta_chars = 1;
185         break;
186       }
187
188   _rl_utf8locale = *t ? STREQ (t, "utf8") : 0;
189
190   xfree (t);
191   return (legal_lang_values[i] ? 1 : 0);
192 #endif /* !HAVE_SETLOCALE */
193 }
194
195 #if !defined (HAVE_SETLOCALE)
196 static char *
197 normalize_codeset (char *codeset)
198 {
199   size_t namelen, i;
200   int len, all_digits;
201   char *wp, *retval;
202
203   codeset = find_codeset (codeset, &namelen);
204
205   if (codeset == 0)
206     return (codeset);
207
208   all_digits = 1;
209   for (len = 0, i = 0; i < namelen; i++)
210     {
211       if (ISALNUM ((unsigned char)codeset[i]))
212         {
213           len++;
214           all_digits &= _rl_digit_p (codeset[i]);
215         }
216     }
217
218   retval = (char *)malloc ((all_digits ? 3 : 0) + len + 1);
219   if (retval == 0)
220     return ((char *)0);
221
222   wp = retval;
223   /* Add `iso' to beginning of an all-digit codeset */
224   if (all_digits)
225     {
226       *wp++ = 'i';
227       *wp++ = 's';
228       *wp++ = 'o';
229     }
230
231   for (i = 0; i < namelen; i++)
232     if (ISALPHA ((unsigned char)codeset[i]))
233       *wp++ = _rl_to_lower (codeset[i]);
234     else if (_rl_digit_p (codeset[i]))
235       *wp++ = codeset[i];
236   *wp = '\0';
237
238   return retval;
239 }
240 #endif /* !HAVE_SETLOCALE */
241
242 /* Isolate codeset portion of locale specification. */
243 static char *
244 find_codeset (char *name, size_t *lenp)
245 {
246   char *cp, *language, *result;
247
248   cp = language = name;
249   result = (char *)0;
250
251   while (*cp && *cp != '_' && *cp != '@' && *cp != '+' && *cp != ',')
252     cp++;
253
254   /* This does not make sense: language has to be specified.  As
255      an exception we allow the variable to contain only the codeset
256      name.  Perhaps there are funny codeset names.  */
257   if (language == cp) 
258     {
259       *lenp = strlen (language);
260       result = language;
261     }
262   else
263     {
264       /* Next is the territory. */
265       if (*cp == '_')
266         do
267           ++cp;
268         while (*cp && *cp != '.' && *cp != '@' && *cp != '+' && *cp != ',' && *cp != '_');
269
270       /* Now, finally, is the codeset. */
271       result = cp;
272       if (*cp == '.')
273         do
274           ++cp;
275         while (*cp && *cp != '@');
276
277       if (cp - result > 2)
278         {
279           result++;
280           *lenp = cp - result;
281         }
282       else
283         {
284           *lenp = strlen (language);
285           result = language;
286         }
287     }
288
289   return result;
290 }