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. */
58static 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
74static char *normalize_codeset PARAMS((char *));
75static char *find_codeset PARAMS((char *, size_t *));
76#endif /* !HAVE_SETLOCALE */
77
78static char *_rl_get_locale_var PARAMS((const char *));
79
80static 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. */
98int
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)
155static char *
156normalize_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. */
202static char *
203find_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 */
253