#include "data/casereader.h"
#include "data/casewriter.h"
+#include "data/data-out.h"
#include "data/dataset.h"
#include "data/dictionary.h"
#include "data/mrset.h"
S(CTSF_LAYERPCT_SUM, "LAYERPCT.SUM", N_("Layer Sum %"), CTF_PERCENT, CTFA_SCALE) \
S(CTSF_LAYERROWPCT_SUM, "LAYERROWPCT.SUM", N_("Layer Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
S(CTSF_LAYERCOLPCT_SUM, "LAYERCOLPCT.SUM", N_("Layer Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
- \
- /* Multiple response sets. */ \
+
+#if 0 /* Multiple response sets not yet implemented. */
S(CTSF_RESPONSES, "RESPONSES", N_("Responses"), CTF_COUNT, CTFA_MRSETS) \
S(CTSF_ROWPCT_RESPONSES, "ROWPCT.RESPONSES", N_("Row Responses %"), CTF_PERCENT, CTFA_MRSETS) \
S(CTSF_COLPCT_RESPONSES, "COLPCT.RESPONSES", N_("Column Responses %"), CTF_PERCENT, CTFA_MRSETS) \
S(CTSF_LAYERPCT_COUNT_RESPONSES, "LAYERPCT.COUNT.RESPONSES", N_("Layer Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
S(CTSF_LAYERROWPCT_COUNT_RESPONSES, "LAYERROWPCT.COUNT.RESPONSES", N_("Layer Row Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
S(CTSF_LAYERCOLPCT_COUNT_RESPONSES, "LAYERCOLPCT.RESPONSES.COUNT", N_("Layer Column Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS)
+#endif
enum ctables_summary_function
{
const struct dictionary *dict;
struct pivot_table_look *look;
+ /* CTABLES has a number of extra formats that we implement via custom
+ currency specifications on an alternate fmt_settings. */
+#define CTEF_NEGPAREN FMT_CCA
+#define CTEF_NEQUAL FMT_CCB
+#define CTEF_PAREN FMT_CCC
+#define CTEF_PCTPAREN FMT_CCD
+ struct fmt_settings ctables_formats;
+
/* If this is NULL, zeros are displayed using the normal print format.
Otherwise, this string is displayed. */
char *zero;
size_t n;
size_t allocated;
- struct variable *var;
+ struct variable *scale_var;
};
static void ctables_summary_spec_set_clone (struct ctables_summary_spec_set *,
enum ctables_summary_function function;
double percentile; /* CTSF_PTILE only. */
char *label;
- struct fmt_spec format; /* XXX extra CTABLES formats */
+
+ struct fmt_spec format;
+ bool is_ctables_format; /* Is 'format' one of CTEF_*? */
+
size_t axis_idx;
};
.specs = specs,
.n = src->n,
.allocated = src->n,
- .var = src->var
+ .scale_var = src->scale_var
};
}
static bool
ctables_summary_function_is_count (enum ctables_summary_function f)
{
- static const bool is_count[N_CTSF_FUNCTIONS] = {
- [CTSF_COUNT] = true,
- [CTSF_ECOUNT] = true,
- [CTSF_ROWPCT_COUNT] = true,
- [CTSF_COLPCT_COUNT] = true,
- [CTSF_TABLEPCT_COUNT] = true,
- [CTSF_SUBTABLEPCT_COUNT] = true,
- [CTSF_LAYERPCT_COUNT] = true,
- [CTSF_LAYERROWPCT_COUNT] = true,
- [CTSF_LAYERCOLPCT_COUNT] = true,
- [CTSF_ROWPCT_RESPONSES_COUNT] = true,
- [CTSF_COLPCT_RESPONSES_COUNT] = true,
- [CTSF_TABLEPCT_RESPONSES_COUNT] = true,
- [CTSF_SUBTABLEPCT_RESPONSES_COUNT] = true,
- [CTSF_LAYERPCT_RESPONSES_COUNT] = true,
- [CTSF_LAYERROWPCT_RESPONSES_COUNT] = true,
- [CTSF_LAYERCOLPCT_RESPONSES_COUNT] = true,
- [CTSF_ROWPCT_COUNT_RESPONSES] = true,
- [CTSF_COLPCT_COUNT_RESPONSES] = true,
- [CTSF_TABLEPCT_COUNT_RESPONSES] = true,
- [CTSF_SUBTABLEPCT_COUNT_RESPONSES] = true,
- [CTSF_LAYERPCT_COUNT_RESPONSES] = true,
- [CTSF_LAYERROWPCT_COUNT_RESPONSES] = true,
- [CTSF_LAYERCOLPCT_COUNT_RESPONSES] = true,
- };
- return is_count[f];
+ switch (f)
+ {
+ case CTSF_COUNT:
+ case CTSF_ECOUNT:
+ case CTSF_ROWPCT_COUNT:
+ case CTSF_COLPCT_COUNT:
+ case CTSF_TABLEPCT_COUNT:
+ case CTSF_SUBTABLEPCT_COUNT:
+ case CTSF_LAYERPCT_COUNT:
+ case CTSF_LAYERROWPCT_COUNT:
+ case CTSF_LAYERCOLPCT_COUNT:
+ return true;
+
+ case CTSF_ROWPCT_VALIDN:
+ case CTSF_COLPCT_VALIDN:
+ case CTSF_TABLEPCT_VALIDN:
+ case CTSF_SUBTABLEPCT_VALIDN:
+ case CTSF_LAYERPCT_VALIDN:
+ case CTSF_LAYERROWPCT_VALIDN:
+ case CTSF_LAYERCOLPCT_VALIDN:
+ case CTSF_ROWPCT_TOTALN:
+ case CTSF_COLPCT_TOTALN:
+ case CTSF_TABLEPCT_TOTALN:
+ case CTSF_SUBTABLEPCT_TOTALN:
+ case CTSF_LAYERPCT_TOTALN:
+ case CTSF_LAYERROWPCT_TOTALN:
+ case CTSF_LAYERCOLPCT_TOTALN:
+ case CTSF_MAXIMUM:
+ case CTSF_MEAN:
+ case CTSF_MEDIAN:
+ case CTSF_MINIMUM:
+ case CTSF_MISSING:
+ case CTSF_MODE:
+ case CTSF_PTILE:
+ case CTSF_RANGE:
+ case CTSF_SEMEAN:
+ case CTSF_STDDEV:
+ case CTSF_SUM:
+ case CSTF_TOTALN:
+ case CTSF_ETOTALN:
+ case CTSF_VALIDN:
+ case CTSF_EVALIDN:
+ case CTSF_VARIANCE:
+ case CTSF_ROWPCT_SUM:
+ case CTSF_COLPCT_SUM:
+ case CTSF_TABLEPCT_SUM:
+ case CTSF_SUBTABLEPCT_SUM:
+ case CTSF_LAYERPCT_SUM:
+ case CTSF_LAYERROWPCT_SUM:
+ case CTSF_LAYERCOLPCT_SUM:
+ return false;
+ }
+ NOT_REACHED ();
}
add_summary_spec (struct ctables_axis *axis,
enum ctables_summary_function function, double percentile,
const char *label, const struct fmt_spec *format,
- const struct msg_location *loc, enum ctables_summary_variant sv)
+ bool is_ctables_format, const struct msg_location *loc,
+ enum ctables_summary_variant sv)
{
if (axis->op == CTAO_VAR)
{
.label = xstrdup (label),
.format = (format ? *format
: ctables_summary_default_format (function, &axis->var)),
+ .is_ctables_format = is_ctables_format,
};
return true;
}
{
for (size_t i = 0; i < 2; i++)
if (!add_summary_spec (axis->subs[i], function, percentile, label,
- format, loc, sv))
+ format, is_ctables_format, loc, sv))
return false;
return true;
}
return s[strcspn (s, "0123456789")] != '\0';
}
+static bool
+parse_ctables_format_specifier (struct lexer *lexer, struct fmt_spec *format,
+ bool *is_ctables_format)
+{
+ char type[FMT_TYPE_LEN_MAX + 1];
+ if (!parse_abstract_format_specifier__ (lexer, type, &format->w, &format->d))
+ return false;
+
+ if (!strcasecmp (type, "NEGPAREN"))
+ format->type = CTEF_NEGPAREN;
+ else if (!strcasecmp (type, "NEQUAL"))
+ format->type = CTEF_NEQUAL;
+ else if (!strcasecmp (type, "PAREN"))
+ format->type = CTEF_PAREN;
+ else if (!strcasecmp (type, "PCTPAREN"))
+ format->type = CTEF_PCTPAREN;
+ else
+ {
+ *is_ctables_format = false;
+ return (parse_format_specifier (lexer, format)
+ && fmt_check_output (format)
+ && fmt_check_type_compat (format, VAL_NUMERIC));
+ }
+
+ if (format->w < 2)
+ {
+ msg (SE, _("Output format %s requires width 2 or greater."), type);
+ return false;
+ }
+ else if (format->d > format->w - 1)
+ {
+ msg (SE, _("Output format %s requires width greater than decimals."),
+ type);
+ return false;
+ }
+ else
+ {
+ *is_ctables_format = true;
+ return true;
+ }
+}
+
static struct ctables_axis *
ctables_axis_parse_postfix (struct ctables_axis_parse_ctx *ctx)
{
/* Parse format. */
struct fmt_spec format;
const struct fmt_spec *formatp;
+ bool is_ctables_format = false;
if (lex_token (ctx->lexer) == T_ID
&& has_digit (lex_tokcstr (ctx->lexer)))
{
- if (!parse_format_specifier (ctx->lexer, &format)
- || !fmt_check_output (&format)
- || !fmt_check_type_compat (&format, VAL_NUMERIC))
+ if (!parse_ctables_format_specifier (ctx->lexer, &format,
+ &is_ctables_format))
{
free (label);
goto error;
struct msg_location *loc = lex_ofs_location (ctx->lexer, start_ofs,
lex_ofs (ctx->lexer) - 1);
- add_summary_spec (sub, function, percentile, label, formatp, loc, sv);
+ add_summary_spec (sub, function, percentile, label, formatp,
+ is_ctables_format, loc, sv);
free (label);
msg_location_destroy (loc);
assert (n == allocate);
const struct ctables_nest *summary_src;
- if (!a->specs[CSV_CELL].var)
+ if (!a->specs[CSV_CELL].n && !a->specs[CSV_CELL].scale_var)
summary_src = b;
- else if (!b->specs[CSV_CELL].var)
+ else if (!b->specs[CSV_CELL].n && !b->specs[CSV_CELL].scale_var)
summary_src = a;
else
NOT_REACHED ();
for (enum ctables_summary_variant sv = 0; sv < N_CSVS; sv++)
{
ctables_summary_spec_set_clone (&nest->specs[sv], &a->specs[sv]);
- nest->specs[sv].var = a->var.var;
+ nest->specs[sv].scale_var = a->var.var;
}
return (struct ctables_stack) { .nests = nest, .n = 1 };
s->ovalue = SYSMIS;
}
break;
-
- case CTSF_RESPONSES:
- case CTSF_ROWPCT_RESPONSES:
- case CTSF_COLPCT_RESPONSES:
- case CTSF_TABLEPCT_RESPONSES:
- case CTSF_SUBTABLEPCT_RESPONSES:
- case CTSF_LAYERPCT_RESPONSES:
- case CTSF_LAYERROWPCT_RESPONSES:
- case CTSF_LAYERCOLPCT_RESPONSES:
- case CTSF_ROWPCT_RESPONSES_COUNT:
- case CTSF_COLPCT_RESPONSES_COUNT:
- case CTSF_TABLEPCT_RESPONSES_COUNT:
- case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
- case CTSF_LAYERPCT_RESPONSES_COUNT:
- case CTSF_LAYERROWPCT_RESPONSES_COUNT:
- case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
- case CTSF_ROWPCT_COUNT_RESPONSES:
- case CTSF_COLPCT_COUNT_RESPONSES:
- case CTSF_TABLEPCT_COUNT_RESPONSES:
- case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
- case CTSF_LAYERPCT_COUNT_RESPONSES:
- case CTSF_LAYERROWPCT_COUNT_RESPONSES:
- case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
- NOT_REACHED ();
}
}
case CTSF_PTILE:
casewriter_destroy (s->writer);
break;
-
- case CTSF_RESPONSES:
- case CTSF_ROWPCT_RESPONSES:
- case CTSF_COLPCT_RESPONSES:
- case CTSF_TABLEPCT_RESPONSES:
- case CTSF_SUBTABLEPCT_RESPONSES:
- case CTSF_LAYERPCT_RESPONSES:
- case CTSF_LAYERROWPCT_RESPONSES:
- case CTSF_LAYERCOLPCT_RESPONSES:
- case CTSF_ROWPCT_RESPONSES_COUNT:
- case CTSF_COLPCT_RESPONSES_COUNT:
- case CTSF_TABLEPCT_RESPONSES_COUNT:
- case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
- case CTSF_LAYERPCT_RESPONSES_COUNT:
- case CTSF_LAYERROWPCT_RESPONSES_COUNT:
- case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
- case CTSF_ROWPCT_COUNT_RESPONSES:
- case CTSF_COLPCT_COUNT_RESPONSES:
- case CTSF_TABLEPCT_COUNT_RESPONSES:
- case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
- case CTSF_LAYERPCT_COUNT_RESPONSES:
- case CTSF_LAYERROWPCT_COUNT_RESPONSES:
- case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
- NOT_REACHED ();
}
}
static void
ctables_summary_add (union ctables_summary *s,
const struct ctables_summary_spec *ss,
- const struct variable *var, const union value *value,
+ const struct variable *scale_var, const union value *value,
double d_weight, double e_weight)
{
+ /* To determine whether a case is included in a given table for a particular
+ kind of summary, consider the following charts for each variable in the
+ table. Only if "yes" appears for every variable for the summary is the
+ case counted.
+
+ Categorical variables: VALIDN COUNT TOTALN
+ Valid values in included categories yes yes yes
+ Missing values in included categories --- yes yes
+ Missing values in excluded categories --- --- yes
+ Valid values in excluded categories --- --- ---
+
+ Scale variables: VALIDN COUNT TOTALN
+ Valid value yes yes yes
+ Missing value --- yes yes
+
+ Missing values include both user- and system-missing. (The system-missing
+ value is always in an excluded category.)
+ */
switch (ss->function)
{
case CTSF_COUNT:
+
case CSTF_TOTALN:
case CTSF_VALIDN:
- if (var_is_value_missing (var, value))
+ if (scale_var && var_is_value_missing (scale_var, value))
s->missing += d_weight;
else
s->valid += d_weight;
case CTSF_MISSING:
case CTSF_ETOTALN:
case CTSF_EVALIDN:
- if (var_is_value_missing (var, value))
+ if (scale_var && var_is_value_missing (scale_var, value))
s->missing += e_weight;
else
s->valid += e_weight;
case CTSF_MAXIMUM:
case CTSF_MINIMUM:
case CTSF_RANGE:
- if (!var_is_value_missing (var, value))
+ if (!var_is_value_missing (scale_var, value))
{
- assert (!var_is_alpha (var)); /* XXX? */
+ assert (!var_is_alpha (scale_var)); /* XXX? */
if (s->min == SYSMIS || value->f < s->min)
s->min = value->f;
if (s->max == SYSMIS || value->f > s->max)
case CTSF_LAYERPCT_SUM:
case CTSF_LAYERROWPCT_SUM:
case CTSF_LAYERCOLPCT_SUM:
- if (!var_is_value_missing (var, value))
+ if (!var_is_value_missing (scale_var, value))
moments1_add (s->moments, value->f, e_weight);
break;
case CTSF_MEDIAN:
case CTSF_MODE:
case CTSF_PTILE:
- if (var_is_value_missing (var, value))
+ if (var_is_value_missing (scale_var, value))
{
s->ovalid += e_weight;
casewriter_write (s->writer, c);
}
break;
-
- case CTSF_RESPONSES:
- case CTSF_ROWPCT_RESPONSES:
- case CTSF_COLPCT_RESPONSES:
- case CTSF_TABLEPCT_RESPONSES:
- case CTSF_SUBTABLEPCT_RESPONSES:
- case CTSF_LAYERPCT_RESPONSES:
- case CTSF_LAYERROWPCT_RESPONSES:
- case CTSF_LAYERCOLPCT_RESPONSES:
- case CTSF_ROWPCT_RESPONSES_COUNT:
- case CTSF_COLPCT_RESPONSES_COUNT:
- case CTSF_TABLEPCT_RESPONSES_COUNT:
- case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
- case CTSF_LAYERPCT_RESPONSES_COUNT:
- case CTSF_LAYERROWPCT_RESPONSES_COUNT:
- case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
- case CTSF_ROWPCT_COUNT_RESPONSES:
- case CTSF_COLPCT_COUNT_RESPONSES:
- case CTSF_TABLEPCT_COUNT_RESPONSES:
- case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
- case CTSF_LAYERPCT_COUNT_RESPONSES:
- case CTSF_LAYERROWPCT_COUNT_RESPONSES:
- case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
- NOT_REACHED ();
}
}
case CTSF_MEDIAN:
case CTSF_PTILE:
case CTSF_MODE:
- case CTSF_RESPONSES:
NOT_REACHED ();
case CTSF_COLPCT_COUNT:
- case CTSF_COLPCT_COUNT_RESPONSES:
- case CTSF_COLPCT_RESPONSES:
- case CTSF_COLPCT_RESPONSES_COUNT:
case CTSF_COLPCT_SUM:
case CTSF_COLPCT_TOTALN:
case CTSF_COLPCT_VALIDN:
return CTDT_COL;
case CTSF_LAYERCOLPCT_COUNT:
- case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
- case CTSF_LAYERCOLPCT_RESPONSES:
- case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
case CTSF_LAYERCOLPCT_SUM:
case CTSF_LAYERCOLPCT_TOTALN:
case CTSF_LAYERCOLPCT_VALIDN:
return CTDT_LAYERCOL;
case CTSF_LAYERPCT_COUNT:
- case CTSF_LAYERPCT_COUNT_RESPONSES:
- case CTSF_LAYERPCT_RESPONSES:
- case CTSF_LAYERPCT_RESPONSES_COUNT:
case CTSF_LAYERPCT_SUM:
case CTSF_LAYERPCT_TOTALN:
case CTSF_LAYERPCT_VALIDN:
return CTDT_LAYER;
case CTSF_LAYERROWPCT_COUNT:
- case CTSF_LAYERROWPCT_COUNT_RESPONSES:
- case CTSF_LAYERROWPCT_RESPONSES:
- case CTSF_LAYERROWPCT_RESPONSES_COUNT:
case CTSF_LAYERROWPCT_SUM:
case CTSF_LAYERROWPCT_TOTALN:
case CTSF_LAYERROWPCT_VALIDN:
return CTDT_LAYERROW;
case CTSF_ROWPCT_COUNT:
- case CTSF_ROWPCT_COUNT_RESPONSES:
- case CTSF_ROWPCT_RESPONSES:
- case CTSF_ROWPCT_RESPONSES_COUNT:
case CTSF_ROWPCT_SUM:
case CTSF_ROWPCT_TOTALN:
case CTSF_ROWPCT_VALIDN:
return CTDT_ROW;
case CTSF_SUBTABLEPCT_COUNT:
- case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
- case CTSF_SUBTABLEPCT_RESPONSES:
- case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
case CTSF_SUBTABLEPCT_SUM:
case CTSF_SUBTABLEPCT_TOTALN:
case CTSF_SUBTABLEPCT_VALIDN:
return CTDT_SUBTABLE;
case CTSF_TABLEPCT_COUNT:
- case CTSF_TABLEPCT_COUNT_RESPONSES:
- case CTSF_TABLEPCT_RESPONSES:
- case CTSF_TABLEPCT_RESPONSES_COUNT:
case CTSF_TABLEPCT_SUM:
case CTSF_TABLEPCT_TOTALN:
case CTSF_TABLEPCT_VALIDN:
statistic_destroy (&mode->parent.parent);
}
return s->ovalue;
-
- case CTSF_RESPONSES:
- case CTSF_ROWPCT_RESPONSES:
- case CTSF_COLPCT_RESPONSES:
- case CTSF_TABLEPCT_RESPONSES:
- case CTSF_SUBTABLEPCT_RESPONSES:
- case CTSF_LAYERPCT_RESPONSES:
- case CTSF_LAYERROWPCT_RESPONSES:
- case CTSF_LAYERCOLPCT_RESPONSES:
- case CTSF_ROWPCT_RESPONSES_COUNT:
- case CTSF_COLPCT_RESPONSES_COUNT:
- case CTSF_TABLEPCT_RESPONSES_COUNT:
- case CTSF_SUBTABLEPCT_RESPONSES_COUNT:
- case CTSF_LAYERPCT_RESPONSES_COUNT:
- case CTSF_LAYERROWPCT_RESPONSES_COUNT:
- case CTSF_LAYERCOLPCT_RESPONSES_COUNT:
- case CTSF_ROWPCT_COUNT_RESPONSES:
- case CTSF_COLPCT_COUNT_RESPONSES:
- case CTSF_TABLEPCT_COUNT_RESPONSES:
- case CTSF_SUBTABLEPCT_COUNT_RESPONSES:
- case CTSF_LAYERPCT_COUNT_RESPONSES:
- case CTSF_LAYERROWPCT_COUNT_RESPONSES:
- case CTSF_LAYERCOLPCT_COUNT_RESPONSES:
- NOT_REACHED ();
}
NOT_REACHED ();
const struct ctables_summary_spec_set *specs = &ss->specs[cell->sv];
for (size_t i = 0; i < specs->n; i++)
- ctables_summary_add (&cell->summaries[i], &specs->specs[i], specs->var,
- case_data (c, specs->var), d_weight, e_weight);
+ {
+ const struct variable *scale_var = specs->scale_var;
+ const union value *value = scale_var ? case_data (c, scale_var) : NULL;
+ ctables_summary_add (&cell->summaries[i], &specs->specs[i],
+ scale_var, value, d_weight, e_weight);
+ }
if (cell->contributes_to_domains)
{
for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++)
value = pivot_value_new_user_text (ct->zero, SIZE_MAX);
else if (d == SYSMIS && ct->missing)
value = pivot_value_new_user_text (ct->missing, SIZE_MAX);
+ else if (specs->specs[j].is_ctables_format)
+ {
+ char *s = data_out_stretchy (&(union value) { .f = d },
+ "UTF-8",
+ &specs->specs[j].format,
+ &ct->ctables_formats, NULL);
+ value = pivot_value_new_user_text_nocopy (s);
+ }
else
{
value = pivot_value_new_number (d);
specs->n = 1;
enum ctables_summary_function function
- = specs->var ? CTSF_MEAN : CTSF_COUNT;
- struct ctables_var var = { .is_mrset = false, .var = specs->var };
+ = specs->scale_var ? CTSF_MEAN : CTSF_COUNT;
+ struct ctables_var var = { .var = specs->scale_var };
*specs->specs = (struct ctables_summary_spec) {
.function = function,
.format = ctables_summary_default_format (function, &var),
.label = ctables_summary_default_label (function, 0),
};
- if (!specs->var)
- specs->var = nest->vars[0];
ctables_summary_spec_set_clone (&nest->specs[CSV_TOTAL],
&nest->specs[CSV_CELL]);
for (size_t i = 0; i < n_vars; i++)
vlabels[i] = (enum ctables_vlabel) tvars;
+ struct pivot_table_look *look = pivot_table_look_unshare (
+ pivot_table_look_ref (pivot_table_look_get_default ()));
+ look->omit_empty = false;
+
struct ctables *ct = xmalloc (sizeof *ct);
*ct = (struct ctables) {
.dict = dataset_dict (ds),
- .look = pivot_table_look_unshare (pivot_table_look_ref (
- pivot_table_look_get_default ())),
+ .look = look,
+ .ctables_formats = FMT_SETTINGS_INIT,
.vlabels = vlabels,
.postcomputes = HMAP_INITIALIZER (ct->postcomputes),
};
- ct->look->omit_empty = false;
+
+ struct ctf
+ {
+ enum fmt_type type;
+ const char *dot_string;
+ const char *comma_string;
+ };
+ static const struct ctf ctfs[4] = {
+ { CTEF_NEGPAREN, "(,,,)", "(...)" },
+ { CTEF_NEQUAL, "-,N=,,", "-.N=.." },
+ { CTEF_PAREN, "-,(,),", "-.(.)." },
+ { CTEF_PCTPAREN, "-,(,%),", "-.(.%)." },
+ };
+ bool is_dot = settings_get_fmt_settings ()->decimal == '.';
+ for (size_t i = 0; i < 4; i++)
+ {
+ const char *s = is_dot ? ctfs[i].dot_string : ctfs[i].comma_string;
+ fmt_settings_set_cc (&ct->ctables_formats, ctfs[i].type,
+ fmt_number_style_from_string (s));
+ }
if (!lex_force_match (lexer, T_SLASH))
goto error;