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    59 Temple Place, Suite 330, Boston, MA 02111 USA. */
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 #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 /* Check for LC_ALL, LC_CTYPE, and LANG and use the first with a value
79    to decide the defaults for 8-bit character input and output.  Returns
80    1 if we set eight-bit mode. */
81 int
_rl_init_eightbit()82 _rl_init_eightbit ()
83 {
84 /* If we have setlocale(3), just check the current LC_CTYPE category
85    value, and go into eight-bit mode if it's not C or POSIX. */
86 #if defined (HAVE_SETLOCALE)
87   char *t;
88 
89   /* Set the LC_CTYPE locale category from environment variables. */
90   t = setlocale (LC_CTYPE, "");
91   if (t && *t && (t[0] != 'C' || t[1]) && (STREQ (t, "POSIX") == 0))
92     {
93       _rl_meta_flag = 1;
94       _rl_convert_meta_chars_to_ascii = 0;
95       _rl_output_meta_chars = 1;
96       return (1);
97     }
98   else
99     return (0);
100 
101 #else /* !HAVE_SETLOCALE */
102   char *lspec, *t;
103   int i;
104 
105   /* We don't have setlocale.  Finesse it.  Check the environment for the
106      appropriate variables and set eight-bit mode if they have the right
107      values. */
108   lspec = sh_get_env_value ("LC_ALL");
109   if (lspec == 0) lspec = sh_get_env_value ("LC_CTYPE");
110   if (lspec == 0) lspec = sh_get_env_value ("LANG");
111   if (lspec == 0 || (t = normalize_codeset (lspec)) == 0)
112     return (0);
113   for (i = 0; t && legal_lang_values[i]; i++)
114     if (STREQ (t, legal_lang_values[i]))
115       {
116 	_rl_meta_flag = 1;
117 	_rl_convert_meta_chars_to_ascii = 0;
118 	_rl_output_meta_chars = 1;
119 	break;
120       }
121   free (t);
122   return (legal_lang_values[i] ? 1 : 0);
123 
124 #endif /* !HAVE_SETLOCALE */
125 }
126 
127 #if !defined (HAVE_SETLOCALE)
128 static char *
normalize_codeset(codeset)129 normalize_codeset (codeset)
130      char *codeset;
131 {
132   size_t namelen, i;
133   int len, all_digits;
134   char *wp, *retval;
135 
136   codeset = find_codeset (codeset, &namelen);
137 
138   if (codeset == 0)
139     return (codeset);
140 
141   all_digits = 1;
142   for (len = 0, i = 0; i < namelen; i++)
143     {
144       if (ISALNUM ((unsigned char)codeset[i]))
145 	{
146 	  len++;
147 	  all_digits &= _rl_digit_p (codeset[i]);
148 	}
149     }
150 
151   retval = (char *)malloc ((all_digits ? 3 : 0) + len + 1);
152   if (retval == 0)
153     return ((char *)0);
154 
155   wp = retval;
156   /* Add `iso' to beginning of an all-digit codeset */
157   if (all_digits)
158     {
159       *wp++ = 'i';
160       *wp++ = 's';
161       *wp++ = 'o';
162     }
163 
164   for (i = 0; i < namelen; i++)
165     if (ISALPHA ((unsigned char)codeset[i]))
166       *wp++ = _rl_to_lower (codeset[i]);
167     else if (_rl_digit_p (codeset[i]))
168       *wp++ = codeset[i];
169   *wp = '\0';
170 
171   return retval;
172 }
173 
174 /* Isolate codeset portion of locale specification. */
175 static char *
find_codeset(name,lenp)176 find_codeset (name, lenp)
177      char *name;
178      size_t *lenp;
179 {
180   char *cp, *language, *result;
181 
182   cp = language = name;
183   result = (char *)0;
184 
185   while (*cp && *cp != '_' && *cp != '@' && *cp != '+' && *cp != ',')
186     cp++;
187 
188   /* This does not make sense: language has to be specified.  As
189      an exception we allow the variable to contain only the codeset
190      name.  Perhaps there are funny codeset names.  */
191   if (language == cp)
192     {
193       *lenp = strlen (language);
194       result = language;
195     }
196   else
197     {
198       /* Next is the territory. */
199       if (*cp == '_')
200 	do
201 	  ++cp;
202 	while (*cp && *cp != '.' && *cp != '@' && *cp != '+' && *cp != ',' && *cp != '_');
203 
204       /* Now, finally, is the codeset. */
205       result = cp;
206       if (*cp == '.')
207 	do
208 	  ++cp;
209 	while (*cp && *cp != '@');
210 
211       if (cp - result > 2)
212 	{
213 	  result++;
214 	  *lenp = cp - result;
215 	}
216       else
217 	{
218 	  *lenp = strlen (language);
219 	  result = language;
220 	}
221     }
222 
223   return result;
224 }
225 #endif /* !HAVE_SETLOCALE */
226