work on memory leaks
[pspp] / src / language / stats / ctables.c
index 3b7dc24d1051daded14b47a9fc25fc6f6c42263f..4b4d58d8a9add8c1e79a41b909c28449ad8b67ba 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;
@@ -1536,13 +1540,20 @@ 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]);
+    }
+
   free (t->caption);
   free (t->corner);
   free (t->title);
@@ -1557,6 +1568,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 +1890,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 +1963,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
@@ -4261,7 +4273,6 @@ ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx,
       }
 
     case CTPO_CAT_NUMBER:
-    case CTPO_CAT_STRING:
     case CTPO_CAT_MISSING:
     case CTPO_CAT_OTHERNM:
     case CTPO_CAT_SUBTOTAL:
@@ -4275,6 +4286,25 @@ ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx,
         return ctables_pcexpr_evaluate_category (ctx, &cv);
       }
 
+    case CTPO_CAT_STRING:
+      {
+        int width = var_get_width (ctx->section->nests[ctx->pc_a]->vars[ctx->pc_a_idx]);
+        char *s = NULL;
+        if (width > e->string.length)
+          {
+            s = xmalloc (width);
+            buf_copy_rpad (s, width, e->string.string, e->string.length, ' ');
+          }
+        struct ctables_cell_value cv = {
+          .category = ctables_find_category_for_postcompute (ctx->section->table->ctables->dict, ctx->cats, ctx->parse_format, e),
+          .value = { .s = CHAR_CAST (uint8_t *, s ? s : e->string.string) },
+        };
+        assert (cv.category != NULL);
+        double retval = ctables_pcexpr_evaluate_category (ctx, &cv);
+        free (s);
+        return retval;
+      }
+
     case CTPO_ADD:
       return ctables_pcexpr_evaluate_nonterminal (ctx, e, 2, ctpo_add);
 
@@ -4634,6 +4664,8 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
             }
           free (sorted);
           free (groups);
+          free (levels);
+          free (sections);
         }
     }
 
@@ -5317,6 +5349,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)
 {
@@ -5556,6 +5605,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)
 {
@@ -5592,10 +5650,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))
         {
@@ -5619,12 +5689,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
         {
@@ -5636,6 +5722,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;
         }
     }