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