]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - locale/programs/locale.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / locale / programs / locale.c
index 1a9673984decadc44d524c985af93f8dba0215fe..235d913a3c821eabe1004a5327b131d135bace76 100644 (file)
@@ -1,22 +1,20 @@
 /* Implementation of the locale program according to POSIX 9945-2.
-   Copyright (C) 1995-1997,1999,2000,2001,2002 Free Software Foundation, Inc.
+   Copyright (C) 1995-2016 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1995.
 
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
+   This program 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; version 2 of the License, or
+   (at your option) any later version.
 
-   The GNU C Library is distributed in the hope that it will be useful,
+   This program 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
-   Lesser General Public License for more details.
+   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 Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <stdint.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 
 #include "localeinfo.h"
 #include "charmap-dir.h"
 #include "../locarchive.h"
+#include <programs/xmalloc.h>
 
-extern void *xmalloc (size_t __n);
-extern char *xstrdup (const char *__str);
-
-#define ARCHIVE_NAME LOCALEDIR "/locale-archive"
+#define ARCHIVE_NAME COMPLOCALEDIR "/locale-archive"
 
 /* If set print the name of the category.  */
 static int show_category_name;
@@ -145,7 +142,7 @@ struct category
 #define DEFINE_CATEGORY(category, name, items, postload) \
     static struct cat_item category##_desc[] =                               \
       {                                                                              \
-        NO_PAREN items                                                       \
+       NO_PAREN items                                                        \
       };
 
 #include "categories.def"
@@ -191,8 +188,10 @@ main (int argc, char *argv[])
 
   /* Set locale.  Do not set LC_ALL because the other categories must
      not be affected (according to POSIX.2).  */
-  setlocale (LC_CTYPE, "");
-  setlocale (LC_MESSAGES, "");
+  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"));
 
   /* Initialize the message catalog.  */
   textdomain (PACKAGE);
@@ -203,7 +202,9 @@ main (int argc, char *argv[])
   /* `-a' requests the names of all available locales.  */
   if (do_all != 0)
     {
-      setlocale (LC_COLLATE, "");
+      if (setlocale (LC_COLLATE, "") == NULL)
+       error (0, errno,
+              gettext ("Cannot set LC_COLLATE to default locale"));
       write_locales ();
       exit (EXIT_SUCCESS);
     }
@@ -218,7 +219,8 @@ main (int argc, char *argv[])
 
   /* Specific information about the current locale are requested.
      Change to this locale now.  */
-  setlocale (LC_ALL, "");
+  if (setlocale (LC_ALL, "") == NULL)
+    error (0, errno, gettext ("Cannot set LC_ALL to default locale"));
 
   /* If no real argument is given we have to print the contents of the
      current locale definition variables.  These are LANG and the LC_*.  */
@@ -267,28 +269,33 @@ parse_opt (int key, char *arg, struct argp_state *state)
 static char *
 more_help (int key, const char *text, void *input)
 {
+  char *tp = NULL;
   switch (key)
     {
     case ARGP_KEY_HELP_EXTRA:
       /* We print some extra information.  */
-      return xstrdup (gettext ("\
-Report bugs using the `glibcbug' script to <bugs@gnu.org>.\n"));
+      if (asprintf (&tp, gettext ("\
+For bug reporting instructions, please see:\n\
+%s.\n"), REPORT_BUGS_TO) < 0)
+       return NULL;
+      return tp;
     default:
       break;
     }
   return (char *) text;
 }
 
+
 /* Print the version information.  */
 static void
 print_version (FILE *stream, struct argp_state *state)
 {
-  fprintf (stream, "locale (GNU %s) %s\n", PACKAGE, VERSION);
+  fprintf (stream, "locale %s%s\n", PKGVERSION, VERSION);
   fprintf (stream, gettext ("\
 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\
-"), "2002");
+"), "2015");
   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
 }
 
