This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / readline / nls.c
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
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 *
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 *
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 */