xref: /openbsd-src/gnu/lib/libreadline/nls.c (revision 9704b281e65e1189747652d0ba55eee892cff5f7)
11acd27e7Smillert /* nls.c -- skeletal internationalization code. */
21acd27e7Smillert 
31acd27e7Smillert /* Copyright (C) 1996 Free Software Foundation, Inc.
41acd27e7Smillert 
51acd27e7Smillert    This file is part of the GNU Readline Library, a library for
61acd27e7Smillert    reading lines of text with interactive input and history editing.
71acd27e7Smillert 
81acd27e7Smillert    The GNU Readline Library is free software; you can redistribute it
91acd27e7Smillert    and/or modify it under the terms of the GNU General Public License
101acd27e7Smillert    as published by the Free Software Foundation; either version 2, or
111acd27e7Smillert    (at your option) any later version.
121acd27e7Smillert 
131acd27e7Smillert    The GNU Readline Library is distributed in the hope that it will be
141acd27e7Smillert    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
151acd27e7Smillert    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
161acd27e7Smillert    GNU General Public License for more details.
171acd27e7Smillert 
181acd27e7Smillert    The GNU General Public License is often shipped with GNU software, and
191acd27e7Smillert    is generally kept in a file called COPYING or LICENSE.  If you do not
201acd27e7Smillert    have a copy of the license, write to the Free Software Foundation,
211acd27e7Smillert    59 Temple Place, Suite 330, Boston, MA 02111 USA. */
221acd27e7Smillert #define READLINE_LIBRARY
231acd27e7Smillert 
241acd27e7Smillert #if defined (HAVE_CONFIG_H)
251acd27e7Smillert #  include <config.h>
261acd27e7Smillert #endif
271acd27e7Smillert 
281acd27e7Smillert #include <sys/types.h>
291acd27e7Smillert 
301acd27e7Smillert #include <stdio.h>
311acd27e7Smillert 
321acd27e7Smillert #if defined (HAVE_UNISTD_H)
331acd27e7Smillert #  include <unistd.h>
341acd27e7Smillert #endif /* HAVE_UNISTD_H */
351acd27e7Smillert 
361acd27e7Smillert #if defined (HAVE_STDLIB_H)
371acd27e7Smillert #  include <stdlib.h>
381acd27e7Smillert #else
391acd27e7Smillert #  include "ansi_stdlib.h"
401acd27e7Smillert #endif /* HAVE_STDLIB_H */
411acd27e7Smillert 
421acd27e7Smillert #if defined (HAVE_LOCALE_H)
431acd27e7Smillert #  include <locale.h>
441acd27e7Smillert #endif
451acd27e7Smillert 
461acd27e7Smillert #include <ctype.h>
471acd27e7Smillert 
481acd27e7Smillert #include "rldefs.h"
491acd27e7Smillert #include "readline.h"
501acd27e7Smillert #include "rlshell.h"
511acd27e7Smillert #include "rlprivate.h"
521acd27e7Smillert 
531acd27e7Smillert #if !defined (HAVE_SETLOCALE)
541acd27e7Smillert /* A list of legal values for the LANG or LC_CTYPE environment variables.
551acd27e7Smillert    If a locale name in this list is the value for the LC_ALL, LC_CTYPE,
561acd27e7Smillert    or LANG environment variable (using the first of those with a value),
571acd27e7Smillert    readline eight-bit mode is enabled. */
581acd27e7Smillert static char *legal_lang_values[] =
591acd27e7Smillert {
601acd27e7Smillert  "iso88591",
611acd27e7Smillert  "iso88592",
621acd27e7Smillert  "iso88593",
631acd27e7Smillert  "iso88594",
641acd27e7Smillert  "iso88595",
651acd27e7Smillert  "iso88596",
661acd27e7Smillert  "iso88597",
671acd27e7Smillert  "iso88598",
681acd27e7Smillert  "iso88599",
691acd27e7Smillert  "iso885910",
701acd27e7Smillert  "koi8r",
711acd27e7Smillert   0
721acd27e7Smillert };
731acd27e7Smillert 
74*af70c2dfSkettenis static char *normalize_codeset PARAMS((char *));
75*af70c2dfSkettenis static char *find_codeset PARAMS((char *, size_t *));
761acd27e7Smillert #endif /* !HAVE_SETLOCALE */
771acd27e7Smillert 
781acd27e7Smillert /* Check for LC_ALL, LC_CTYPE, and LANG and use the first with a value
791acd27e7Smillert    to decide the defaults for 8-bit character input and output.  Returns
801acd27e7Smillert    1 if we set eight-bit mode. */
811acd27e7Smillert int
_rl_init_eightbit()821acd27e7Smillert _rl_init_eightbit ()
831acd27e7Smillert {
841acd27e7Smillert /* If we have setlocale(3), just check the current LC_CTYPE category
851acd27e7Smillert    value, and go into eight-bit mode if it's not C or POSIX. */
861acd27e7Smillert #if defined (HAVE_SETLOCALE)
871acd27e7Smillert   char *t;
881acd27e7Smillert 
891acd27e7Smillert   /* Set the LC_CTYPE locale category from environment variables. */
901acd27e7Smillert   t = setlocale (LC_CTYPE, "");
911acd27e7Smillert   if (t && *t && (t[0] != 'C' || t[1]) && (STREQ (t, "POSIX") == 0))
921acd27e7Smillert     {
931acd27e7Smillert       _rl_meta_flag = 1;
941acd27e7Smillert       _rl_convert_meta_chars_to_ascii = 0;
951acd27e7Smillert       _rl_output_meta_chars = 1;
961acd27e7Smillert       return (1);
971acd27e7Smillert     }
981acd27e7Smillert   else
991acd27e7Smillert     return (0);
1001acd27e7Smillert 
1011acd27e7Smillert #else /* !HAVE_SETLOCALE */
1021acd27e7Smillert   char *lspec, *t;
1031acd27e7Smillert   int i;
1041acd27e7Smillert 
1051acd27e7Smillert   /* We don't have setlocale.  Finesse it.  Check the environment for the
1061acd27e7Smillert      appropriate variables and set eight-bit mode if they have the right
1071acd27e7Smillert      values. */
108*af70c2dfSkettenis   lspec = sh_get_env_value ("LC_ALL");
109*af70c2dfSkettenis   if (lspec == 0 || *lspec == '\0') lspec = sh_get_env_value ("LC_CTYPE");
110*af70c2dfSkettenis   if (lspec == 0 || *lspec == '\0') lspec = sh_get_env_value ("LANG");
11194bc1d69Smillert   if (lspec == 0 || *lspec == '\0' || (t = normalize_codeset (lspec)) == 0)
1121acd27e7Smillert     return (0);
1131acd27e7Smillert   for (i = 0; t && legal_lang_values[i]; i++)
1141acd27e7Smillert     if (STREQ (t, legal_lang_values[i]))
1151acd27e7Smillert       {
1161acd27e7Smillert 	_rl_meta_flag = 1;
1171acd27e7Smillert 	_rl_convert_meta_chars_to_ascii = 0;
1181acd27e7Smillert 	_rl_output_meta_chars = 1;
1191acd27e7Smillert 	break;
1201acd27e7Smillert       }
1211acd27e7Smillert   free (t);
1221acd27e7Smillert   return (legal_lang_values[i] ? 1 : 0);
1231acd27e7Smillert 
1241acd27e7Smillert #endif /* !HAVE_SETLOCALE */
1251acd27e7Smillert }
1261acd27e7Smillert 
1271acd27e7Smillert #if !defined (HAVE_SETLOCALE)
1281acd27e7Smillert static char *
normalize_codeset(codeset)1291acd27e7Smillert normalize_codeset (codeset)
1301acd27e7Smillert      char *codeset;
1311acd27e7Smillert {
1321acd27e7Smillert   size_t namelen, i;
1331acd27e7Smillert   int len, all_digits;
1341acd27e7Smillert   char *wp, *retval;
1351acd27e7Smillert 
1361acd27e7Smillert   codeset = find_codeset (codeset, &namelen);
1371acd27e7Smillert 
1381acd27e7Smillert   if (codeset == 0)
1391acd27e7Smillert     return (codeset);
1401acd27e7Smillert 
1411acd27e7Smillert   all_digits = 1;
1421acd27e7Smillert   for (len = 0, i = 0; i < namelen; i++)
1431acd27e7Smillert     {
144*af70c2dfSkettenis       if (ISALNUM ((unsigned char)codeset[i]))
1451acd27e7Smillert 	{
1461acd27e7Smillert 	  len++;
147*af70c2dfSkettenis 	  all_digits &= _rl_digit_p (codeset[i]);
1481acd27e7Smillert 	}
1491acd27e7Smillert     }
1501acd27e7Smillert 
1511acd27e7Smillert   retval = (char *)malloc ((all_digits ? 3 : 0) + len + 1);
1521acd27e7Smillert   if (retval == 0)
1531acd27e7Smillert     return ((char *)0);
1541acd27e7Smillert 
1551acd27e7Smillert   wp = retval;
1561acd27e7Smillert   /* Add `iso' to beginning of an all-digit codeset */
1571acd27e7Smillert   if (all_digits)
1581acd27e7Smillert     {
1591acd27e7Smillert       *wp++ = 'i';
1601acd27e7Smillert       *wp++ = 's';
1611acd27e7Smillert       *wp++ = 'o';
1621acd27e7Smillert     }
1631acd27e7Smillert 
1641acd27e7Smillert   for (i = 0; i < namelen; i++)
165*af70c2dfSkettenis     if (ISALPHA ((unsigned char)codeset[i]))
166*af70c2dfSkettenis       *wp++ = _rl_to_lower (codeset[i]);
167*af70c2dfSkettenis     else if (_rl_digit_p (codeset[i]))
1681acd27e7Smillert       *wp++ = codeset[i];
1691acd27e7Smillert   *wp = '\0';
1701acd27e7Smillert 
1711acd27e7Smillert   return retval;
1721acd27e7Smillert }
1731acd27e7Smillert 
1741acd27e7Smillert /* Isolate codeset portion of locale specification. */
1751acd27e7Smillert static char *
find_codeset(name,lenp)1761acd27e7Smillert find_codeset (name, lenp)
1771acd27e7Smillert      char *name;
1781acd27e7Smillert      size_t *lenp;
1791acd27e7Smillert {
1801acd27e7Smillert   char *cp, *language, *result;
1811acd27e7Smillert 
1821acd27e7Smillert   cp = language = name;
1831acd27e7Smillert   result = (char *)0;
1841acd27e7Smillert 
1851acd27e7Smillert   while (*cp && *cp != '_' && *cp != '@' && *cp != '+' && *cp != ',')
1861acd27e7Smillert     cp++;
1871acd27e7Smillert 
1881acd27e7Smillert   /* This does not make sense: language has to be specified.  As
1891acd27e7Smillert      an exception we allow the variable to contain only the codeset
1901acd27e7Smillert      name.  Perhaps there are funny codeset names.  */
1911acd27e7Smillert   if (language == cp)
1921acd27e7Smillert     {
1931acd27e7Smillert       *lenp = strlen (language);
1941acd27e7Smillert       result = language;
1951acd27e7Smillert     }
1961acd27e7Smillert   else
1971acd27e7Smillert     {
1981acd27e7Smillert       /* Next is the territory. */
1991acd27e7Smillert       if (*cp == '_')
2001acd27e7Smillert 	do
2011acd27e7Smillert 	  ++cp;
2021acd27e7Smillert 	while (*cp && *cp != '.' && *cp != '@' && *cp != '+' && *cp != ',' && *cp != '_');
2031acd27e7Smillert 
2041acd27e7Smillert       /* Now, finally, is the codeset. */
2051acd27e7Smillert       result = cp;
2061acd27e7Smillert       if (*cp == '.')
2071acd27e7Smillert 	do
2081acd27e7Smillert 	  ++cp;
2091acd27e7Smillert 	while (*cp && *cp != '@');
2101acd27e7Smillert 
2111acd27e7Smillert       if (cp - result > 2)
2121acd27e7Smillert 	{
2131acd27e7Smillert 	  result++;
2141acd27e7Smillert 	  *lenp = cp - result;
2151acd27e7Smillert 	}
2161acd27e7Smillert       else
2171acd27e7Smillert 	{
2181acd27e7Smillert 	  *lenp = strlen (language);
2191acd27e7Smillert 	  result = language;
2201acd27e7Smillert 	}
2211acd27e7Smillert     }
2221acd27e7Smillert 
2231acd27e7Smillert   return result;
2241acd27e7Smillert }
2251acd27e7Smillert #endif /* !HAVE_SETLOCALE */
226