size_t n;
};
+static void ctables_stack_uninit (struct ctables_stack *);
+
struct ctables_value
{
struct hmap_node node;
struct hmap domains[N_CTDTS]; /* Contains "struct ctables_domain"s. */
};
+static void ctables_section_uninit (struct ctables_section *);
+
struct ctables_table
{
struct ctables *ctables;
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);
if (!ct)
return;
+ fmt_settings_uninit (&ct->ctables_formats);
pivot_table_look_unref (ct->look);
free (ct->zero);
free (ct->missing);
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:
dict, e->subs[i], pc_cat, cats, cats_location))
return false;
return true;
-
- default:
- NOT_REACHED ();
}
+
+ NOT_REACHED ();
}
static bool
}
case CTPO_CAT_NUMBER:
- case CTPO_CAT_STRING:
case CTPO_CAT_MISSING:
case CTPO_CAT_OTHERNM:
case CTPO_CAT_SUBTOTAL:
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);
}
free (sorted);
free (groups);
+ free (levels);
+ free (sections);
}
}
}
}
+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)
{
};
}
+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)
{
{
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))
{
}
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
{
{
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;
}
}