pivot-table: Use ctime_r() instead of ctime(), for thread safety.
[pspp] / src / output / pivot-table.c
index 0b4f0fb4bab85cb0a58348e86058dc6dee71ec35..72a158baaad78a777935077475e529bf01285bb2 100644 (file)
@@ -279,6 +279,13 @@ pivot_dimension_create__ (struct pivot_table *table,
     axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
   axis->dimensions[axis->n_dimensions++] = d;
 
+  if (axis_type == PIVOT_AXIS_LAYER)
+    {
+      free (table->current_layer);
+      table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
+                                      sizeof *table->current_layer);
+    }
+
   /* XXX extent and label_depth need to be calculated later. */
 
   return d;
@@ -293,6 +300,7 @@ pivot_dimension_destroy (struct pivot_dimension *d)
   pivot_category_destroy (d->root);
   free (d->data_leaves);
   free (d->presentation_leaves);
+  free (d);
 }
 
 /* Returns the first leaf node in an in-order traversal that is a child of
@@ -505,6 +513,7 @@ pivot_category_destroy (struct pivot_category *c)
   pivot_value_destroy (c->name);
   for (size_t i = 0; i < c->n_subs; i++)
     pivot_category_destroy (c->subs[i]);
+  free (c->subs);
   free (c);
 }
 \f
@@ -612,7 +621,8 @@ pivot_table_create (const char *title)
   return pivot_table_create__ (pivot_value_new_text (title));
 }
 
-/* Creates and returns a new pivot table with the given TITLE.
+/* Creates and returns a new pivot table with the given TITLE, and takes
+   ownership of TITLE.
 
    Operations commonly performed on the new pivot_table:
 
@@ -810,7 +820,7 @@ pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
 }
 
 static bool
-equal_indexes (const size_t *a, const size_t *b, size_t n)
+equal_indexes (const size_t *a, const unsigned int *b, size_t n)
 {
   for (size_t i = 0; i < n; i++)
     if (a[i] != b[i])
@@ -1268,7 +1278,7 @@ void
 pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
 {
   indent (indentation);
-  printf ("%s dimension %zu (where 0=innermost), label_depth=%zu:\n",
+  printf ("%s dimension %zu (where 0=innermost), label_depth=%d:\n",
           pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
 
   pivot_category_dump (d->root, indentation + 1);
@@ -1342,6 +1352,18 @@ compose_headings (const struct pivot_axis *axis,
   return headings;
 }
 
+static void
+free_headings (const struct pivot_axis *axis, char ***headings)
+{
+  for (size_t i = 0; i < axis->label_depth; i++)
+    {
+      for (size_t j = 0; j < axis->extent; j++)
+        free (headings[i][j]);
+      free (headings[i]);
+    }
+  free (headings);
+}
+
 void
 pivot_table_dump (const struct pivot_table *table, int indentation)
 {
@@ -1361,7 +1383,8 @@ pivot_table_dump (const struct pivot_table *table, int indentation)
   if (table->date)
     {
       indent (indentation);
-      printf ("date: %s", ctime (&table->date)); /* XXX thread unsafe */
+      char buf[26];
+      printf ("date: %s", ctime_r (&table->date, buf));
     }
 
   indent (indentation);
@@ -1460,6 +1483,7 @@ pivot_table_dump (const struct pivot_table *table, int indentation)
             }
           putchar ('\n');
         }
+      free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
 
       indent (indentation + 1);
       printf ("-----------------------------------------------\n");
@@ -1508,6 +1532,7 @@ pivot_table_dump (const struct pivot_table *table, int indentation)
 
       free (column_enumeration);
       free (row_enumeration);
+      free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
     }
 
   pivot_table_dump_value (table->caption, "caption", indentation);
@@ -1520,12 +1545,13 @@ pivot_table_dump (const struct pivot_table *table, int indentation)
       if (f->marker)
         pivot_value_dump (f->marker);
       else
-        printf ("%d", f->idx);
+        printf ("%zu", f->idx);
       putchar (']');
       pivot_value_dump (f->content);
       putchar ('\n');
     }
 
+  free (dindexes);
   settings_set_decimal_char (old_decimal);
 }
 \f
@@ -1789,9 +1815,10 @@ pivot_value_destroy (struct pivot_value *value)
       font_style_uninit (value->font_style);
       free (value->font_style);
       free (value->cell_style);
