Use UTF-8 case-insensitive hashes and comparisons for language identifiers.
[pspp] / src / data / dictionary.c
index c8f58516ecc79d1d6a7bc78a29353f838745634c..d36f8c519f5f31437be7f70418f78ae99ce8ed9a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
 
    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
@@ -87,6 +87,8 @@ struct dictionary
 static void dict_unset_split_var (struct dictionary *, struct variable *);
 static void dict_unset_mrset_var (struct dictionary *, struct variable *);
 
+/* Returns the encoding for data in dictionary D.  The return value is a
+   nonnull string that contains an IANA character set name. */
 const char *
 dict_get_encoding (const struct dictionary *d)
 {
@@ -181,7 +183,9 @@ dict_create (const char *encoding)
    dictionary.  If the new dictionary won't be used to access
    cases produced with the old dictionary, then the new
    dictionary's case indexes should be compacted with
-   dict_compact_values to save space. */
+   dict_compact_values to save space.
+
+   Callbacks are not cloned. */
 struct dictionary *
 dict_clone (const struct dictionary *s)
 {
@@ -190,11 +194,6 @@ dict_clone (const struct dictionary *s)
 
   d = dict_create (s->encoding);
 
-  /* Set the new dictionary's encoding early so that string length limitations
-     are interpreted correctly. */
-  if ( s->encoding)
-    d->encoding = xstrdup (s->encoding);
-
   for (i = 0; i < s->var_cnt; i++)
     {
       struct variable *sv = s->var[i].var;
@@ -302,6 +301,7 @@ dict_destroy (struct dictionary *d)
       d->callbacks  = NULL ;
 
       dict_clear (d);
+      string_array_destroy (&d->documents);
       hmap_destroy (&d->name_map);
       attrset_destroy (&d->attributes);
       dict_clear_mrsets (d);
@@ -397,7 +397,7 @@ add_var (struct dictionary *d, struct variable *v)
   vardict->dict = d;
   vardict->var = v;
   hmap_insert (&d->name_map, &vardict->name_node,
-               hash_case_string (var_get_name (v), 0));
+               utf8_hash_case_string (var_get_name (v), 0));
   vardict->case_index = d->next_value_idx;
   var_set_vardict (v, vardict);
 
@@ -487,10 +487,10 @@ dict_lookup_var (const struct dictionary *d, const char *name)
   struct vardict_info *vardict;
 
   HMAP_FOR_EACH_WITH_HASH (vardict, struct vardict_info, name_node,
-                           hash_case_string (name, 0), &d->name_map)
+                           utf8_hash_case_string (name, 0), &d->name_map)
     {
       struct variable *var = vardict->var;
-      if (!strcasecmp (var_get_name (var), name))
+      if (!utf8_strcasecmp (var_get_name (var), name))
         return var;
     }
 
@@ -597,7 +597,6 @@ dict_delete_var (struct dictionary *d, struct variable *v)
 {
   int dict_index = var_get_dict_index (v);
   const int case_index = var_get_case_index (v);
-  const int width = var_get_width (v);
 
   assert (dict_contains_var (d, v));
 
@@ -625,13 +624,14 @@ dict_delete_var (struct dictionary *d, struct variable *v)
 
   /* Free memory. */
   var_clear_vardict (v);
-  var_destroy (v);
 
   if ( d->changed ) d->changed (d, d->changed_data);
 
   invalidate_proto (d);
   if (d->callbacks &&  d->callbacks->var_deleted )
-    d->callbacks->var_deleted (d, dict_index, case_index, width, d->cb_data);
+    d->callbacks->var_deleted (d, v, dict_index, case_index, d->cb_data);
+
+  var_destroy (v);
 }
 
 /* Deletes the COUNT variables listed in VARS from D.  This is
@@ -742,7 +742,7 @@ rename_var (struct variable *v, const char *new_name)
   struct vardict_info *vardict = var_get_vardict (v);
   var_clear_vardict (v);
   var_set_name (v, new_name);
-  vardict->name_node.hash = hash_case_string (new_name, 0);
+  vardict->name_node.hash = utf8_hash_case_string (new_name, 0);
   var_set_vardict (v, vardict);
 }
 
@@ -753,7 +753,7 @@ void
 dict_rename_var (struct dictionary *d, struct variable *v,
                  const char *new_name)
 {
-  assert (!strcasecmp (var_get_name (v), new_name)
+  assert (!utf8_strcasecmp (var_get_name (v), new_name)
           || dict_lookup_var (d, new_name) == NULL);
 
   unindex_var (d, var_get_vardict (v));
@@ -1247,15 +1247,18 @@ dict_get_label (const struct dictionary *d)
   return d->label;
 }
 
-/* Sets D's file label to LABEL, truncating it to a maximum of 60
-   characters.
+/* Sets D's file label to LABEL, truncating it to at most 60 bytes in D's
+   encoding.
 
    Removes D's label if LABEL is null or the empty string. */
 void
 dict_set_label (struct dictionary *d, const char *label)
 {
   free (d->label);
-  d->label = label != NULL && label[0] != '\0' ? xstrndup (label, 60) : NULL;
+  if (label == NULL || label[0] == '\0')
+    d->label = NULL;
+  else
+    d->label = utf8_encoding_trunc (label, d->encoding, 60);
 }
 
 /* Returns the documents for D, as an UTF-8 encoded string_array.  The
@@ -1408,7 +1411,7 @@ dict_lookup_vector (const struct dictionary *d, const char *name)
 {
   size_t i;
   for (i = 0; i < d->vector_cnt; i++)
-    if (!strcasecmp (vector_get_name (d->vector[i]), name))
+    if (!utf8_strcasecmp (vector_get_name (d->vector[i]), name))
       return d->vector[i];
   return NULL;
 }
@@ -1453,7 +1456,7 @@ dict_lookup_mrset_idx (const struct dictionary *dict, const char *name)
   size_t i;
 
   for (i = 0; i < dict->n_mrsets; i++)
-    if (!strcasecmp (name, dict->mrsets[i]->name))
+    if (!utf8_strcasecmp (name, dict->mrsets[i]->name))
       return i;
 
   return SIZE_MAX;