about summary refs log tree commit diff
path: root/locale/programs/localedef.c
diff options
context:
space:
mode:
Diffstat (limited to 'locale/programs/localedef.c')
-rw-r--r--locale/programs/localedef.c299
1 files changed, 105 insertions, 194 deletions
diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c
index 69e9dc5555..5eadbf3570 100644
--- a/locale/programs/localedef.c
+++ b/locale/programs/localedef.c
@@ -1,6 +1,6 @@
 /* Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+   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 Library General Public License as
@@ -30,26 +30,16 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#ifdef _POSIX2_LOCALEDEF
-# include <sys/mman.h>
-#endif
+#include <sys/mman.h>
 #include <sys/stat.h>
 
 #include "error.h"
-#include "charset.h"
+#include "charmap.h"
 #include "locfile.h"
-#include "locales.h"
-
 
-/* This is a special entry of the copylist.  For all categories we don't
-   have a definition we use the data for the POSIX locale.  */
-struct copy_def_list_t copy_posix =
-{
-  next: NULL,
-  name: "POSIX",
-  mask: (1 << LC_ALL) - 1,
-  locale: NULL
-};
+/* Undefine the following line in the production version.  */
+/* #define NDEBUG 1 */
+#include <assert.h>
 
 
 /* List of copied locales.  */
@@ -74,7 +64,10 @@ static const char *charmap_file;
 static const char *input_file;
 
 /* Name of the repertoire map file.  */
-const char *repertoiremap;
+const char *repertoire_global;
+
+/* List of all locales.  */
+static struct localedef_t *locales;
 
 
 /* Name and version of program.  */
