121308Sache/* nls.c -- skeletal internationalization code. */
221308Sache
321308Sache/* Copyright (C) 1996 Free Software Foundation, Inc.
421308Sache
521308Sache   This file is part of the GNU Readline Library, a library for
621308Sache   reading lines of text with interactive input and history editing.
721308Sache
821308Sache   The GNU Readline Library is free software; you can redistribute it
921308Sache   and/or modify it under the terms of the GNU General Public License
1058310Sache   as published by the Free Software Foundation; either version 2, or
1121308Sache   (at your option) any later version.
1221308Sache
1321308Sache   The GNU Readline Library is distributed in the hope that it will be
1421308Sache   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
1521308Sache   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1621308Sache   GNU General Public License for more details.
1721308Sache
1821308Sache   The GNU General Public License is often shipped with GNU software, and
1921308Sache   is generally kept in a file called COPYING or LICENSE.  If you do not
2021308Sache   have a copy of the license, write to the Free Software Foundation,
2158310Sache   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
2221308Sache#define READLINE_LIBRARY
2321308Sache
2421308Sache#if defined (HAVE_CONFIG_H)
2521308Sache#  include <config.h>
2621308Sache#endif
2721308Sache
2826497Sache#include <sys/types.h>
2926497Sache
3058310Sache#include <stdio.h>
3158310Sache
3221308Sache#if defined (HAVE_UNISTD_H)
3321308Sache#  include <unistd.h>
3421308Sache#endif /* HAVE_UNISTD_H */
3521308Sache
3621308Sache#if defined (HAVE_STDLIB_H)
3721308Sache#  include <stdlib.h>
3821308Sache#else
3921308Sache#  include "ansi_stdlib.h"
4021308Sache#endif /* HAVE_STDLIB_H */
4121308Sache
4221308Sache#if defined (HAVE_LOCALE_H)
4321308Sache#  include <locale.h>
4421308Sache#endif
4521308Sache
4621308Sache#include <ctype.h>
4721308Sache
4821308Sache#include "rldefs.h"
4958310Sache#include "readline.h"
5058310Sache#include "rlshell.h"
5158310Sache#include "rlprivate.h"
5221308Sache
5326497Sache#if !defined (HAVE_SETLOCALE)
5421308Sache/* A list of legal values for the LANG or LC_CTYPE environment variables.
5521308Sache   If a locale name in this list is the value for the LC_ALL, LC_CTYPE,
5621308Sache   or LANG environment variable (using the first of those with a value),
5721308Sache   readline eight-bit mode is enabled. */
5821308Sachestatic char *legal_lang_values[] =
5921308Sache{
6021308Sache "iso88591",
6121308Sache "iso88592",
6221308Sache "iso88593",
6321308Sache "iso88594",
6421308Sache "iso88595",
6521308Sache "iso88596",
6621308Sache "iso88597",
6721308Sache "iso88598",
6821308Sache "iso88599",
6921308Sache "iso885910",
7035486Sache "koi8r",
7121308Sache  0
7221308Sache};
7321308Sache
74119610Sachestatic char *normalize_codeset PARAMS((char *));
75119610Sachestatic char *find_codeset PARAMS((char *, size_t *));
7626497Sache#endif /* !HAVE_SETLOCALE */
7721308Sache
78136644Sachestatic char *_rl_get_locale_var PARAMS((const char *));
79136644Sache
80136644Sachestatic char *
81136644Sache_rl_get_locale_var (v)
82136644Sache     const char *v;
83136644Sache{
84136644Sache  char *lspec;
85136644Sache
86136644Sache  lspec = sh_get_env_value ("LC_ALL");
87136644Sache  if (lspec == 0 || *lspec == 0)
88136644Sache    lspec = sh_get_env_value (v);
89136644Sache  if (lspec == 0 || *lspec == 0)
90136644Sache    lspec = sh_get_env_value ("LANG");
91136644Sache
92136644Sache  return lspec;
93136644Sache}
94136644Sache
9521308Sache/* Check for LC_ALL, LC_CTYPE, and LANG and use the first with a value
9621308Sache   to decide the defaults for 8-bit character input and output.  Returns
9721308Sache   1 if we set eight-bit mode. */
9821308Sacheint
9921308Sache_rl_init_eightbit ()
10021308Sache{
10126497Sache/* If we have setlocale(3), just check the current LC_CTYPE category
10226497Sache   value, and go into eight-bit mode if it's not C or POSIX. */
10326497Sache#if defined (HAVE_SETLOCALE)
104136644Sache  char *lspec, *t;
10526497Sache
10626497Sache  /* Set the LC_CTYPE locale category from environment variables. */
107136644Sache  lspec = _rl_get_locale_var ("LC_CTYPE");
108136644Sache  /* Since _rl_get_locale_var queries the right environment variables,
109136644Sache     we query the current locale settings with setlocale(), and, if
110136644Sache     that doesn't return anything, we set lspec to the empty string to
111136644Sache     force the subsequent call to setlocale() to define the `native'
112136644Sache     environment. */
113136644Sache  if (lspec == 0 || *lspec == 0)
114136644Sache    lspec = setlocale (LC_CTYPE, (char *)NULL);
115136644Sache  if (lspec == 0)
116136644Sache    lspec = "";
117136644Sache  t = setlocale (LC_CTYPE, lspec);
118136644Sache
11926497Sache  if (t && *t && (t[0] != 'C' || t[1]) && (STREQ (t, "POSIX") == 0))
12026497Sache    {
12126497Sache      _rl_meta_flag = 1;
12226497Sache      _rl_convert_meta_chars_to_ascii = 0;
12326497Sache      _rl_output_meta_chars = 1;
12426497Sache      return (1);
12526497Sache    }
12626497Sache  else
12726497Sache    return (0);
12826497Sache
12926497Sache#else /* !HAVE_SETLOCALE */
13021308Sache  char *lspec, *t;
13121308Sache  int i;
13221308Sache
13326497Sache  /* We don't have setlocale.  Finesse it.  Check the environment for the
13426497Sache     appropriate variables and set eight-bit mode if they have the right
13526497Sache     values. */
136136644Sache  lspec = _rl_get_locale_var ("LC_CTYPE");
137136644Sache
13821308Sache  if (lspec == 0 || (t = normalize_codeset (lspec)) == 0)
13921308Sache    return (0);
14021308Sache  for (i = 0; t && legal_lang_values[i]; i++)
14121308Sache    if (STREQ (t, legal_lang_values[i]))
14221308Sache      {
14321308Sache	_rl_meta_flag = 1;
14421308Sache	_rl_convert_meta_chars_to_ascii = 0;
14521308Sache	_rl_output_meta_chars = 1;
14621308Sache	break;
14721308Sache      }
14821308Sache  free (t);
14921308Sache  return (legal_lang_values[i] ? 1 : 0);
15026497Sache
15126497Sache#endif /* !HAVE_SETLOCALE */
15221308Sache}
15321308Sache
15426497Sache#if !defined (HAVE_SETLOCALE)
15521308Sachestatic char *
15621308Sachenormalize_codeset (codeset)
15721308Sache     char *codeset;
15821308Sache{
15921308Sache  size_t namelen, i;
16021308Sache  int len, all_digits;
16121308Sache  char *wp, *retval;
16221308Sache
16321308Sache  codeset = find_codeset (codeset, &namelen);
16421308Sache
16521308Sache  if (codeset == 0)
16621308Sache    return (codeset);
16721308Sache
16821308Sache  all_digits = 1;
16921308Sache  for (len = 0, i = 0; i < namelen; i++)
17021308Sache    {
171119610Sache      if (ISALNUM ((unsigned char)codeset[i]))
17221308Sache	{
17321308Sache	  len++;
174119610Sache	  all_digits &= _rl_digit_p (codeset[i]);
17521308Sache	}
17621308Sache    }
17721308Sache
17821308Sache  retval = (char *)malloc ((all_digits ? 3 : 0) + len + 1);
17921308Sache  if (retval == 0)
18021308Sache    return ((char *)0);
18121308Sache
18221308Sache  wp = retval;
18321308Sache  /* Add `iso' to beginning of an all-digit codeset */
18421308Sache  if (all_digits)
18521308Sache    {
18621308Sache      *wp++ = 'i';
18721308Sache      *wp++ = 's';
18821308Sache      *wp++ = 'o';
18921308Sache    }
19021308Sache
19121308Sache  for (i = 0; i < namelen; i++)
192119610Sache    if (ISALPHA ((unsigned char)codeset[i]))
193119610Sache      *wp++ = _rl_to_lower (codeset[i]);
194119610Sache    else if (_rl_digit_p (codeset[i]))
19521308Sache      *wp++ = codeset[i];
19621308Sache  *wp = '\0';
19721308Sache
19821308Sache  return retval;
19921308Sache}
20021308Sache
20121308Sache/* Isolate codeset portion of locale specification. */
20221308Sachestatic char *
20321308Sachefind_codeset (name, lenp)
20421308Sache     char *name;
20521308Sache     size_t *lenp;
20621308Sache{
20721308Sache  char *cp, *language, *result;
20821308Sache
20921308Sache  cp = language = name;
21021308Sache  result = (char *)0;
21121308Sache
21221308Sache  while (*cp && *cp != '_' && *cp != '@' && *cp != '+' && *cp != ',')
21321308Sache    cp++;
21421308Sache
21521308Sache  /* This does not make sense: language has to be specified.  As
21621308Sache     an exception we allow the variable to contain only the codeset
21721308Sache     name.  Perhaps there are funny codeset names.  */
21821308Sache  if (language == cp)
21921308Sache    {
22021308Sache      *lenp = strlen (language);
22121308Sache      result = language;
22221308Sache    }
22321308Sache  else
22421308Sache    {
22521308Sache      /* Next is the territory. */
22621308Sache      if (*cp == '_')
22721308Sache	do
22821308Sache	  ++cp;
22921308Sache	while (*cp && *cp != '.' && *cp != '@' && *cp != '+' && *cp != ',' && *cp != '_');
23021308Sache
23121308Sache      /* Now, finally, is the codeset. */
23221308Sache      result = cp;
23321308Sache      if (*cp == '.')
23421308Sache	do
23521308Sache	  ++cp;
23621308Sache	while (*cp && *cp != '@');
23721308Sache
23821308Sache      if (cp - result > 2)
23921308Sache	{
24021308Sache	  result++;
24121308Sache	  *lenp = cp - result;
24221308Sache	}
24321308Sache      else
24421308Sache	{
24521308Sache	  *lenp = strlen (language);
24621308Sache	  result = language;
24721308Sache	}
24821308Sache    }
24921308Sache
25021308Sache  return result;
25121308Sache}
25226497Sache#endif /* !HAVE_SETLOCALE */
253