work on memory leaks
[pspp] / src / language / stats / ctables.c
index a69e8d56593a035aad6e6fba5c249681a8c45387..dd97afc0cc97e3c56adffc9a643ae60a8e831406 100644 (file)
@@ -445,6 +445,8 @@ struct ctables_stack
     size_t n;
   };
 
+static void ctables_stack_uninit (struct ctables_stack *);
+
 struct ctables_value
   {
     struct hmap_node node;
@@ -470,6 +472,8 @@ struct ctables_section
     struct hmap domains[N_CTDTS]; /* Contains "struct ctables_domain"s. */
   };
 
+static void ctables_section_uninit (struct ctables_section *);
+
 struct ctables_table
   {
     struct ctables *ctables;
@@ -611,6 +615,7 @@ ctables_category_uninit (struct ctables_category *cat)
   if (!cat)
     return;
 
+  msg_location_destroy (cat->location);
   switch (cat->type)
     {
     case CCT_NUMBER:
@@ -1536,13 +1541,32 @@ ctables_table_destroy (struct ctables_table *t)
   if (!t)
     return;
 
+  for (size_t i = 0; i < t->n_sections; i++)
+    ctables_section_uninit (&t->sections[i]);
+  free (t->sections);
+
   for (size_t i = 0; i < t->n_categories; i++)
     ctables_categories_unref (t->categories[i]);
   free (t->categories);
 
-  ctables_axis_destroy (t->axes[PIVOT_AXIS_COLUMN]);
-  ctables_axis_destroy (t->axes[PIVOT_AXIS_ROW]);
-  ctables_axis_destroy (t->axes[PIVOT_AXIS_LAYER]);
+  for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
+    {
+      ctables_axis_destroy (t->axes[a]);
+      ctables_stack_uninit (&t->stacks[a]);
+    }
+
+  struct ctables_value *ctv, *next_ctv;
+  HMAP_FOR_EACH_SAFE (ctv, next_ctv, struct ctables_value, node,
+                      &t->clabels_values_map)
+    {
+      value_destroy (&ctv->value, var_get_width (t->clabels_example));
+      hmap_delete (&t->clabels_values_map, &ctv->node);
+      free (ctv);
+    }
+  hmap_destroy (&t->clabels_values_map);
+  free (t->clabels_values);
+
+  free (t->sum_vars);
   free (t->caption);
   free (t->corner);
   free (t->title);
@@ -1557,6 +1581,7 @@ ctables_destroy (struct ctables *ct)
   if (!ct)
     return;
 
+  fmt_settings_uninit (&ct->ctables_formats);
   pivot_table_look_unref (ct->look);
   free (ct->zero);
   free (ct->missing);
@@ -1878,6 +1903,7 @@ ctables_recursive_check_postcompute (struct dictionary *dict,
     case CTPO_CAT_NUMBER:
     case CTPO_CAT_STRING:
     case CTPO_CAT_NRANGE:
+    case CTPO_CAT_SRANGE:
     case CTPO_CAT_MISSING:
     case CTPO_CAT_OTHERNM:
     case CTPO_CAT_SUBTOTAL:
@@ -1950,10 +1976,9 @@ ctables_recursive_check_postcompute (struct dictionary *dict,
               dict, e->subs[i], pc_cat, cats, cats_location))
           return false;
       return true;
-
-    default:
-      NOT_REACHED ();
     }
+
+  NOT_REACHED ();
 }
 
 static bool
@@ -2025,7 +2050,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
           int start_ofs = lex_ofs (lexer);
           struct ctables_category *cat = &c->cats[c->n_cats];
           if (!ctables_table_parse_explicit_category (lexer, dict, ct, cat))
-            return false;
+            goto error;
           cat->location = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1);
           c->n_cats++;
 
@@ -2055,7 +2080,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
           else
             {
               lex_error_expecting (lexer, "A", "D");
-              return false;
+              goto error;
             }
         }
       else if (!c->n_cats && lex_match_id (lexer, "KEY"))
