Fix memory leaks.
[kopensolaris-gnu/glibc.git] / locale / findlocale.c
index 5e87a33..308aa2b 100644 (file)
@@ -1,42 +1,32 @@
-/* Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
 
-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
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   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
+   published by the Free Software Foundation; either 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,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library 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
+   Library General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  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 Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 #include <locale.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
 
 #include "localeinfo.h"
 
 
 /* Constant data defined in setlocale.c.  */
-extern const struct locale_data *const _nl_C[];
-
-
-static inline char *
-copy (const char *string)
-{
-  size_t len;
-  char *new;
-  len = strlen (string) + 1;
-  new = (char *) malloc (len);
-  return new != NULL ? memcpy (new, string, len) : NULL;
-}
+extern struct locale_data *const _nl_C[];
 
 
 /* For each category we keep a list of records for the locale files
@@ -44,9 +34,9 @@ copy (const char *string)
 static struct loaded_l10nfile *locale_file_list[LC_ALL];
 
 
-const struct locale_data *
+struct locale_data *
 _nl_find_locale (const char *locale_path, size_t locale_path_len,
-                int category, char **name)
+                int category, const char **name)
 {
   int mask;
   /* Name of the locale for this category.  */
@@ -88,10 +78,10 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
   loc_name = (char *) _nl_expand_alias (*name);
   if (loc_name == NULL)
     /* It is no alias.  */
-    loc_name = *name;
+    loc_name = (char *) *name;
 
   /* Make a writable copy of the locale name.  */
-  loc_name = copy (loc_name);
+  loc_name = __strdup (loc_name);
 
   /* LOCALE can consist of up to four recognized parts for the XPG syntax:
 
@@ -99,7 +89,7 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
 
      and six parts for the CEN syntax:
 
-       language[_territory][+audience][+special][,sponsor][_revision]
+       language[_territory][+audience][+special][,[sponsor][_revision]]
 
      Beside the first all of them are allowed to be missing.  If the
      full specified locale is not found, the less specific one are
@@ -141,9 +131,9 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
        return NULL;
     }
   else
-    /* If the addressed locale is already available it should be freed.
-       If we would not do this switching back and force between two
-       locales would slowly eat up all memory.*/
+    /* If the addressed locale is already available it should be
+       freed.  If we would not do this switching back and force
+       between two locales would slowly eat up all memory.  */
     free ((void *) loc_name);
 
   if (locale_file->decided == 0)
@@ -170,23 +160,65 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
 
   /* Determine the locale name for which loading succeeded.  This
      information comes from the file name.  The form is
-     <path>/<locale>/LC_foo.  We must extract this <locale> part.  */
+     <path>/<locale>/LC_foo.  We must extract the <locale> part.  */
   if (((struct locale_data *) locale_file->data)->name == NULL)
     {
-      char *newp, *cp, *endp;
+      char *cp, *endp;
 
       endp = strrchr (locale_file->filename, '/');
       cp = endp - 1;
       while (cp[-1] != '/')
        --cp;
-      newp = (char *) malloc (endp - cp + 1);
-      if (newp == NULL)
-       return NULL;
-      memcpy (newp, cp, endp - cp);
-      newp[endp - cp] = '\0';
-      ((struct locale_data *) locale_file->data)->name = newp;
+      ((struct locale_data *) locale_file->data)->name = __strndup (cp,
+                                                                   endp - cp);
     }
   *name = (char *) ((struct locale_data *) locale_file->data)->name;
 
+  /* Increment the usage count.  */
+  if (((struct locale_data *) locale_file->data)->usage_count
+      != MAX_USAGE_COUNT)
+    ++((struct locale_data *) locale_file->data)->usage_count;
+
   return (struct locale_data *) locale_file->data;
 }
+
+
+/* Calling this function assumes the lock for handling global locale data
+   is acquired.  */
+void
+_nl_remove_locale (int locale, struct locale_data *data)
+{
+  if (--data->usage_count == 0)
+    {
+      /* First search the entry in the list of loaded files.  */
+      struct loaded_l10nfile *ptr = locale_file_list[locale];
+
+      /* Search for the entry.  It must be in the list.  Otherwise it
+        is a bug and we crash badly.  */
+      while ((struct locale_data *) ptr->data != data)
+       ptr = ptr->next;
+
+      /* Mark the data as not available anymore.  So when the data has
+        to be used again it is reloaded.  */
+      ptr->decided = 0;
+      ptr->data = NULL;
+
+      /* Really delete the data.  First delete the real data.  */
+      if (data->mmaped)
+       {
+         /* Try to unmap the area.  If this fails we mark the area as
+            permanent.  */
+         if (__munmap ((caddr_t) data->filedata, data->filesize) != 0)
+           {
+             data->usage_count = MAX_USAGE_COUNT;
+             return;
+           }
+       }
+      else
+       /* The memory was malloced.  */
+       free ((void *) data->filedata);
+
+      /* Now free the structure itself.  */
+      free (data);
+    }
+}