@@ -318,9 +325,11 @@ select_dirs (const struct dirent *dirent)
 #endif
        {
          struct stat64 st;
-         char buf[sizeof (LOCALEDIR) + strlen (dirent->d_name) + 1];
+         char buf[sizeof (COMPLOCALEDIR)
+                  + strlen (dirent->d_name) + 1];
 
-         stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"), dirent->d_name);
+         stpcpy (stpcpy (stpcpy (buf, COMPLOCALEDIR), "/"),
+                 dirent->d_name);
 
          if (stat64 (buf, &st) == 0)
            mode = st.st_mode;
@@ -437,17 +446,21 @@ write_locales (void)
     first_locale = 0;
 
   /* Now we can look for all files in the directory.  */
-  ndirents = scandir (LOCALEDIR, &dirents, select_dirs, alphasort);
+  ndirents = scandir (COMPLOCALEDIR, &dirents, select_dirs,
+                     alphasort);
   for (cnt = 0; cnt < ndirents; ++cnt)
     {
       /* Test whether at least the LC_CTYPE data is there.  Some
         directories only contain translations.  */
-      char buf[sizeof (LOCALEDIR) + strlen (dirents[cnt]->d_name)
-             + sizeof "/LC_IDENTIFICATION"];
+      char buf[sizeof (COMPLOCALEDIR)
+              + strlen (dirents[cnt]->d_name)
+              + sizeof "/LC_IDENTIFICATION"];
       char *enddir;
       struct stat64 st;
 
-      stpcpy (enddir = stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"),
+      stpcpy (enddir = stpcpy (stpcpy (stpcpy (buf,
+                                              COMPLOCALEDIR),
+                                              "/"),
                               dirents[cnt]->d_name),
              "/LC_IDENTIFICATION");
 
@@ -533,7 +546,7 @@ write_locales (void)
             because
             a) we are only interested in the first two fields
             b) these fields must be usable as file names and so must
-               not be that long  */
+               not be that long  */
          char buf[BUFSIZ];
          char *alias;
          char *value;
@@ -756,175 +769,210 @@ write_charmaps (void)
   twalk (all_data, print_names);
 }
 
