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 1, 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    675 Mass Ave, Cambridge, MA 02139, 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 #if defined (HAVE_UNISTD_H)
31 #  include <unistd.h>
32 #endif /* HAVE_UNISTD_H */
33
34 #if defined (HAVE_STDLIB_H)
35 #  include <stdlib.h>
36 #else
37 #  include "ansi_stdlib.h"
38 #endif /* HAVE_STDLIB_H */
39
40 #if defined (HAVE_LOCALE_H)
41 #  include <locale.h>
42 #endif
43
44 #include <ctype.h>
45
46 #include "rldefs.h"
47
48 extern int _rl_convert_meta_chars_to_ascii;
49 extern int _rl_output_meta_chars;
50 extern int _rl_meta_flag;
51
52 /* Functions imported from shell.c */
53 extern char *get_env_value ();
54
55 #if !defined (HAVE_SETLOCALE)    
56 /* A list of legal values for the LANG or LC_CTYPE environment variables.
57    If a locale name in this list is the value for the LC_ALL, LC_CTYPE,
58    or LANG environment variable (using the first of those with a value),
59    readline eight-bit mode is enabled. */
60 static char *legal_lang_values[] =
61 {
62  "iso88591",
63  "iso88592",
64  "iso88593",
65  "iso88594",
66  "iso88595",
67  "iso88596",
68  "iso88597",
69  "iso88598",
70  "iso88599",
71  "iso885910",
72  "koi8r",
73  "koi8-r", 
74   0
75 };
76
77 static char *normalize_codeset ();
78 static char *find_codeset ();
79 #endif /* !HAVE_SETLOCALE */
80
81 /* Check for LC_ALL, LC_CTYPE, and LANG and use the first with a value
82    to decide the defaults for 8-bit character input and output.  Returns
83    1 if we set eight-bit mode. */
84 int
85 _rl_init_eightbit ()
86 {
87 /* If we have setlocale(3), just check the current LC_CTYPE category
88    value, and go into eight-bit mode if it's not C or POSIX. */
89 #if defined (HAVE_SETLOCALE)
90   char *t;
91
92   /* Set the LC_CTYPE locale category from environment variables. */
93   t = setlocale (LC_CTYPE, "");
94   if (t && *t && (t[0] != 'C' || t[1]) && (STREQ (t, "POSIX") == 0))
95     {
96       _rl_meta_flag = 1;
97       _rl_convert_meta_chars_to_ascii = 0;
98       _rl_output_meta_chars = 1;
99       return (1);
100     }
101   else
102     return (0);
103
104 #else /* !HAVE_SETLOCALE */
105   char *lspec, *t;
106   int i;
107
108   /* We don't have setlocale.  Finesse it.  Check the environment for the
109      appropriate variables and set eight-bit mode if they have the right
110      values. */
111   lspec = get_env_value ("LC_ALL");
112   if (lspec == 0) lspec = get_env_value ("LC_CTYPE");
113   if (lspec == 0) lspec = get_env_value ("LANG");
114   if (lspec == 0 || (t = normalize_codeset (lspec)) == 0)
115     return (0);
116   for (i = 0; t && legal_lang_values[i]; i++)
117     if (STREQ (t, legal_lang_values[i]))
118       {
119         _rl_meta_flag = 1;
120         _rl_convert_meta_chars_to_ascii = 0;
121         _rl_output_meta_chars = 1;
122         break;
123       }
124   free (t);
125   return (legal_lang_values[i] ? 1 : 0);
126
127 #endif /* !HAVE_SETLOCALE */
128 }
129
130 #if !defined (HAVE_SETLOCALE)
131 static char *
132 normalize_codeset (codeset)
133      char *codeset;
134 {
135   size_t namelen, i;
136   int len, all_digits;
137   char *wp, *retval;
138
139   codeset = find_codeset (codeset, &namelen);
140
141   if (codeset == 0)
142     return (codeset);
143
144   all_digits = 1;
145   for (len = 0, i = 0; i < namelen; i++)
146     {
147       if (isalnum (codeset[i]))
148         {
149           len++;
150           all_digits &= isdigit (codeset[i]);
151         }
152     }
153
154   retval = (char *)malloc ((all_digits ? 3 : 0) + len + 1);
155   if (retval == 0)
156     return ((char *)0);
157
158   wp = retval;
159   /* Add `iso' to beginning of an all-digit codeset */
160   if (all_digits)
161     {
162       *wp++ = 'i';
163       *wp++ = 's';
164       *wp++ = 'o';
165     }
166
167   for (i = 0; i < namelen; i++)
168     if (isalpha (codeset[i]))
169       *wp++ = (isupper (codeset[i])) ? tolower (codeset[i]) : codeset[i];
170     else if (isdigit (codeset[i]))
171       *wp++ = codeset[i];
172   *wp = '\0';
173
174   return retval;
175 }
176
177 /* Isolate codeset portion of locale specification. */
178 static char *
179 find_codeset (name, lenp)
180      char *name;
181      size_t *lenp;
182 {
183   char *cp, *language, *result;
184
185   cp = language = name;
186   result = (char *)0;
187
188   while (*cp && *cp != '_' && *cp != '@' && *cp != '+' && *cp != ',')
189     cp++;
190
191   /* This does not make sense: language has to be specified.  As
192      an exception we allow the variable to contain only the codeset
193      name.  Perhaps there are funny codeset names.  */
194   if (language == cp) 
195     {
196       *lenp = strlen (language);
197       result = language;
198     }
199   else
200     {
201       /* Next is the territory. */
202       if (*cp == '_')
203         do
204           ++cp;
205         while (*cp && *cp != '.' && *cp != '@' && *cp != '+' && *cp != ',' && *cp != '_');
206
207       /* Now, finally, is the codeset. */
208       result = cp;
209       if (*cp == '.')
210         do
211           ++cp;
212         while (*cp && *cp != '@');
213
214       if (cp - result > 2)
215         {
216           result++;
217           *lenp = cp - result;
218         }
219       else
220         {
221           *lenp = strlen (language);
222           result = language;
223         }
224     }
225
226   return result;
227 }
228 #endif /* !HAVE_SETLOCALE */