\f
/* CTABLES postcompute expressions. */
+struct ctables_postcompute
+ {
+ struct hmap_node hmap_node; /* In struct ctables's 'pcompute' hmap. */
+ char *name; /* Name, without leading &. */
+
+ struct msg_location *location; /* Location of definition. */
+ struct ctables_pcexpr *expr;
+ char *label;
+ struct ctables_summary_spec_set *specs;
+ bool hide_source_cats;
+ };
+
struct ctables_pcexpr
{
/* Precedence table:
}
return ctables_find_category_for_postcompute__ (cats, e);
}
+
+static struct substring
+rtrim_value (const union value *v, const struct variable *var)
+{
+ struct substring s = ss_buffer (CHAR_CAST (char *, v->s),
+ var_get_width (var));
+ ss_rtrim (&s, ss_cstr (" "));
+ return s;
+}
+
+static bool
+in_string_range (const union value *v, const struct variable *var,
+ const struct substring *srange)
+{
+ struct substring s = rtrim_value (v, var);
+ return ((!srange[0].string || ss_compare (s, srange[0]) >= 0)
+ && (!srange[1].string || ss_compare (s, srange[1]) <= 0));
+}
+
+static const struct ctables_category *
+ctables_categories_match (const struct ctables_categories *c,
+ const union value *v, const struct variable *var)
+{
+ if (var_is_numeric (var) && v->f == SYSMIS)
+ return NULL;
+
+ const struct ctables_category *othernm = NULL;
+ for (size_t i = c->n_cats; i-- > 0; )
+ {
+ const struct ctables_category *cat = &c->cats[i];
+ switch (cat->type)
+ {
+ case CCT_NUMBER:
+ if (cat->number == v->f)
+ return cat;
+ break;
+
+ case CCT_STRING:
+ if (ss_equals (cat->string, rtrim_value (v, var)))
+ return cat;
+ break;
+
+ case CCT_NRANGE:
+ if ((cat->nrange[0] == -DBL_MAX || v->f >= cat->nrange[0])
+ && (cat->nrange[1] == DBL_MAX || v->f <= cat->nrange[1]))
+ return cat;
+ break;
+
+ case CCT_SRANGE:
+ if (in_string_range (v, var, cat->srange))
+ return cat;
+ break;
+
+ case CCT_MISSING:
+ if (var_is_value_missing (var, v))
+ return cat;
+ break;
+
+ case CCT_POSTCOMPUTE:
+ break;
+
+ case CCT_OTHERNM:
+ if (!othernm)
+ othernm = cat;
+ break;
+
+ case CCT_SUBTOTAL:
+ case CCT_TOTAL:
+ break;
+
+ case CCT_VALUE:
+ case CCT_LABEL:
+ case CCT_FUNCTION:
+ return (cat->include_missing || !var_is_value_missing (var, v) ? cat
+ : NULL);
+
+ case CCT_EXCLUDED_MISSING:
+ break;
+ }
+ }
+
+ return var_is_value_missing (var, v) ? NULL : othernm;
+}
+
+static const struct ctables_category *
+ctables_categories_total (const struct ctables_categories *c)
+{
+ const struct ctables_category *first = &c->cats[0];
+ const struct ctables_category *last = &c->cats[c->n_cats - 1];
+ return (first->type == CCT_TOTAL ? first
+ : last->type == CCT_TOTAL ? last
+ : NULL);
+}
+
+static void
+ctables_category_format_number (double number, const struct variable *var,
+ struct string *s)
+{
+ struct pivot_value *pv = pivot_value_new_var_value (
+ var, &(union value) { .f = number });
+ pivot_value_format (pv, NULL, s);
+ pivot_value_destroy (pv);
+}
+
+static void
+ctables_category_format_string (struct substring string,
+ const struct variable *var, struct string *out)
+{
+ int width = var_get_width (var);
+ char *s = xmalloc (width);
+ buf_copy_rpad (s, width, string.string, string.length, ' ');
+ struct pivot_value *pv = pivot_value_new_var_value (
+ var, &(union value) { .s = CHAR_CAST (uint8_t *, s) });
+ pivot_value_format (pv, NULL, out);
+ pivot_value_destroy (pv);
+ free (s);
+}
+
+static bool
+ctables_category_format_label (const struct ctables_category *cat,
+ const struct variable *var,
+ struct string *s)
+{
+ switch (cat->type)
+ {
+ case CCT_NUMBER:
+ ctables_category_format_number (cat->number, var, s);
+ return true;
+
+ case CCT_STRING:
+ ctables_category_format_string (cat->string, var, s);
+ return true;
+
+ case CCT_NRANGE:
+ ctables_category_format_number (cat->nrange[0], var, s);
+ ds_put_format (s, " THRU ");
+ ctables_category_format_number (cat->nrange[1], var, s);
+ return true;
+
+ case CCT_SRANGE:
+ ctables_category_format_string (cat->srange[0], var, s);
+ ds_put_format (s, " THRU ");
+ ctables_category_format_string (cat->srange[1], var, s);
+ return true;
+
+ case CCT_MISSING:
+ ds_put_cstr (s, "MISSING");
+ return true;
+
+ case CCT_OTHERNM:
+ ds_put_cstr (s, "OTHERNM");
+ return true;
+
+ case CCT_POSTCOMPUTE:
+ ds_put_format (s, "&%s", cat->pc->name);
+ return true;
+
+ case CCT_TOTAL:
+ case CCT_SUBTOTAL:
+ ds_put_cstr (s, cat->total_label);
+ return true;
+
+ case CCT_VALUE:
+ case CCT_LABEL:
+ case CCT_FUNCTION:
+ case CCT_EXCLUDED_MISSING:
+ return false;
+ }
+
+ return false;
+}
\f
/* CTABLES variable nesting and stacking. */
NOT_REACHED ();
}
\f
-\f
/* CTABLES summary calculation. */
union ctables_summary
union ctables_summary *summaries;
};
-struct ctables_postcompute
- {
- struct hmap_node hmap_node; /* In struct ctables's 'pcompute' hmap. */
- char *name; /* Name, without leading &. */
-
- struct msg_location *location; /* Location of definition. */
- struct ctables_pcexpr *expr;
- char *label;
- struct ctables_summary_spec_set *specs;
- bool hide_source_cats;
- };
-
struct ctables
{
const struct dictionary *dict;
return a;
}
-static struct substring
-rtrim_value (const union value *v, const struct variable *var)
-{
- struct substring s = ss_buffer (CHAR_CAST (char *, v->s),
- var_get_width (var));
- ss_rtrim (&s, ss_cstr (" "));
- return s;
-}
-
-static bool
-in_string_range (const union value *v, const struct variable *var,
- const struct substring *srange)
-{
- struct substring s = rtrim_value (v, var);
- return ((!srange[0].string || ss_compare (s, srange[0]) >= 0)
- && (!srange[1].string || ss_compare (s, srange[1]) <= 0));
-}
-
-static const struct ctables_category *
-ctables_categories_match (const struct ctables_categories *c,
- const union value *v, const struct variable *var)
-{
- if (var_is_numeric (var) && v->f == SYSMIS)
- return NULL;
-
- const struct ctables_category *othernm = NULL;
- for (size_t i = c->n_cats; i-- > 0; )
- {
- const struct ctables_category *cat = &c->cats[i];
- switch (cat->type)
- {
- case CCT_NUMBER:
- if (cat->number == v->f)
- return cat;
- break;
-
- case CCT_STRING:
- if (ss_equals (cat->string, rtrim_value (v, var)))
- return cat;
- break;
-
- case CCT_NRANGE:
- if ((cat->nrange[0] == -DBL_MAX || v->f >= cat->nrange[0])
- && (cat->nrange[1] == DBL_MAX || v->f <= cat->nrange[1]))
- return cat;
- break;
-
- case CCT_SRANGE:
- if (in_string_range (v, var, cat->srange))
- return cat;
- break;
-
- case CCT_MISSING:
- if (var_is_value_missing (var, v))
- return cat;
- break;
-
- case CCT_POSTCOMPUTE:
- break;
-
- case CCT_OTHERNM:
- if (!othernm)
- othernm = cat;
- break;
-
- case CCT_SUBTOTAL:
- case CCT_TOTAL:
- break;
-
- case CCT_VALUE:
- case CCT_LABEL:
- case CCT_FUNCTION:
- return (cat->include_missing || !var_is_value_missing (var, v) ? cat
- : NULL);
-
- case CCT_EXCLUDED_MISSING:
- break;
- }
- }
-
- return var_is_value_missing (var, v) ? NULL : othernm;
-}
-
-static const struct ctables_category *
-ctables_categories_total (const struct ctables_categories *c)
-{
- const struct ctables_category *first = &c->cats[0];
- const struct ctables_category *last = &c->cats[c->n_cats - 1];
- return (first->type == CCT_TOTAL ? first
- : last->type == CCT_TOTAL ? last
- : NULL);
-}
-
static struct ctables_cell *
ctables_cell_insert__ (struct ctables_section *s, const struct ccase *c,
const struct ctables_category **cats[PIVOT_N_AXES])
return strcmp (as_label, bs_label);
}
-static void
-ctables_category_format_number (double number, const struct variable *var,
- struct string *s)
-{
- struct pivot_value *pv = pivot_value_new_var_value (
- var, &(union value) { .f = number });
- pivot_value_format (pv, NULL, s);
- pivot_value_destroy (pv);
-}
-
-static void
-ctables_category_format_string (struct substring string,
- const struct variable *var, struct string *out)
-{
- int width = var_get_width (var);
- char *s = xmalloc (width);
- buf_copy_rpad (s, width, string.string, string.length, ' ');
- struct pivot_value *pv = pivot_value_new_var_value (
- var, &(union value) { .s = CHAR_CAST (uint8_t *, s) });
- pivot_value_format (pv, NULL, out);
- pivot_value_destroy (pv);
- free (s);
-}
-
-static bool
-ctables_category_format_label (const struct ctables_category *cat,
- const struct variable *var,
- struct string *s)
-{
- switch (cat->type)
- {
- case CCT_NUMBER:
- ctables_category_format_number (cat->number, var, s);
- return true;
-
- case CCT_STRING:
- ctables_category_format_string (cat->string, var, s);
- return true;
-
- case CCT_NRANGE:
- ctables_category_format_number (cat->nrange[0], var, s);
- ds_put_format (s, " THRU ");
- ctables_category_format_number (cat->nrange[1], var, s);
- return true;
-
- case CCT_SRANGE:
- ctables_category_format_string (cat->srange[0], var, s);
- ds_put_format (s, " THRU ");
- ctables_category_format_string (cat->srange[1], var, s);
- return true;
-
- case CCT_MISSING:
- ds_put_cstr (s, "MISSING");
- return true;
-
- case CCT_OTHERNM:
- ds_put_cstr (s, "OTHERNM");
- return true;
-
- case CCT_POSTCOMPUTE:
- ds_put_format (s, "&%s", cat->pc->name);
- return true;
-
- case CCT_TOTAL:
- case CCT_SUBTOTAL:
- ds_put_cstr (s, cat->total_label);
- return true;
-
- case CCT_VALUE:
- case CCT_LABEL:
- case CCT_FUNCTION:
- case CCT_EXCLUDED_MISSING:
- return false;
- }
-
- return false;
-}
-
static struct pivot_value *
ctables_postcompute_label (const struct ctables_categories *cats,
const struct ctables_category *cat,