summaryrefslogtreecommitdiff
path: root/locale/programs/locale.c
diff options
context:
space:
mode:
Diffstat (limited to 'locale/programs/locale.c')
-rw-r--r--locale/programs/locale.c143
1 files changed, 131 insertions, 12 deletions
diff --git a/locale/programs/locale.c b/locale/programs/locale.c
index 86941e4ef6..e07108d345 100644
--- a/locale/programs/locale.c
+++ b/locale/programs/locale.c
@@ -1,5 +1,5 @@
/* Implementation of the locale program according to POSIX 9945-2.
- Copyright (C) 1995-2018 Free Software Foundation, Inc.
+ Copyright (C) 1995-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1995.
@@ -14,7 +14,7 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, see <https://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
@@ -173,6 +173,9 @@ static int write_archive_locales (void **all_datap, char *linebuf);
static void write_charmaps (void);
static void show_locale_vars (void);
static void show_info (const char *name);
+static void try_setlocale (int category, const char *category_name);
+static char *quote_string (const char *input);
+static void setlocale_diagnostics (void);
int
@@ -186,10 +189,8 @@ main (int argc, char *argv[])
/* Set locale. Do not set LC_ALL because the other categories must
not be affected (according to POSIX.2). */
- if (setlocale (LC_CTYPE, "") == NULL)
- error (0, errno, gettext ("Cannot set LC_CTYPE to default locale"));
- if (setlocale (LC_MESSAGES, "") == NULL)
- error (0, errno, gettext ("Cannot set LC_MESSAGES to default locale"));
+ try_setlocale (LC_CTYPE, "LC_CTYPE");
+ try_setlocale (LC_MESSAGES, "LC_MESSAGES");
/* Initialize the message catalog. */
textdomain (PACKAGE);
@@ -200,9 +201,8 @@ main (int argc, char *argv[])
/* `-a' requests the names of all available locales. */
if (do_all != 0)
{
- if (setlocale (LC_COLLATE, "") == NULL)
- error (0, errno,
- gettext ("Cannot set LC_COLLATE to default locale"));
+ setlocale_diagnostics ();
+ try_setlocale (LC_COLLATE, "LC_COLLATE");
write_locales ();
exit (EXIT_SUCCESS);
}
@@ -211,14 +211,15 @@ main (int argc, char *argv[])
used for the -f argument to localedef(1). */
if (do_charmaps != 0)
{
+ setlocale_diagnostics ();
write_charmaps ();
exit (EXIT_SUCCESS);
}
/* Specific information about the current locale are requested.
Change to this locale now. */
- if (setlocale (LC_ALL, "") == NULL)
- error (0, errno, gettext ("Cannot set LC_ALL to default locale"));
+ try_setlocale (LC_ALL, "LC_ALL");
+ setlocale_diagnostics ();
/* If no real argument is given we have to print the contents of the
current locale definition variables. These are LANG and the LC_*. */
@@ -293,7 +294,7 @@ print_version (FILE *stream, struct argp_state *state)
Copyright (C) %s Free Software Foundation, Inc.\n\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2018");
+"), "2019");
fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
}
@@ -983,3 +984,121 @@ show_info (const char *name)
For testing and perhaps advanced use allow some more symbols. */
locale_special (name, show_category_name, show_keyword_name);
}
+
+/* Set to true by try_setlocale if setlocale fails. Used by
+ setlocale_diagnostics. */
+static bool setlocale_failed;
+
+/* Call setlocale, with non-fatal error reporting. */
+static void
+try_setlocale (int category, const char *category_name)
+{
+ if (setlocale (category, "") == NULL)
+ {
+ error (0, errno, gettext ("Cannot set %s to default locale"),
+ category_name);
+ setlocale_failed = true;
+ }
+}
+
+/* Return a quoted version of the passed string, or NULL on error. */
+static char *
+quote_string (const char *input)
+{
+ char *buffer;
+ size_t length;
+ FILE *stream = open_memstream (&buffer, &length);
+ if (stream == NULL)
+ return NULL;
+
+ while (true)
+ {
+ unsigned char ch = *input++;
+ if (ch == '\0')
+ break;
+
+ /* Use C backslash escapes for those control characters for
+ which they are defined. */
+ switch (ch)
+ {
+ case '\a':
+ putc_unlocked ('\\', stream);
+ putc_unlocked ('a', stream);
+ break;
+ case '\b':
+ putc_unlocked ('\\', stream);
+ putc_unlocked ('b', stream);
+ break;
+ case '\f':
+ putc_unlocked ('\\', stream);
+ putc_unlocked ('f', stream);
+ break;
+ case '\n':
+ putc_unlocked ('\\', stream);
+ putc_unlocked ('n', stream);
+ break;
+ case '\r':
+ putc_unlocked ('\\', stream);
+ putc_unlocked ('r', stream);
+ break;
+ case '\t':
+ putc_unlocked ('\\', stream);
+ putc_unlocked ('t', stream);
+ break;
+ case '\v':
+ putc_unlocked ('\\', stream);
+ putc_unlocked ('v', stream);
+ break;
+ case '\\':
+ case '\'':
+ case '\"':
+ putc_unlocked ('\\', stream);
+ putc_unlocked (ch, stream);
+ break;
+ default:
+ if (ch < ' ' || ch > '~')
+ /* Use octal sequences because they are fixed width,
+ unlike hexadecimal sequences. */
+ fprintf (stream, "\\%03o", ch);
+ else
+ putc_unlocked (ch, stream);
+ }
+ }
+
+ if (ferror (stream))
+ {
+ fclose (stream);
+ free (buffer);
+ return NULL;
+ }
+ if (fclose (stream) != 0)
+ {
+ free (buffer);
+ return NULL;
+ }
+
+ return buffer;
+}
+
+/* Print additional information if there was a setlocale error (during
+ try_setlocale). */
+static void
+setlocale_diagnostics (void)
+{
+ if (setlocale_failed)
+ {
+ const char *locpath = getenv ("LOCPATH");
+ if (locpath != NULL)
+ {
+ char *quoted = quote_string (locpath);
+ if (quoted != NULL)
+ fprintf (stderr,
+ gettext ("\
+warning: The LOCPATH variable is set to \"%s\"\n"),
+ quoted);
+ else
+ fputs ("warning: The LOCPATH variable is set\n", stderr);
+ free (quoted);
+ }
+ }
+}