treewide: Replace <name>_cnt by n_<name>s and <name>_cap by allocated_<name>.
[pspp] / src / data / short-names.c
index 3ed99c04c2417792696f2eafe72351fb571f47f7..ff6b4ff7739d0793a6f2b4c8bbb314b21281a7d7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2010, 2011, 2014 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
 
 #include <config.h>
 
-#include <data/short-names.h>
+#include "data/short-names.h"
 
-#include <data/dictionary.h>
-#include <data/sys-file-private.h>
-#include <data/variable.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/hash.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/dictionary.h"
+#include "data/sys-file-private.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+#include "libpspp/stringi-set.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* Compares two strings. */
-static int
-compare_strings (const void *a, const void *b, const void *aux UNUSED)
-{
-  return strcmp (a, b);
-}
-
-/* Hashes a string. */
-static unsigned
-hash_string (const void *s, const void *aux UNUSED)
-{
-  return hsh_hash_string (s);
-}
-
-/* Sets V's short name to BASE, followed by a suffix of the form
-   _A, _B, _C, ..., _AA, _AB, etc. according to the value of
-   SUFFIX_NUMBER.  Truncates BASE as necessary to fit. */
-static void
-set_var_short_name_suffix (struct variable *v, size_t i,
-                           const char *base, int suffix_number)
-{
-  char suffix[SHORT_NAME_LEN + 1];
-  char short_name[SHORT_NAME_LEN + 1];
-  char *start, *end;
-  int len, ofs;
-
-  assert (suffix_number >= 0);
-
-  /* Set base name. */
-  var_set_short_name (v, i, base);
-
-  /* Compose suffix. */
-  start = end = suffix + sizeof suffix - 1;
-  *end = '\0';
-  do
-    {
-      *--start = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[suffix_number % 26];
-      if (start <= suffix + 1)
-        msg (SE, _("Variable suffix too large."));
-      suffix_number /= 26;
-    }
-  while (suffix_number > 0);
-  *--start = '_';
-
-  /* Append suffix to V's short name. */
-  str_copy_trunc (short_name, sizeof short_name, base);
-  len = end - start;
-  if (len + strlen (short_name) > SHORT_NAME_LEN)
-    ofs = SHORT_NAME_LEN - len;
-  else
-    ofs = strlen (short_name);
-  strcpy (short_name + ofs, start);
-
-  /* Set name. */
-  var_set_short_name (v, i, short_name);
-}
-
 static void
-claim_short_name (struct variable *v, size_t i, struct hsh_table *short_names)
+claim_short_name (struct variable *v, size_t i,
+                  struct stringi_set *short_names)
 {
   const char *short_name = var_get_short_name (v, i);
-  if (short_name != NULL
-      && hsh_insert (short_names, (char *) short_name) != NULL)
+  if (short_name != NULL && !stringi_set_insert (short_names, short_name))
     var_set_short_name (v, i, NULL);
 }
 
 /* Form initial short_name from the variable name, then try _A,
    _B, ... _AA, _AB, etc., if needed. */
 static void
-assign_short_name (struct variable *v, size_t i, struct hsh_table *short_names)
+assign_short_name (struct variable *v, size_t i,
+                   struct stringi_set *short_names)
 {
   int trial;
 
@@ -108,13 +53,28 @@ assign_short_name (struct variable *v, size_t i, struct hsh_table *short_names)
 
   for (trial = 0; ; trial++)
     {
+      char suffix[SHORT_NAME_LEN + 1];
+      char *short_name;
+
+      /* Compose suffix. */
       if (trial == 0)
-        var_set_short_name (v, i, var_get_name (v));
+        suffix[0] = '\0';
       else
-        set_var_short_name_suffix (v, i, var_get_name (v), trial - 1);
+        {
+          suffix[0] = '_';
+          str_format_26adic (trial, true, &suffix[1], sizeof suffix - 1);
+        }
 
-      if (hsh_insert (short_names, (char *) var_get_short_name (v, i)) == NULL)
-        break;
+      /* Set name. */
+      short_name = utf8_encoding_concat (var_get_name (v), suffix,
+                                         var_get_encoding (v), SHORT_NAME_LEN);
+      if (stringi_set_insert (short_names, short_name))
+        {
+          var_set_short_name (v, i, short_name);
+          free (short_name);
+          return;
+        }
+      free (short_name);
     }
 }
 