@@ -2069,31 +2094,31 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
             {
               cat.type = CCT_FUNCTION;
               if (!parse_ctables_summary_function (lexer, &cat.sort_function))
-                return false;
+                goto error;
 
               if (lex_match (lexer, T_LPAREN))
                 {
                   cat.sort_var = parse_variable (lexer, dict);
                   if (!cat.sort_var)
-                    return false;
+                    goto error;
 
                   if (cat.sort_function == CTSF_PTILE)
                     {
                       lex_match (lexer, T_COMMA);
                       if (!lex_force_num_range_closed (lexer, "PTILE", 0, 100))
-                        return false;
+                        goto error;
                       cat.percentile = lex_number (lexer);
                       lex_get (lexer);
                     }
 
                   if (!lex_force_match (lexer, T_RPAREN))
-                    return false;
+                    goto error;
                 }
               else if (ctables_function_availability (cat.sort_function)
                        == CTFA_SCALE)
                 {
                   bool UNUSED b = lex_force_match (lexer, T_LPAREN);
-                  return false;
+                  goto error;
                 }
             }
         }
@@ -2107,20 +2132,20 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
           else
             {
               lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
-              return false;
+              goto error;
             }
         }
       else if (lex_match_id (lexer, "TOTAL"))
         {
           lex_match (lexer, T_EQUALS);
           if (!parse_bool (lexer, &show_totals))
-            return false;
+            goto error;
         }
       else if (lex_match_id (lexer, "LABEL"))
         {
           lex_match (lexer, T_EQUALS);
           if (!lex_force_string (lexer))
-            return false;
+            goto error;
           free (total_label);
           total_label = ss_xstrdup (lex_tokss (lexer));
           lex_get (lexer);
@@ -2135,7 +2160,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
           else
             {
               lex_error_expecting (lexer, "BEFORE", "AFTER");
-              return false;
+              goto error;
             }
         }
       else if (lex_match_id (lexer, "EMPTY"))
@@ -2148,7 +2173,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
           else
             {
               lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
-              return false;
+              goto error;
             }
         }
       else
@@ -2158,7 +2183,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
                                  "TOTAL", "LABEL", "POSITION", "EMPTY");
           else
             lex_error_expecting (lexer, "TOTAL", "LABEL", "POSITION", "EMPTY");
-          return false;
+          goto error;
         }
     }
 
@@ -2225,8 +2250,6 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
 
   if (cats_start_ofs != -1)
     {
-      struct msg_location *cats_location
-        = lex_ofs_location (lexer, cats_start_ofs, cats_end_ofs);
       for (size_t i = 0; i < c->n_cats; i++)
         {
           struct ctables_category *cat = &c->cats[i];
@@ -2234,9 +2257,13 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
             {
             case CCT_POSTCOMPUTE:
               cat->parse_format = parse_strings ? common_format->type : FMT_F;
-              if (!ctables_recursive_check_postcompute (dict, cat->pc->expr,
-                                                        cat, c, cats_location))
-                return false;
+              struct msg_location *cats_location
+                = lex_ofs_location (lexer, cats_start_ofs, cats_end_ofs);
+              bool ok = ctables_recursive_check_postcompute (
+                dict, cat->pc->expr, cat, c, cats_location);
+              msg_location_destroy (cats_location);
+              if (!ok)
+                goto error;
               break;
 
             case CCT_NUMBER:
@@ -2250,7 +2277,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
                               "subcommand tries to apply it to string "
                               "variable %s."),
                             var_get_name (vars[j]));
-                    return false;
+                    goto error;
                   }
               break;
 
@@ -2260,7 +2287,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
                   double n;
                   if (!parse_category_string (cat->location, cat->string, dict,
                                               common_format->type, &n))
-                    return false;
+                    goto error;
 
                   ss_dealloc (&cat->string);
 
@@ -2268,7 +2295,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
                   cat->number = n;
                 }
               else if (!all_strings (vars, n_vars, cat))
-                return false;
+                goto error;
               break;
 
             case CCT_SRANGE:
@@ -2281,14 +2308,14 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
                   else if (!parse_category_string (cat->location,
                                                    cat->srange[0], dict,
                                                    common_format->type, &n[0]))
-                    return false;
+                    goto error;
 
                   if (!cat->srange[1].string)
                     n[1] = DBL_MAX;
                   else if (!parse_category_string (cat->location,
                                                    cat->srange[1], dict,
                                                    common_format->type, &n[1]))
