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 (!cat)
return;
+ msg_location_destroy (cat->location);
switch (cat->type)
{
case CCT_NUMBER:
ctables_summary_spec_set_clone (struct ctables_summary_spec_set *dst,
const struct ctables_summary_spec_set *src)
{
- struct ctables_summary_spec *specs = xnmalloc (src->n, sizeof *specs);
+ struct ctables_summary_spec *specs
+ = (src->n ? xnmalloc (src->n, sizeof *specs) : NULL);
for (size_t i = 0; i < src->n; i++)
ctables_summary_spec_clone (&specs[i], &src->specs[i]);
{
for (size_t i = 0; i < set->n; i++)
ctables_summary_spec_uninit (&set->specs[i]);
+ free (set->listwise_vars);
free (set->specs);
}
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->summary_specs.specs);
+
+ 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);
if (!ct)
return;
+ struct ctables_postcompute *pc, *next_pc;
+ HMAP_FOR_EACH_SAFE (pc, next_pc, struct ctables_postcompute, hmap_node,
+ &ct->postcomputes)
+ {
+ free (pc->name);
+ msg_location_destroy (pc->location);
+ ctables_pcexpr_destroy (pc->expr);
+ free (pc->label);
+ if (pc->specs)
+ {
+ ctables_summary_spec_set_uninit (pc->specs);
+ free (pc->specs);
+ }
+ hmap_delete (&ct->postcomputes, &pc->hmap_node);
+ free (pc);
+ }
+
+ fmt_settings_uninit (&ct->ctables_formats);
pivot_table_look_unref (ct->look);
free (ct->zero);
free (ct->missing);
else
{
if (!lex_force_string (lexer))
- return false;
+ {
+ ss_dealloc (&s);
+ return false;
+ }
struct substring sr1 = parse_substring (lexer, dict);
*cat = cct_srange (s, sr1);
}
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
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++;
else
{
lex_error_expecting (lexer, "A", "D");
- return false;
+ goto error;
}
}
else if (!c->n_cats && lex_match_id (lexer, "KEY"))
{
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;
}
}
}
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);
else
{
lex_error_expecting (lexer, "BEFORE", "AFTER");
- return false;
+ goto error;
}
}
else if (lex_match_id (lexer, "EMPTY"))
else
{
lex_error_expecting (lexer, "INCLUDE", "EXCLUDE");
- return false;
+ goto error;
}
}
else
"TOTAL", "LABEL", "POSITION", "EMPTY");
else
lex_error_expecting (lexer, "TOTAL", "LABEL", "POSITION", "EMPTY");
- return false;
+ goto error;
}
}
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];
{
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:
"subcommand tries to apply it to string "
"variable %s."),
var_get_name (vars[j]));
- return false;
+ goto error;
}
break;
double n;
if (!parse_category_string (cat->location, cat->string, dict,
common_format->type, &n))
- return false;
+ goto error;
ss_dealloc (&cat->string);
cat->number = n;
}
else if (!all_strings (vars, n_vars, cat))
- return false;
+ goto error;
break;
case CCT_SRANGE:
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]);
cat->nrange[1] = n[1];
}
else if (!all_strings (vars, n_vars, cat))
- return false;
+ goto error;
break;
case CCT_MISSING:
}
}
+ free (vars);
return true;
+
+error:
+ free (vars);
+ return false;
}
static void
ctables_nest_uninit (struct ctables_nest *nest)
{
- if (nest)
- free (nest->vars);
+ free (nest->vars);
+ for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
+ ctables_summary_spec_set_uninit (&nest->specs[sv]);
+ for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
+ free (nest->domains[dt]);
}
static void
size_t allocate = a->n + b->n;
struct variable **vars = xnmalloc (allocate, sizeof *vars);
- enum pivot_axis_type *axes = xnmalloc (allocate, sizeof *axes);
size_t n = 0;
for (size_t k = 0; k < a->n; k++)
vars[n++] = a->vars[k];
}
free (sorted);
free (groups);
+ free (levels);
+ free (sections);
}
}
value = pivot_value_new_number (d);
value->numeric.format = format;
}
+ /* XXX should text values be right-justified? */
pivot_table_put (pt, dindexes, n_dindexes, value);
}
}
listwise_vars[n++] = other_nest->vars[other_nest->scale_idx];
}
}
- for (size_t j = 0; j < N_CSVS; j++)
+ for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
{
- nest->specs[j].listwise_vars = listwise_vars;
- nest->specs[j].n_listwise_vars = n;
+ if (sv > 0)
+ listwise_vars = xmemdup (listwise_vars,
+ n * sizeof *listwise_vars);
+ nest->specs[sv].listwise_vars = listwise_vars;
+ nest->specs[sv].n_listwise_vars = n;
}
}
}
j++;
}
}
+ free (items);
#if 0
for (size_t j = 0; j < merged->n; j++)
}
}
+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++)
+ {
+ struct ctables_nest *nest = s->nests[a];
+ for (size_t i = 0; i < nest->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 const struct operator *
-ctable_pcexpr_match_operator (struct lexer *lexer,
+ctables_pcexpr_match_operator (struct lexer *lexer,
const struct operator ops[], size_t n_ops)
{
for (const struct operator *op = ops; op < ops + n_ops; op++)
}
static struct ctables_pcexpr *
-ctable_pcexpr_parse_binary_operators__ (
+ctables_pcexpr_parse_binary_operators__ (
struct lexer *lexer, struct dictionary *dict,
const struct operator ops[], size_t n_ops,
parse_recursively_func *parse_next_level,
for (int op_count = 0; ; op_count++)
{
const struct operator *op
- = ctable_pcexpr_match_operator (lexer, ops, n_ops);
+ = ctables_pcexpr_match_operator (lexer, ops, n_ops);
if (!op)
{
if (op_count > 1 && chain_warning)
}
static struct ctables_pcexpr *
-ctable_pcexpr_parse_binary_operators (struct lexer *lexer,
- struct dictionary *dict,
- const struct operator ops[], size_t n_ops,
- parse_recursively_func *parse_next_level,
- const char *chain_warning)
+ctables_pcexpr_parse_binary_operators (
+ struct lexer *lexer, struct dictionary *dict,
+ const struct operator ops[], size_t n_ops,
+ parse_recursively_func *parse_next_level, const char *chain_warning)
{
struct ctables_pcexpr *lhs = parse_next_level (lexer, dict);
if (!lhs)
return NULL;
- return ctable_pcexpr_parse_binary_operators__ (lexer, dict, ops, n_ops,
+ return ctables_pcexpr_parse_binary_operators__ (lexer, dict, ops, n_ops,
parse_next_level,
chain_warning, lhs);
}
-static struct ctables_pcexpr *ctable_pcexpr_parse_add (struct lexer *,
- struct dictionary *);
+static struct ctables_pcexpr *ctables_pcexpr_parse_add (struct lexer *,
+ struct dictionary *);
static struct ctables_pcexpr
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)
+ctables_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict)
{
int start_ofs = lex_ofs (lexer);
struct ctables_pcexpr e;
{
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;
}
}
else if (lex_match (lexer, T_LPAREN))
{
- struct ctables_pcexpr *ep = ctable_pcexpr_parse_add (lexer, dict);
+ struct ctables_pcexpr *ep = ctables_pcexpr_parse_add (lexer, dict);
if (!ep)
return NULL;
if (!lex_force_match (lexer, T_RPAREN))
}
static struct ctables_pcexpr *
-ctable_pcexpr_parse_exp (struct lexer *lexer, struct dictionary *dict)
+ctables_pcexpr_parse_exp (struct lexer *lexer, struct dictionary *dict)
{
static const struct operator op = { T_EXP, CTPO_POW };
"To disable this warning, insert parentheses.");
if (lex_token (lexer) != T_NEG_NUM || lex_next_token (lexer, 1) != T_EXP)
- return ctable_pcexpr_parse_binary_operators (lexer, dict, &op, 1,
- ctable_pcexpr_parse_primary,
- chain_warning);
+ return ctables_pcexpr_parse_binary_operators (lexer, dict, &op, 1,
+ ctables_pcexpr_parse_primary,
+ chain_warning);
/* Special case for situations like "-5**6", which must be parsed as
-(5**6). */
};
lex_get (lexer);
- struct ctables_pcexpr *node = ctable_pcexpr_parse_binary_operators__ (
+ struct ctables_pcexpr *node = ctables_pcexpr_parse_binary_operators__ (
lexer, dict, &op, 1,
- ctable_pcexpr_parse_primary, chain_warning, lhs);
+ ctables_pcexpr_parse_primary, chain_warning, lhs);
if (!node)
return NULL;
/* Parses the unary minus level. */
static struct ctables_pcexpr *
-ctable_pcexpr_parse_neg (struct lexer *lexer, struct dictionary *dict)
+ctables_pcexpr_parse_neg (struct lexer *lexer, struct dictionary *dict)
{
int start_ofs = lex_ofs (lexer);
if (!lex_match (lexer, T_DASH))
- return ctable_pcexpr_parse_exp (lexer, dict);
+ return ctables_pcexpr_parse_exp (lexer, dict);
- struct ctables_pcexpr *inner = ctable_pcexpr_parse_neg (lexer, dict);
+ struct ctables_pcexpr *inner = ctables_pcexpr_parse_neg (lexer, dict);
if (!inner)
return NULL;
/* Parses the multiplication and division level. */
static struct ctables_pcexpr *
-ctable_pcexpr_parse_mul (struct lexer *lexer, struct dictionary *dict)
+ctables_pcexpr_parse_mul (struct lexer *lexer, struct dictionary *dict)
{
static const struct operator ops[] =
{
{ T_SLASH, CTPO_DIV },
};
- return ctable_pcexpr_parse_binary_operators (lexer, dict, ops,
+ return ctables_pcexpr_parse_binary_operators (lexer, dict, ops,
sizeof ops / sizeof *ops,
- ctable_pcexpr_parse_neg, NULL);
+ ctables_pcexpr_parse_neg, NULL);
}
/* Parses the addition and subtraction level. */
static struct ctables_pcexpr *
-ctable_pcexpr_parse_add (struct lexer *lexer, struct dictionary *dict)
+ctables_pcexpr_parse_add (struct lexer *lexer, struct dictionary *dict)
{
static const struct operator ops[] =
{
{ T_NEG_NUM, CTPO_ADD },
};
- return ctable_pcexpr_parse_binary_operators (lexer, dict,
+ return ctables_pcexpr_parse_binary_operators (lexer, dict,
ops, sizeof ops / sizeof *ops,
- ctable_pcexpr_parse_mul, NULL);
+ ctables_pcexpr_parse_mul, NULL);
}
static struct ctables_postcompute *
}
int expr_start = lex_ofs (lexer);
- struct ctables_pcexpr *expr = ctable_pcexpr_parse_add (lexer, dict);
+ struct ctables_pcexpr *expr = ctables_pcexpr_parse_add (lexer, dict);
int expr_end = lex_ofs (lexer) - 1;
if (!expr || !lex_force_match (lexer, T_RPAREN))
{
+ ctables_pcexpr_destroy (expr);
free (name);
return false;
}