summaryrefslogtreecommitdiffstats
path: root/lib/readline/nls.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/readline/nls.c')
-rw-r--r--lib/readline/nls.c348
1 files changed, 348 insertions, 0 deletions
diff --git a/lib/readline/nls.c b/lib/readline/nls.c
new file mode 100644
index 0000000..8c027d6
--- /dev/null
+++ b/lib/readline/nls.c
@@ -0,0 +1,348 @@
+/* nls.c -- skeletal internationalization code. */
+
+/* Copyright (C) 1996-2022 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library (Readline), a library
+ for reading lines of text with interactive input and history editing.
+
+ Readline is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Readline is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Readline. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_LOCALE_H)
+# include <locale.h>
+#endif
+
+#if defined (HAVE_LANGINFO_CODESET)
+# include <langinfo.h>
+#endif
+
+#include <ctype.h>
+
+#include "rldefs.h"
+#include "readline.h"
+#include "rlshell.h"
+#include "rlprivate.h"
+#include "xmalloc.h"
+
+static int utf8locale (char *);
+
+#define RL_DEFAULT_LOCALE "C"
+static char *_rl_current_locale = 0;
+
+#if !defined (HAVE_SETLOCALE)
+/* A list of legal values for the LANG or LC_CTYPE environment variables.
+ If a locale name in this list is the value for the LC_ALL, LC_CTYPE,
+ or LANG environment variable (using the first of those with a value),
+ readline eight-bit mode is enabled. */
+static char *legal_lang_values[] =
+{
+ "iso88591",
+ "iso88592",
+ "iso88593",
+ "iso88594",
+ "iso88595",
+ "iso88596",
+ "iso88597",
+ "iso88598",
+ "iso88599",
+ "iso885910",
+ "koi8r",
+ "utf8",
+ 0
+};
+
+static char *normalize_codeset (char *);
+#endif /* !HAVE_SETLOCALE */
+
+static char *find_codeset (char *, size_t *);
+
+static char *_rl_get_locale_var (const char *);
+
+static char *
+_rl_get_locale_var (const char *v)
+{
+ char *lspec;
+
+ lspec = sh_get_env_value ("LC_ALL");
+ if (lspec == 0 || *lspec == 0)
+ lspec = sh_get_env_value (v);
+ if (lspec == 0 || *lspec == 0)
+ lspec = sh_get_env_value ("LANG");
+
+ return lspec;
+}
+
+static int
+utf8locale (char *lspec)
+{
+ char *cp;
+ size_t len;
+
+#if HAVE_LANGINFO_CODESET
+ cp = nl_langinfo (CODESET);
+ return (STREQ (cp, "UTF-8") || STREQ (cp, "utf8"));
+#else
+ cp = find_codeset (lspec, &len);
+
+ if (cp == 0 || len < 4 || len > 5)
+ return 0;
+ return ((len == 5) ? strncmp (cp, "UTF-8", len) == 0 : strncmp (cp, "utf8", 4) == 0);
+#endif
+}
+
+/* Query the right environment variables and call setlocale() to initialize
+ the C library locale settings. */
+char *
+_rl_init_locale (void)
+{
+ char *ret, *lspec;
+
+ /* Set the LC_CTYPE locale category from environment variables. */
+ lspec = _rl_get_locale_var ("LC_CTYPE");
+ /* Since _rl_get_locale_var queries the right environment variables,
+ we query the current locale settings with setlocale(), and, if
+ that doesn't return anything, we set lspec to the empty string to
+ force the subsequent call to setlocale() to define the `native'
+ environment. */
+#if defined (HAVE_SETLOCALE)
+ if (lspec == 0 || *lspec == 0)
+ lspec = setlocale (LC_CTYPE, (char *)NULL);
+ if (lspec == 0)
+ lspec = "";
+ ret = setlocale (LC_CTYPE, lspec); /* ok, since it does not change locale */
+ if (ret == 0 || *ret == 0)
+ ret = setlocale (LC_CTYPE, (char *)NULL);
+ if (ret == 0 || *ret == 0)
+ ret = RL_DEFAULT_LOCALE;
+#else
+ ret = (lspec == 0 || *lspec == 0) ? RL_DEFAULT_LOCALE : lspec;
+#endif
+
+ _rl_utf8locale = (ret && *ret) ? utf8locale (ret) : 0;
+
+ _rl_current_locale = savestring (ret);
+ return ret;
+}
+
+/* If we have setlocale(3), just check the current LC_CTYPE category
+ value (passed as LOCALESTR), and go into eight-bit mode if it's not "C"
+ or "POSIX". If FORCE is non-zero, we reset the locale variables to values
+ appropriate for the C locale if the locale is "C" or "POSIX". FORCE is 0
+ when this is called from _rl_init_eightbit, since we're modifying the
+ default initial values and don't need to change anything else. If we
+ don't have setlocale(3), we check the codeset portion of LOCALESTR against
+ a set of known values and go into eight-bit mode if it matches one of those.
+ Returns 1 if we set eight-bit (multibyte) mode. */
+static int
+_rl_set_localevars (char *localestr, int force)
+{
+#if defined (HAVE_SETLOCALE)
+ if (localestr && *localestr && (localestr[0] != 'C' || localestr[1]) && (STREQ (localestr, "POSIX") == 0))
+ {
+ _rl_meta_flag = 1;
+ _rl_convert_meta_chars_to_ascii = 0;
+ _rl_output_meta_chars = 1;
+ return (1);
+ }
+ else if (force)
+ {
+ /* Default "C" locale settings. */
+ _rl_meta_flag = 0;
+ _rl_convert_meta_chars_to_ascii = 1;
+ _rl_output_meta_chars = 0;
+ return (0);
+ }
+ else
+ return (0);
+
+#else /* !HAVE_SETLOCALE */
+ char *t;
+ int i;
+
+ /* We don't have setlocale. Finesse it. Check the environment for the
+ appropriate variables and set eight-bit mode if they have the right
+ values. */
+ if (localestr == 0 || (t = normalize_codeset (localestr)) == 0)
+ return (0);
+ for (i = 0; t && legal_lang_values[i]; i++)
+ if (STREQ (t, legal_lang_values[i]))
+ {
+ _rl_meta_flag = 1;
+ _rl_convert_meta_chars_to_ascii = 0;
+ _rl_output_meta_chars = 1;
+ break;
+ }
+
+ if (force && legal_lang_values[i] == 0) /* didn't find it */
+ {
+ /* Default "C" locale settings. */
+ _rl_meta_flag = 0;
+ _rl_convert_meta_chars_to_ascii = 1;
+ _rl_output_meta_chars = 0;
+ }
+
+ _rl_utf8locale = *t ? STREQ (t, "utf8") : 0;
+
+ xfree (t);
+ return (legal_lang_values[i] ? 1 : 0);
+#endif /* !HAVE_SETLOCALE */
+}
+
+/* Check for LC_ALL, LC_CTYPE, and LANG and use the first with a value
+ to decide the defaults for 8-bit character input and output. Returns
+ 1 if we set eight-bit mode. */
+int
+_rl_init_eightbit (void)
+{
+ char *t, *ol;
+
+ ol = _rl_current_locale;
+ t = _rl_init_locale (); /* resets _rl_current_locale, returns static pointer */
+ xfree (ol);
+
+ return (_rl_set_localevars (t, 0));
+}
+
+#if !defined (HAVE_SETLOCALE)
+static char *
+normalize_codeset (char *codeset)
+{
+ size_t namelen, i;
+ int len, all_digits;
+ char *wp, *retval;
+
+ codeset = find_codeset (codeset, &namelen);
+
+ if (codeset == 0)
+ return (codeset);
+
+ all_digits = 1;
+ for (len = 0, i = 0; i < namelen; i++)
+ {
+ if (ISALNUM ((unsigned char)codeset[i]))
+ {
+ len++;
+ all_digits &= _rl_digit_p (codeset[i]);
+ }
+ }
+
+ retval = (char *)malloc ((all_digits ? 3 : 0) + len + 1);
+ if (retval == 0)
+ return ((char *)0);
+
+ wp = retval;
+ /* Add `iso' to beginning of an all-digit codeset */
+ if (all_digits)
+ {
+ *wp++ = 'i';
+ *wp++ = 's';
+ *wp++ = 'o';
+ }
+
+ for (i = 0; i < namelen; i++)
+ if (ISALPHA ((unsigned char)codeset[i]))
+ *wp++ = _rl_to_lower (codeset[i]);
+ else if (_rl_digit_p (codeset[i]))
+ *wp++ = codeset[i];
+ *wp = '\0';
+
+ return retval;
+}
+#endif /* !HAVE_SETLOCALE */
+
+/* Isolate codeset portion of locale specification. */
+static char *
+find_codeset (char *name, size_t *lenp)
+{
+ char *cp, *language, *result;
+
+ cp = language = name;
+ result = (char *)0;
+
+ while (*cp && *cp != '_' && *cp != '@' && *cp != '+' && *cp != ',')
+ cp++;
+
+ /* This does not make sense: language has to be specified. As
+ an exception we allow the variable to contain only the codeset
+ name. Perhaps there are funny codeset names. */
+ if (language == cp)
+ {
+ *lenp = strlen (language);
+ result = language;
+ }
+ else
+ {
+ /* Next is the territory. */
+ if (*cp == '_')
+ do
+ ++cp;
+ while (*cp && *cp != '.' && *cp != '@' && *cp != '+' && *cp != ',' && *cp != '_');
+
+ /* Now, finally, is the codeset. */
+ result = cp;
+ if (*cp == '.')
+ do
+ ++cp;
+ while (*cp && *cp != '@');
+
+ if (cp - result > 2)
+ {
+ result++;
+ *lenp = cp - result;
+ }
+ else
+ {
+ *lenp = strlen (language);
+ result = language;
+ }
+ }
+
+ return result;
+}
+
+void
+_rl_reset_locale (void)
+{
+ char *ol, *nl;
+
+ /* This should not be NULL; _rl_init_eightbit sets it on the first call to
+ readline() or rl_initialize(). */
+ ol = _rl_current_locale;
+ nl = _rl_init_locale (); /* resets _rl_current_locale */
+
+ if ((ol == 0 && nl) || (ol && nl && (STREQ (ol, nl) == 0)))
+ (void)_rl_set_localevars (nl, 1);
+
+ xfree (ol);
+}