]> 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 33963d5b25d611deb328c89684e312d0c3141403..235d913a3c821eabe1004a5327b131d135bace76 100644 (file)
@@ -1,5 +1,5 @@
 /* Implementation of the locale program according to POSIX 9945-2.
-   Copyright (C) 1995-1997, 1999-2008, 2009 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.
 
@@ -14,8 +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, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   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;
@@ -84,9 +82,7 @@ static const struct argp_option options[] =
 };
 
 /* Short description of program.  */
-static const char doc[] = N_("Get locale-specific information.\v\
-For bug reporting instructions, please see:\n\
-<http://www.gnu.org/software/libc/bugs.html>.\n");
+static const char doc[] = N_("Get locale-specific information.");
 
 /* Strings for arguments in help texts.  */
 static const char args_doc[] = N_("NAME\n[-a|-m]");
@@ -94,10 +90,13 @@ static const char args_doc[] = N_("NAME\n[-a|-m]");
 /* Prototype for option handler.  */
 static error_t parse_opt (int key, char *arg, struct argp_state *state);
 
+/* Function to print some extra text in the help message.  */
+static char *more_help (int key, const char *text, void *input);
+
 /* Data structure to communicate with argp functions.  */
 static struct argp argp =
 {
-  options, parse_opt, args_doc, doc
+  options, parse_opt, args_doc, doc, NULL, more_help
 };
 
 
@@ -143,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"
@@ -267,16 +266,36 @@ 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.  */
+      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\
-"), "2009");
+"), "2015");
   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
 }
 
@@ -306,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;
@@ -425,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");
 
@@ -521,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;
@@ -744,176 +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") ? : "";
-
-  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 ?: "")[0] ? lang : "POSIX");
-      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 == '\177' ? -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;
+         }
+
+       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);
 
-           if (show_keyword_name)
-             printf ("%s=", item->name);
+       printf ("%d\n", val.word);
+      }
+      break;
+    case wordarray:
+      {
+       int first = 1;
+       union { unsigned int *wordarray; char *string; } val;
 
-           while (cnt > 1)
-             {
-               printf ("%d;", *val == '\177' ? -1 : *val);
-                --cnt;
-               ++val;
-             }
+       val.string = nl_langinfo (item->item_id);
+       if (show_keyword_name)
+         printf ("%s=", item->name);
 
-           printf ("%d\n", cnt == 0 || *val == '\177' ? -1 : *val);
-         }
-         break;
-       case word:
+       for (int cnt = 0; cnt < item->max; ++cnt)
          {
-           union { unsigned int word; char *string; } val;
-           val.string = nl_langinfo (item->item_id);
-           if (show_keyword_name)
-             printf ("%s=", item->name);
-
-           printf ("%d\n", val.word);
+           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)