Merge from vendor branch NTPD:
[dragonfly.git] / contrib / readline-5.0 / 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 static char *_rl_get_locale_var PARAMS((const char *));
79
80 static char *
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
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   char *lspec, *t;
105
106   /* Set the LC_CTYPE locale category from environment variables. */
107   lspec = _rl_get_locale_var ("LC_CTYPE");
108   /* Since _rl_get_locale_var queries the right environment variables,
109      we query the current locale settings with setlocale(), and, if
110      that doesn't return anything, we set lspec to the empty string to
111      force the subsequent call to setlocale() to define the `native'
112      environment. */
113   if (lspec == 0 || *lspec == 0)
114     lspec = setlocale (LC_CTYPE, (char *)NULL);
115   if (lspec == 0)
116     lspec = "";
117   t = setlocale (LC_CTYPE, lspec);
118
119   if (t && *t && (t[0] != 'C' || t[1]) && (STREQ (t, "POSIX") == 0))
120     {
121       _rl_meta_flag = 1;
122       _rl_convert_meta_chars_to_ascii = 0;
123       _rl_output_meta_chars = 1;
124       return (1);
125     }
126   else
127     return (0);
128
129 #else /* !HAVE_SETLOCALE */
130   char *lspec, *t;
131   int i;
132
133   /* We don't have setlocale.  Finesse it.  Check the environment for the
134      appropriate variables and set eight-bit mode if they have the right
135      values. */
136   lspec = _rl_get_locale_var ("LC_CTYPE");
137
138   if (lspec == 0 || (t = normalize_codeset (lspec)) == 0)
139     return (0);
140   for (i = 0; t && legal_lang_values[i]; i++)
141     if (STREQ (t, legal_lang_values[i]))
142       {
143         _rl_meta_flag = 1;
144         _rl_convert_meta_chars_to_ascii = 0;
145         _rl_output_meta_chars = 1;
146         break;
147       }
148   free (t);
149   return (legal_lang_values[i] ? 1 : 0);
150
151 #endif /* !HAVE_SETLOCALE */
152 }
153
154 #if !defined (HAVE_SETLOCALE)
155 static char *
156 normalize_codeset (codeset)
157      char *codeset;
158 {
159   size_t namelen, i;
160   int len, all_digits;
161   char *wp, *retval;
162
163   codeset = find_codeset (codeset, &namelen);
164
165   if (codeset == 0)
166     return (codeset);
167
168   all_digits = 1;
169   for (len = 0, i = 0; i < namelen; i++)
170     {
171       if (ISALNUM ((unsigned char)codeset[i]))
172         {
173           len++;
174           all_digits &= _rl_digit_p (codeset[i]);
175         }
176     }
177
178   retval = (char *)malloc ((all_digits ? 3 : 0) + len + 1);
179   if (retval == 0)
180     return ((char *)0);
181
182   wp = retval;
183   /* Add `iso' to beginning of an all-digit codeset */
184   if (all_digits)
185     {
186       *wp++ = 'i';
187       *wp++ = 's';
188       *wp++ = 'o';
189     }
190
191   for (i = 0; i < namelen; i++)
192     if (ISALPHA ((unsigned char)codeset[i]))
193       *wp++ = _rl_to_lower (codeset[i]);
194     else if (_rl_digit_p (codeset[i]))
195       *wp++ = codeset[i];
196   *wp = '\0';
197
198   return retval;
199 }
200
201 /* Isolate codeset portion of locale specification. */
202 static char *
203 find_codeset (name, lenp)
204      char *name;
205      size_t *lenp;
206 {
207   char *cp, *language, *result;
208
209   cp = language = name;
210   result = (char *)0;
211
212   while (*cp && *cp != '_' && *cp != '@' && *cp != '+' && *cp != ',')
213     cp++;
214
215   /* This does not make sense: language has to be specified.  As
216      an exception we allow the variable to contain only the codeset
217      name.  Perhaps there are funny codeset names.  */
218   if (language == cp) 
219     {
220       *lenp = strlen (language);
221       result = language;
222     }
223   else
224     {
225       /* Next is the territory. */
226       if (*cp == '_')
227         do
228           ++cp;
229         while (*cp && *cp != '.' && *cp != '@' && *cp != '+' && *cp != ',' && *cp != '_');
230
231       /* Now, finally, is the codeset. */
232       result = cp;
233       if (*cp == '.')
234         do
235           ++cp;
236         while (*cp && *cp != '@');
237
238       if (cp - result > 2)
239         {
240           result++;
241           *lenp = cp - result;
242         }
243       else
244         {
245           *lenp = strlen (language);
246           result = language;
247         }
248     }
249
250   return result;
251 }
252 #endif /* !HAVE_SETLOCALE */