+/* Print a properly quoted assignment of NAME with VAL, using double
+   quotes iff DQUOTE is true.  */
+static void
+print_assignment (const char *name, const char *val, bool dquote)
+{
+  printf ("%s=", name);
+  if (dquote)
+    putchar ('"');
+  while (*val != '\0')
+    {
+      size_t segment
+       = strcspn (val, dquote ? "$`\"\\" : "~|&;<>()$`\\\"' \t\n");
+      printf ("%.*s", (int) segment, val);
+      val += segment;
+      if (*val == '\0')
+       break;
+      putchar ('\\');
+      putchar (*val++);
+    }
+  if (dquote)
+    putchar ('"');
+  putchar ('\n');
+}
 
 /* We have to show the contents of the environments determining the
    locale.  */
 static void
 show_locale_vars (void)
 {
-  size_t cat_no;
-  const char *lcall = getenv ("LC_ALL");
-  const char *lang = getenv ("LANG") ? : "POSIX";
-
-  auto void get_source (const char *name);
-
-  void get_source (const char *name)
-    {
-      char *val = getenv (name);
-
-      if ((lcall ?: "")[0] != '\0' || val == NULL)
-       printf ("%s=\"%s\"\n", name, (lcall ?: "")[0] ? lcall : lang);
-      else
-       printf ("%s=%s\n", name, val);
-    }
+  const char *lcall = getenv ("LC_ALL") ?: "";
+  const char *lang = getenv ("LANG") ?: "";
 
   /* LANG has to be the first value.  */
-  printf ("LANG=%s\n", lang);
+  print_assignment ("LANG", lang, false);
 
   /* Now all categories in an unspecified order.  */
-  for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
+  for (size_t cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
     if (cat_no != LC_ALL)
-      get_source (category[cat_no].name);
+      {
+       const char *name = category[cat_no].name;
+       const char *val = getenv (name);
+
+       if (lcall[0] != '\0' || val == NULL)
+         print_assignment (name,
+                           lcall[0] != '\0' ? lcall
+                           : lang[0] != '\0' ? lang
+                           : "POSIX",
+                           true);
+       else
+         print_assignment (name, val, false);
+      }
 
   /* The last is the LC_ALL value.  */
-  printf ("LC_ALL=%s\n", lcall ? : "");
+  print_assignment ("LC_ALL", lcall, false);
 }
 
 
-/* Show the information request for NAME.  */
+/* Subroutine of show_info, below.  */
 static void
-show_info (const char *name)
+print_item (struct cat_item *item)
 {
-  size_t cat_no;
-
-  auto void print_item (struct cat_item *item);
-
-  void print_item (struct cat_item *item)
+  switch (item->value_type)
     {
-      switch (item->value_type)
-       {
-       case string:
-         if (show_keyword_name)
-           printf ("%s=\"", item->name);
-         fputs (nl_langinfo (item->item_id) ? : "", stdout);
-         if (show_keyword_name)
-           putchar ('"');
-         putchar ('\n');
-         break;
-       case stringarray:
-         {
-           int cnt;
-           const char *val;
-
-           if (show_keyword_name)
-             printf ("%s=\"", item->name);
+    case string:
+      if (show_keyword_name)
+       printf ("%s=\"", item->name);
+      fputs (nl_langinfo (item->item_id) ? : "", stdout);
+      if (show_keyword_name)
+       putchar ('"');
+      putchar ('\n');
+      break;
+    case stringarray:
+      {
+       const char *val;
+       int cnt;
 
-           for (cnt = 0; cnt < item->max - 1; ++cnt)
-             {
-               val = nl_langinfo (item->item_id + cnt);
-               if (val != NULL)
-                 fputs (val, stdout);
-               putchar (';');
-             }
+       if (show_keyword_name)
+         printf ("%s=\"", item->name);
 
+       for (cnt = 0; cnt < item->max - 1; ++cnt)
+         {
            val = nl_langinfo (item->item_id + cnt);
            if (val != NULL)
              fputs (val, stdout);
-
-           if (show_keyword_name)
-             putchar ('"');
-           putchar ('\n');
+           putchar (';');
          }
-         break;
-       case stringlist:
+
+       val = nl_langinfo (item->item_id + cnt);
+       if (val != NULL)
+         fputs (val, stdout);
+
+       if (show_keyword_name)
+         putchar ('"');
+       putchar ('\n');
+      }
+      break;
+    case stringlist:
+      {
+       int first = 1;
+       const char *val = nl_langinfo (item->item_id) ? : "";
+
+       if (show_keyword_name)
+         printf ("%s=", item->name);
+
+       for (int cnt = 0; cnt < item->max && *val != '\0'; ++cnt)
          {
-           int first = 1;
-           const char *val = nl_langinfo (item->item_id) ? : "";
-           int cnt;
-
-           if (show_keyword_name)
-             printf ("%s=", item->name);
-
-           for (cnt = 0; cnt < item->max && *val != '\0'; ++cnt)
-             {
-               printf ("%s%s%s%s", first ? "" : ";",
-                       show_keyword_name ? "\"" : "", val,
-                       show_keyword_name ? "\"" : "");
-               val = strchr (val, '\0') + 1;
-               first = 0;
-             }
-           putchar ('\n');
+           printf ("%s%s%s%s", first ? "" : ";",
+                   show_keyword_name ? "\"" : "", val,
+                   show_keyword_name ? "\"" : "");
+           val = strchr (val, '\0') + 1;
+           first = 0;
          }
-         break;
-       case byte:
-         {
-           const char *val = nl_langinfo (item->item_id);
+       putchar ('\n');
+      }
+      break;
+    case byte:
+      {
+       const char *val = nl_langinfo (item->item_id);
 
-           if (show_keyword_name)
-             printf ("%s=", item->name);
+       if (show_keyword_name)
+         printf ("%s=", item->name);
 
-           if (val != NULL)
-             printf ("%d", *val == CHAR_MAX ? -1 : *val);
-           putchar ('\n');
-         }
-         break;
-       case bytearray:
+       if (val != NULL)
+         printf ("%d", *val == '\377' ? -1 : *val);
+       putchar ('\n');
+      }
+      break;
+    case bytearray:
+      {
+       const char *val = nl_langinfo (item->item_id);
+       int cnt = val ? strlen (val) : 0;
+
+       if (show_keyword_name)
+         printf ("%s=", item->name);
+
+       while (cnt > 1)
          {
-           const char *val = nl_langinfo (item->item_id);
-           int cnt = val ? strlen (val) : 0;
+           printf ("%d;", *val == '\177' ? -1 : *val);
+           --cnt;
+           ++val;
+         }
 
-           if (show_keyword_name)
-             printf ("%s=", item->name);
+       printf ("%d\n", cnt == 0 || *val == '\177' ? -1 : *val);
+      }
+      break;
+    case word:
+      {
+       union { unsigned int word; char *string; } val;
+       val.string = nl_langinfo (item->item_id);
+       if (show_keyword_name)
+         printf ("%s=", item->name);
 
-           while (cnt > 1)
-             {
-               printf ("%d;", *val == CHAR_MAX ? -1 : *val);
-                --cnt;
-               ++val;
-             }
+       printf ("%d\n", val.word);
+      }
+      break;
+    case wordarray:
+      {
+       int first = 1;
+       union { unsigned int *wordarray; char *string; } val;
 
-           printf ("%d\n", cnt == 0 || *val == CHAR_MAX ? -1 : *val);
-         }
-         break;
-       case word:
-         {
-           unsigned int val =
-             (unsigned int) (unsigned long int) nl_langinfo (item->item_id);
-           if (show_keyword_name)
-             printf ("%s=", item->name);
+       val.string = nl_langinfo (item->item_id);
+       if (show_keyword_name)
+         printf ("%s=", item->name);
 
-           printf ("%d\n", val);
+       for (int cnt = 0; cnt < item->max; ++cnt)
+         {
+           printf ("%s%d", first ? "" : ";", val.wordarray[cnt]);
+           first = 0;
          }
-         break;
-       case wstring:
-       case wstringarray:
-       case wstringlist:
-         /* We don't print wide character information since the same
-            information is available in a multibyte string.  */
-       default:
-         break;
-
-       }
+       putchar ('\n');
+      }
+      break;
+    case wstring:
+    case wstringarray:
+    case wstringlist:
+      /* We don't print wide character information since the same
+        information is available in a multibyte string.  */
+    default:
+      break;
     }
+}
 
-  for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
+/* Show the information request for NAME.  */
+static void
+show_info (const char *name)
+{
+  for (size_t cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
     if (cat_no != LC_ALL)
       {
-       size_t item_no;
-
        if (strcmp (name, category[cat_no].name) == 0)
          /* Print the whole category.  */
          {
            if (show_category_name != 0)
              puts (category[cat_no].name);
 
-           for (item_no = 0; item_no < category[cat_no].number; ++item_no)
+           for (size_t item_no = 0;
+                item_no < category[cat_no].number;
+                ++item_no)
              print_item (&category[cat_no].item_desc[item_no]);
 
            return;
          }
 
-       for (item_no = 0; item_no < category[cat_no].number; ++item_no)
+       for (size_t item_no = 0; item_no < category[cat_no].number; ++item_no)
          if (strcmp (name, category[cat_no].item_desc[item_no].name) == 0)
            {
              if (show_category_name != 0)