bool hide_subcategories; /* CCT_SUBTOTAL. */
};
- const struct ctables_postcompute *pc; /* CCT_POSTCOMPUTE. */
+ /* CCT_POSTCOMPUTE. */
+ struct
+ {
+ const struct ctables_postcompute *pc;
+ enum fmt_type parse_format;
+ };
/* CCT_VALUE, CCT_LABEL, CCT_FUNCTION. */
struct
return true;
}
+static bool
+parse_category_string (struct msg_location *location,
+ struct substring s, const struct dictionary *dict,
+ enum fmt_type format, double *n)
+{
+ union value v;
+ char *error = data_in (s, dict_get_encoding (dict), format,
+ settings_get_fmt_settings (), &v, 0, NULL);
+ if (error)
+ {
+ msg_at (SE, location,
+ _("Failed to parse category specification as format %s: %s."),
+ fmt_name (format), error);
+ free (error);
+ return false;
+ }
+
+ *n = v.f;
+ return true;
+}
+
static struct ctables_category *
-ctables_find_category_for_postcompute (const struct ctables_categories *cats,
- const struct ctables_pcexpr *e)
+ctables_find_category_for_postcompute__ (const struct ctables_categories *cats,
+ const struct ctables_pcexpr *e)
{
struct ctables_category *best = NULL;
size_t n_subtotals = 0;
return best;
}
+static struct ctables_category *
+ctables_find_category_for_postcompute (const struct dictionary *dict,
+ const struct ctables_categories *cats,
+ enum fmt_type parse_format,
+ const struct ctables_pcexpr *e)
+{
+ if (parse_format != FMT_F)
+ {
+ if (e->op == CTPO_CAT_STRING)
+ {
+ double number;
+ if (!parse_category_string (e->location, e->string, dict,
+ parse_format, &number))
+ return NULL;
+
+ struct ctables_pcexpr e2 = {
+ .op = CTPO_CAT_NUMBER,
+ .number = number,
+ .location = e->location,
+ };
+ return ctables_find_category_for_postcompute__ (cats, &e2);
+ }
+ else if (e->op == CTPO_CAT_SRANGE)
+ {
+ double nrange[2];
+ if (!e->srange[0].string)
+ nrange[0] = -DBL_MAX;
+ else if (!parse_category_string (e->location, e->srange[0], dict,
+ parse_format, &nrange[0]))
+ return NULL;
+
+ if (!e->srange[1].string)
+ nrange[1] = DBL_MAX;
+ else if (!parse_category_string (e->location, e->srange[1], dict,
+ parse_format, &nrange[1]))
+ return NULL;
+
+ struct ctables_pcexpr e2 = {
+ .op = CTPO_CAT_NRANGE,
+ .nrange = { nrange[0], nrange[1] },
+ .location = e->location,
+ };
+ return ctables_find_category_for_postcompute__ (cats, &e2);
+ }
+ }
+ return ctables_find_category_for_postcompute__ (cats, e);
+}
+
static bool
-ctables_recursive_check_postcompute (const struct ctables_pcexpr *e,
+ctables_recursive_check_postcompute (struct dictionary *dict,
+ const struct ctables_pcexpr *e,
struct ctables_category *pc_cat,
const struct ctables_categories *cats,
const struct msg_location *cats_location)
case CTPO_CAT_TOTAL:
{
struct ctables_category *cat = ctables_find_category_for_postcompute (
- cats, e);
+ dict, cats, pc_cat->parse_format, e);
if (!cat)
{
if (e->op == CTPO_CAT_SUBTOTAL && e->subtotal_index == 0)
case CTPO_NEG:
for (size_t i = 0; i < 2; i++)
if (e->subs[i] && !ctables_recursive_check_postcompute (
- e->subs[i], pc_cat, cats, cats_location))
+ dict, e->subs[i], pc_cat, cats, cats_location))
return false;
return true;
}
}
-static bool
-parse_category_string (const struct ctables_category *cat,
- struct substring s, struct dictionary *dict,
- enum fmt_type format, double *n)
-{
- union value v;
- char *error = data_in (s, dict_get_encoding (dict), format,
- settings_get_fmt_settings (), &v, 0, NULL);
- if (error)
- {
- msg_at (SE, cat->location,
- _("Failed to parse category specification as format %s: %s."),
- fmt_name (format), error);
- free (error);
- return false;
- }
-
- *n = v.f;
- return true;
-}
-
static bool
all_strings (struct variable **vars, size_t n_vars,
const struct ctables_category *cat)
switch (cat->type)
{
case CCT_POSTCOMPUTE:
- if (!ctables_recursive_check_postcompute (cat->pc->expr, cat,
- c, cats_location))
+ 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;
break;
if (parse_strings)
{
double n;
- if (!parse_category_string (cat, cat->string, dict,
+ if (!parse_category_string (cat->location, cat->string, dict,
common_format->type, &n))
return false;
if (!cat->srange[0].string)
n[0] = -DBL_MAX;
- else if (!parse_category_string (cat, cat->srange[0], dict,
+ else if (!parse_category_string (cat->location,
+ cat->srange[0], dict,
common_format->type, &n[0]))
return false;
if (!cat->srange[1].string)
n[1] = DBL_MAX;
- else if (!parse_category_string (cat, cat->srange[1], dict,
+ else if (!parse_category_string (cat->location,
+ cat->srange[1], dict,
common_format->type, &n[1]))
return false;
enum pivot_axis_type pc_a;
size_t pc_a_idx;
size_t summary_idx;
+ enum fmt_type parse_format;
};
static double ctables_pcexpr_evaluate (
case CTPO_CAT_SRANGE:
{
struct ctables_cell_value cv = {
- .category = ctables_find_category_for_postcompute (ctx->cats, e)
+ .category = ctables_find_category_for_postcompute (ctx->section->table->ctables->dict, ctx->cats, ctx->parse_format, e)
};
assert (cv.category != NULL);
case CTPO_CAT_TOTAL:
{
struct ctables_cell_value cv = {
- .category = ctables_find_category_for_postcompute (ctx->cats, e),
+ .category = ctables_find_category_for_postcompute (ctx->section->table->ctables->dict, ctx->cats, ctx->parse_format, e),
.value = { .f = e->number },
};
assert (cv.category != NULL);
NOT_REACHED ();
}
-/* XXX what if there is a postcompute in more than one dimension?? */
-static const struct ctables_postcompute *
+static const struct ctables_category *
ctables_cell_postcompute (const struct ctables_section *s,
const struct ctables_cell *cell,
enum pivot_axis_type *pc_a_p,
size_t *pc_a_idx_p)
{
assert (cell->postcompute);
- const struct ctables_postcompute *pc = NULL;
+ const struct ctables_category *pc_cat = NULL;
for (enum pivot_axis_type pc_a = 0; pc_a < PIVOT_N_AXES; pc_a++)
for (size_t pc_a_idx = 0; pc_a_idx < s->nests[pc_a]->n; pc_a_idx++)
{
const struct ctables_cell_value *cv = &cell->axes[pc_a].cvs[pc_a_idx];
if (cv->category->type == CCT_POSTCOMPUTE)
{
- if (pc)
+ if (pc_cat)
{
/* Multiple postcomputes cross each other. The value is
undefined. */
return NULL;
}
- pc = cv->category->pc;
+ pc_cat = cv->category;
if (pc_a_p)
*pc_a_p = pc_a;
if (pc_a_idx_p)
}
}
- assert (pc != NULL);
- return pc;
+ assert (pc_cat != NULL);
+ return pc_cat;
}
static double
{
enum pivot_axis_type pc_a = 0;
size_t pc_a_idx = 0;
- const struct ctables_postcompute *pc = ctables_cell_postcompute (
+ const struct ctables_category *pc_cat = ctables_cell_postcompute (
s, cell, &pc_a, &pc_a_idx);
- if (!pc)
+ if (!pc_cat)
return SYSMIS;
+ const struct ctables_postcompute *pc = pc_cat->pc;
if (pc->specs)
{
for (size_t i = 0; i < pc->specs->n; i++)
.pc_a = pc_a,
.pc_a_idx = pc_a_idx,
.summary_idx = summary_idx,
+ .parse_format = pc_cat->parse_format,
};
return ctables_pcexpr_evaluate (&ctx, pc->expr);
}