-                    return false;
+                    goto error;
 
                   ss_dealloc (&cat->srange[0]);
                   ss_dealloc (&cat->srange[1]);
@@ -2298,7 +2325,7 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
                   cat->nrange[1] = n[1];
                 }
               else if (!all_strings (vars, n_vars, cat))
-                return false;
+                goto error;
               break;
 
             case CCT_MISSING:
@@ -2314,7 +2341,12 @@ ctables_table_parse_categories (struct lexer *lexer, struct dictionary *dict,
         }
     }
 
+  free (vars);
   return true;
+
+error:
+  free (vars);
+  return false;
 }
 
 static void
@@ -4652,6 +4684,8 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
             }
           free (sorted);
           free (groups);
+          free (levels);
+          free (sections);
         }
     }
 
@@ -5335,6 +5369,23 @@ ctables_section_clear (struct ctables_section *s)
     }
 }
 
+static void
+ctables_section_uninit (struct ctables_section *s)
+{
+  ctables_section_clear (s);
+
+  for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
+    {
+      for (size_t i = 0; i < s->nests[a]->n; i++)
+        hmap_destroy (&s->occurrences[a][i]);
+      free (s->occurrences[a]);
+    }
+
+  hmap_destroy (&s->cells);
+  for (size_t i = 0; i < N_CTDTS; i++)
+    hmap_destroy (&s->domains[i]);
+}
+
 static void
 ctables_table_clear (struct ctables_table *t)
 {
@@ -5574,6 +5625,15 @@ ctpo_cat_nrange (double low, double high)
   };
 }
 
+static struct ctables_pcexpr
+ctpo_cat_srange (struct substring low, struct substring high)
+{
+  return (struct ctables_pcexpr) {
+    .op = CTPO_CAT_SRANGE,
+    .srange = { low, high },
+  };
+}
+
 static struct ctables_pcexpr *
 ctable_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict)
 {
@@ -5610,10 +5670,22 @@ ctable_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict)
     {
       if (lex_match_id (lexer, "LO"))
         {
-          if (!lex_force_match_id (lexer, "THRU") || !lex_force_num (lexer))
+          if (!lex_force_match_id (lexer, "THRU"))
             return false;
-          e = ctpo_cat_nrange (-DBL_MAX, lex_number (lexer));
-          lex_get (lexer);
+
+          if (lex_is_string (lexer))
+            {
+              struct substring low = { .string = NULL };
+              struct substring high = parse_substring (lexer, dict);
+              e = ctpo_cat_srange (low, high);
+            }
+          else
+            {
+              if (!lex_force_num (lexer))
+                return false;
+              e = ctpo_cat_nrange (-DBL_MAX, lex_number (lexer));
+              lex_get (lexer);
+            }
         }
       else if (lex_is_number (lexer))
         {
@@ -5637,12 +5709,28 @@ ctable_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict)
         }
       else if (lex_is_string (lexer))
         {
-          struct substring s = recode_substring_pool (
-            dict_get_encoding (dict), "UTF-8", lex_tokss (lexer), NULL);
-          ss_rtrim (&s, ss_cstr (" "));
+          struct substring s = parse_substring (lexer, dict);
 
-          e = (struct ctables_pcexpr) { .op = CTPO_CAT_STRING, .string = s };
-          lex_get (lexer);
+          if (lex_match_id (lexer, "THRU"))
+            {
+              struct substring high;
+
+              if (lex_match_id (lexer, "HI"))
+                high = (struct substring) { .string = NULL };
+              else
+                {
+                  if (!lex_force_string (lexer))
+                    {
+                      ss_dealloc (&s);
+                      return false;
+                    }
+                  high = parse_substring (lexer, dict);
+                }
+
+              e = ctpo_cat_srange (s, high);
+            }
+          else
+            e = (struct ctables_pcexpr) { .op = CTPO_CAT_STRING, .string = s };
         }
       else
         {
@@ -5654,6 +5742,11 @@ ctable_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict)
         {
           if (e.op == CTPO_CAT_STRING)
             ss_dealloc (&e.string);
+          else if (e.op == CTPO_CAT_SRANGE)
+            {
+              ss_dealloc (&e.srange[0]);
+              ss_dealloc (&e.srange[1]);
+            }
           return NULL;
         }
     }