@@ -88,11 +81,10 @@ void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
 static const struct argp_option options[] =
 {
   { NULL, 0, NULL, 0, N_("Input Files:") },
-  { "charmap", 'f', N_("FILE"), 0,
+  { "charmap", 'f', "FILE", 0,
     N_("Symbolic character names defined in FILE") },
-  { "inputfile", 'i', N_("FILE"), 0,
-    N_("Source definitions are found in FILE") },
-  { "repertoire-map", 'u', N_("FILE"), 0,
+  { "inputfile", 'i', "FILE", 0, N_("Source definitions are found in FILE") },
+  { "repertoire-map", 'u', "FILE", 0,
     N_("FILE contains mapping from symbolic names to UCS4 values") },
 
   { NULL, 0, NULL, 0, N_("Output control:") },
@@ -125,7 +117,7 @@ static struct argp argp =
 
 
 /* Prototypes for global functions.  */
-void *xmalloc (size_t __n);
+extern void *xmalloc (size_t __n);
 
 /* Prototypes for local functions.  */
 static void error_print (void);
@@ -138,12 +130,12 @@ main (int argc, char *argv[])
 {
   const char *output_path;
   int cannot_write_why;
-  struct charset_t *charset;
-  struct localedef_t *localedef;
-  struct copy_def_list_t *act_add_locdef;
+  struct charmap_t *charmap;
+  struct localedef_t global;
   int remaining;
 
   /* Set initial values for global variables.  */
+  copy_list = NULL;
   posix_conformance = getenv ("POSIXLY_CORRECT") != NULL;
   error_print_progname = error_print;
 
@@ -187,135 +179,37 @@ main (int argc, char *argv[])
     error (3, 0, _("FATAL: system does not define `_POSIX2_LOCALEDEF'"));
 
   /* Process charmap file.  */
-  charset = charmap_read (charmap_file);
+  charmap = charmap_read (charmap_file);
+
+  /* Add the first entry in the locale list.  */
+  memset (&global, '\0', sizeof (struct localedef_t));
+  global.name = input_file;
+  global.needed = ALL_LOCALES;
+  locales = &global;
 
   /* Now read the locale file.  */
-  localedef = locfile_read (input_file, charset);
-  if (localedef->failed != 0)
+  if (locfile_read (&global, charmap) != 0)
     error (4, errno, _("cannot open locale definition file `%s'"), input_file);
 
-  /* Make sure all categories are defined.  */
-  copy_posix.next = copy_list;
-  copy_list = &copy_posix;
-
-  /* Perhaps we saw some `copy' instructions.  Process the given list.
-     We use a very simple algorithm: we look up the list from the
-     beginning every time.  */
-  do
+  /* Perhaps we saw some `copy' instructions.  */
+  while (1)
     {
-      int cat = 0;
+      struct localedef_t *runp = locales;
 
-      for (act_add_locdef = copy_list; act_add_locdef != NULL;
-	   act_add_locdef = act_add_locdef->next)
-	{
-	  for (cat = LC_CTYPE; cat <= LC_MESSAGES; ++cat)
-	    if ((act_add_locdef->mask & (1 << cat)) != 0)
-	      {
-		act_add_locdef->mask &= ~(1 << cat);
-		break;
-	      }
-	  if (cat <= LC_MESSAGES)
-	    break;
-	}
+      while (runp != NULL && runp->needed == runp->avail)
+	runp = runp->next;
 
-      if (act_add_locdef != NULL)
-	{
-	  int avail = 0;
-
-	  if (act_add_locdef->locale == NULL)
-	    {
-	      /* Saving the mask is an ugly trick to prevent the reader
-		 from modifying `copy_posix' if we currently process it.  */
-	      int save_mask = act_add_locdef->mask;
-	      act_add_locdef->locale = locfile_read (act_add_locdef->name,
-						     charset);
-	      act_add_locdef->mask = save_mask;
-	    }
-
-	  if (! act_add_locdef->locale->failed)
-	    {
-	      avail = act_add_locdef->locale->categories[cat].generic != NULL;
-	      if (avail)
-		{
-		  localedef->categories[cat].generic
-		    = act_add_locdef->locale->categories[cat].generic;
-		  localedef->avail |= 1 << cat;
-		}
-	    }
-
-	  if (! avail)
-	    {
-	      static const char *locale_names[] =
-	      {
-		"LC_COLLATE", "LC_CTYPE", "LC_MONETARY",
-		"LC_NUMERIC", "LC_TIME", "LC_MESSAGES"
-	      };
-	      char *fname;
-	      int fd;
-	      struct stat st;
-
-	      asprintf (&fname, LOCALEDIR "/%s/%s", act_add_locdef->name,
-			locale_names[cat]);
-	      fd = open (fname, O_RDONLY);
-	      if (fd == -1)
-		{
-		  free (fname);
-
-		  asprintf (&fname, LOCALEDIR "/%s/%s/SYS_%s",
-			    act_add_locdef->name, locale_names[cat],
-			    locale_names[cat]);
-
-		  fd = open (fname, O_RDONLY);
-		  if (fd == -1)
-		    error (5, 0, _("\
-locale file `%s', used in `copy' statement, not found"),
-			   act_add_locdef->name);
-		}
-
-	      if (fstat (fd, &st) < 0)
-		error (5, errno, _("\
-cannot `stat' locale file `%s'"),
-		       fname);
-
-	      localedef->len[cat] = st.st_size;
-#ifdef _POSIX_MAPPED_FILES
-	      localedef->categories[cat].generic
-		= mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-
-	      if (localedef->categories[cat].generic == MAP_FAILED)
-#endif	/* _POSIX_MAPPED_FILES */
-		{
-		  size_t left = st.st_size;
-		  void *read_ptr;
-
-		  localedef->categories[cat].generic
-		    = xmalloc (st.st_size);
-		  read_ptr = localedef->categories[cat].generic;
-
-		  do
-		    {
-		      long int n;
-		      n = read (fd, read_ptr, left);
-		      if (n == -1)
-			error (5, errno, _("cannot read locale file `%s'"),
-			       fname);
-		      read_ptr += n;
-		      left -= n;
-		    }
-		  while (left > 0);
-		}
-
-	      close (fd);
-	      free (fname);
-
-	      localedef->binary |= 1 << cat;
-	    }
-	}
+      if (runp == NULL)
+	/* Everything read.  */
+	break;
+
+      if (locfile_read (runp, charmap) != 0)
+	error (4, errno, _("cannot open locale definition file `%s'"),
+	       runp->name);
     }
-  while (act_add_locdef != NULL);
 
   /* Check the categories we processed in source form.  */
-  check_all_categories (localedef, charset);
+  check_all_categories (locales, charmap);
 
   /* We are now able to write the data files.  If warning were given we
      do it only if it is explicitly requested (--force).  */
@@ -325,7 +219,7 @@ cannot `stat' locale file `%s'"),
 	error (4, cannot_write_why, _("cannot write output files to `%s'"),
 	       output_path);
       else
-	write_all_categories (localedef, charset, output_path);
+	write_all_categories (locales, charmap, output_path);
     }
   else
     error (4, 0, _("no output file produced because warning were issued"));
@@ -357,7 +251,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
       input_file = arg;
       break;
     case 'u':
-      repertoiremap = arg;
+      repertoire_global = arg;
       break;
     case 'v':
       verbose = 1;
@@ -406,50 +300,11 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
 }
 
 
-void
-def_to_process (const char *name, int category)
-{
-  struct copy_def_list_t *new, **rp;
-
-  for (rp = &copy_list; *rp != NULL; rp = &(*rp)->next)
-    if (strcmp (name, (*rp)->name) == 0)
-      break;
-
-  if (*rp == NULL)
-    {
-      size_t cnt;
-
-      *rp = (struct copy_def_list_t *) xmalloc (sizeof (**rp));
-
-      (*rp)->next = NULL;
-      (*rp)->name = name;
-      (*rp)->mask = 0;
-      (*rp)->locale = NULL;
-
-      for (cnt = 0; cnt < 6; ++cnt)
-	{
-	  (*rp)->binary[cnt].data = NULL;
-	  (*rp)->binary[cnt].len = 0;
-	}
-    }
-  new = *rp;
-
-  if ((new->mask & category) != 0)
-    /* We already have the information.  This cannot happen.  */
-    error (5, 0, _("\
-category data requested more than once: should not happen"));
-
-  new->mask |= category;
-}
-
-
 /* The address of this function will be assigned to the hook in the error
    functions.  */
 static void
-error_print ()
+error_print (void)
 {
-  /* We don't want the program name to be printed in messages.  Emacs'
-     compile.el does not like this.  */
 }
 
 
@@ -461,13 +316,15 @@ construct_output_path (char *path)
 {
   const char *normal = NULL;
   char *result;
+  char *endp;
 
   if (strchr (path, '/') == NULL)
     {
       /* This is a system path.  First examine whether the locale name
 	 contains a reference to the codeset.  This should be
 	 normalized.  */
-      char *startp, *endp;
+      char *startp;
+      size_t n;
 
       startp = path;
       /* We must be prepared for finding a CEN name or a location of
@@ -493,17 +350,20 @@ construct_output_path (char *path)
 	 the end of the function we need another byte for the trailing
 	 '/'.  */
       if (normal == NULL)
-	asprintf (&result, "%s/%s%c", LOCALEDIR, path, '\0');
+	n = asprintf (&result, "%s/%s%c", LOCALEDIR, path, '\0');
       else
-	asprintf (&result, "%s/%.*s%s%s%c", LOCALEDIR, startp - path, path,
-		  normal, endp, '\0');
+	n = asprintf (&result, "%s/%.*s%s%s%c", LOCALEDIR, startp - path, path,
+		      normal, endp, '\0');
+
+      endp = result + n;
     }
   else
     {
       /* This is a user path.  Please note the additional byte in the
 	 memory allocation.  */
-      result = xmalloc (strlen (path) + 2);
-      strcpy (result, path);
+      size_t len = strlen (path) + 1;
+      result = xmalloc (len + 1);
+      endp = mempcpy (result, path, len);
     }
 
   errno = 0;
@@ -516,11 +376,13 @@ construct_output_path (char *path)
 	mkdir (result, 0777);
       }
 
-  strcat (result, "/");
+  *endp++ = '/';
+  *endp = '\0';
 
   return result;
 }
 
+
 /* Normalize codeset name.  There is no standard for the codeset
    names.  Normalization allows the user to use any of the common
    names.  */
@@ -555,7 +417,7 @@ normalize_codeset (codeset, name_len)
 
       for (cnt = 0; cnt < name_len; ++cnt)
 	if (isalpha (codeset[cnt]))
-	  *wp++ = _tolower (codeset[cnt]);
+	  *wp++ = tolower (codeset[cnt]);
 	else if (isdigit (codeset[cnt]))
 	  *wp++ = codeset[cnt];
 
@@ -564,3 +426,52 @@ normalize_codeset (codeset, name_len)
 
   return (const char *) retval;
 }