@@ -129,23 +89,17 @@ assign_short_name (struct variable *v, size_t i, struct hsh_table *short_names)
 void
 short_names_assign (struct dictionary *d)
 {
-  size_t var_cnt = dict_get_var_cnt (d);
-  struct hsh_table *short_names;
-  size_t i, j;
+  size_t n_vars = dict_get_n_vars (d);
+  struct stringi_set short_names;
 
-  /* Create hash used for detecting conflicts.  The entries in
-     the hash table point to strings owned by dictionary
-     variables, not by us, so we don't need to provide a free
-     function. */
-  short_names = hsh_create (var_cnt, compare_strings, hash_string,
-                            NULL, NULL);
+  stringi_set_init (&short_names);
 
   /* Clear short names that conflict with a variable name. */
-  for (i = 0; i < var_cnt; i++)
+  for (size_t i = 0; i < n_vars; i++)
     {
       struct variable *v = dict_get_var (d, i);
-      int segment_cnt = sfm_width_to_segments (var_get_width (v));
-      for (j = 0; j < segment_cnt; j++)
+      int n_segments = sfm_width_to_segments (var_get_width (v));
+      for (size_t j = 0; j < n_segments; j++)
         {
           const char *name = var_get_short_name (v, j);
           if (name != NULL)
@@ -159,11 +113,13 @@ short_names_assign (struct dictionary *d)
 
   /* Give variables whose names are short the corresponding short
      name. */
-  for (i = 0; i < var_cnt; i++)
+  for (size_t i = 0; i < n_vars; i++)
     {
       struct variable *v = dict_get_var (d, i);
-      if (strlen (var_get_name (v)) <= SHORT_NAME_LEN)
-        var_set_short_name (v, 0, var_get_name (v));
+      const char *name = var_get_name (v);
+      int len = recode_string_len (var_get_encoding (v), "UTF-8", name, -1);
+      if (len <= SHORT_NAME_LEN)
+        var_set_short_name (v, 0, name);
     }
 
   /* Each variable with an assigned short name for its first
@@ -171,34 +127,33 @@ short_names_assign (struct dictionary *d)
      conflict, the claimant earlier in dictionary order wins.
      Then similarly for additional segments of very long
      strings. */
-  for (i = 0; i < var_cnt; i++)
+  for (size_t i = 0; i < n_vars; i++)
     {
       struct variable *v = dict_get_var (d, i);
-      claim_short_name (v, 0, short_names);
+      claim_short_name (v, 0, &short_names);
     }
-  for (i = 0; i < var_cnt; i++)
+  for (size_t i = 0; i < n_vars; i++)
     {
       struct variable *v = dict_get_var (d, i);
-      int segment_cnt = sfm_width_to_segments (var_get_width (v));
-      for (j = 1; j < segment_cnt; j++)
-        claim_short_name (v, i, short_names);
+      int n_segments = sfm_width_to_segments (var_get_width (v));
+      for (size_t j = 1; j < n_segments; j++)
+        claim_short_name (v, j, &short_names);
     }
 
   /* Assign short names to first segment of remaining variables,
      then similarly for additional segments. */
-  for (i = 0; i < var_cnt; i++)
+  for (size_t i = 0; i < n_vars; i++)
     {
       struct variable *v = dict_get_var (d, i);
-      assign_short_name (v, 0, short_names);
+      assign_short_name (v, 0, &short_names);
     }
-  for (i = 0; i < var_cnt; i++)
+  for (size_t i = 0; i < n_vars; i++)
     {
       struct variable *v = dict_get_var (d, i);
-      int segment_cnt = sfm_width_to_segments (var_get_width (v));
-      for (j = 1; j < segment_cnt; j++)
-        assign_short_name (v, j, short_names);
+      int n_segments = sfm_width_to_segments (var_get_width (v));
+      for (size_t j = 1; j < n_segments; j++)
+        assign_short_name (v, j, &short_names);
     }
 
-  /* Get rid of hash table. */
-  hsh_destroy (short_names);
+  stringi_set_destroy (&short_names);
 }