-      for (size_t i = 0; i < value->n_footnotes; i++)
-        pivot_footnote_destroy (value->footnotes[i]);
+      /* Do not free the elements of footnotes because VALUE does not own
+         them. */
       free (value->footnotes);
+      free (value->subscript);
 
       switch (value->type)
         {
@@ -1800,7 +1827,8 @@ pivot_value_destroy (struct pivot_value *value)
           free (value->numeric.value_label);
           break;
 
-        case SETTINGS_VALUE_SHOW_VALUE:
+        case PIVOT_VALUE_STRING:
+          free (value->string.s);
           free (value->string.var_name);
           free (value->string.value_label);
           break;
@@ -1873,6 +1901,14 @@ pivot_argument_uninit (struct pivot_argument *arg)
     }
 }
 
+/* Creates and returns a new pivot_value whose contents is the null-terminated
+   string TEXT.  Takes ownership of TEXT.
+
+   This function is for text strings provided by the user (with the exception
+   that pivot_value_new_variable() should be used for variable names).  For
+   strings that are part of the PSPP user interface, such as names of
+   procedures, statistics, annotations, error messages, etc., use
+   pivot_value_new_text(). */
 struct pivot_value *
 pivot_value_new_user_text_nocopy (char *text)
 {
@@ -1889,6 +1925,17 @@ pivot_value_new_user_text_nocopy (char *text)
   return value;
 }
 
+/* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
+   TEXT.  Use SIZE_MAX if TEXT is null-teriminated and its length is not known
+   in advance.
+
+   This function is for text strings provided by the user (with the exception
+   that pivot_value_new_variable() should be used for variable names).  For
+   strings that are part of the PSPP user interface, such as names of
+   procedures, statistics, annotations, error messages, etc., use
+   pivot_value_new_text().j
+
+   The caller retains ownership of TEXT.*/
 struct pivot_value *
 pivot_value_new_user_text (const char *text, size_t length)
 {
@@ -1896,8 +1943,12 @@ pivot_value_new_user_text (const char *text, size_t length)
     xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
 }
 
-/* TEXT should be a translatable string, but not actually translated yet,
-   e.g. enclosed in N_(). */
+/* Creates and returns new pivot_value whose contents is TEXT, which should be
+   a translatable string, but not actually translated yet, e.g. enclosed in
+   N_().  This function is for text strings that are part of the PSPP user
+   interface, such as names of procedures, statistics, annotations, error
+   messages, etc.  For strings that come from the user, use
+   pivot_value_new_user_text(). */
 struct pivot_value *
 pivot_value_new_text (const char *text)
 {
@@ -1917,8 +1968,8 @@ pivot_value_new_text (const char *text)
   return value;
 }
 
-/* FORMAT should be a translatable string, but not actually translated yet,
-   e.g. enclosed in N_(). */
+/* Same as pivot_value_new_text() but its argument is a printf()-like format
+   string. */
 struct pivot_value * PRINTF_FORMAT (1, 2)
 pivot_value_new_text_format (const char *format, ...)
 {
@@ -2014,8 +2065,7 @@ pivot_value_new_value (const union value *value, int width,
   struct pivot_value *pv = xzalloc (sizeof *pv);
   if (width > 0)
     {
-      char *s = recode_string (UTF8, encoding,
-                               CHAR_CAST (char *, value_str (value, width)),
+      char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
                                width);
       size_t n = strlen (s);
       while (n > 0 && s[n - 1] == ' ')
@@ -2053,7 +2103,7 @@ pivot_value_new_variable (const struct variable *variable)
 /* Attaches a reference to FOOTNOTE to V. */
 void
 pivot_value_add_footnote (struct pivot_value *v,
-                          struct pivot_footnote *footnote)
+                          const struct pivot_footnote *footnote)
 {
   v->footnotes = xrealloc (v->footnotes,
                            (v->n_footnotes + 1) * sizeof *v->footnotes);
@@ -2063,7 +2113,7 @@ pivot_value_add_footnote (struct pivot_value *v,
 /* If VALUE is a numeric value, and RC is a result class such as
    PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
 void
-pivot_value_set_rc (struct pivot_table *table, struct pivot_value *value,
+pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
                     const char *rc)
 {
   if (value->type == PIVOT_VALUE_NUMERIC)