+
+
+struct localedef_t *
+add_to_readlist (int locale, const char *name, const char *repertoire_name)
+{
+  struct localedef_t *runp = locales;
+
+  while (runp != NULL && strcmp (name, runp->name) != 0)
+    runp = runp->next;
+
+  if (runp == NULL)
+    {
+      /* Add a new entry at the end.  */
+      struct localedef_t *newp = xcalloc (1, sizeof (struct localedef_t));
+      newp->name = name;
+      newp->repertoire_name = repertoire_name;
+
+      if (locales == NULL)
+	runp = locales = newp;
+      else
+	{
+	  runp = locales;
+	  while (runp->next != NULL)
+	    runp = runp->next;
+	  runp = runp->next = newp;
+	}
+    }
+
+  if ((runp->needed & (1 << locale)) != 0)
+    error (5, 0, _("circular dependencies between locale definitions"));
+
+  runp->needed |= 1 << locale;
+
+  return runp;
+}
+
+
+struct localedef_t *
+find_locale (int locale, const char *name, const char *repertoire_name,
+	     struct charmap_t *charmap)
+{
+  struct localedef_t *result = add_to_readlist (locale, name, repertoire_name);
+
+  if (locfile_read (result, charmap) != 0)
+    error (4, errno, _("cannot open locale definition file `%s'"),
+	   result->name);
+
+  return result;
+}