- upper confidence limits (*.UCL)
- standard error (*.SE)
*/
-#define SUMMARIES \
- /* All variables. */ \
- S(CTSF_COUNT, "COUNT", N_("Count"), CTF_COUNT, CTFA_ALL) \
- S(CTSF_ECOUNT, "ECOUNT", N_("Adjusted Count"), CTF_COUNT, CTFA_ALL) \
- S(CTSF_ROWPCT_COUNT, "ROWPCT.COUNT", N_("Row %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_COLPCT_COUNT, "COLPCT.COUNT", N_("Column %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_TABLEPCT_COUNT, "TABLEPCT.COUNT", N_("Table %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_SUBTABLEPCT_COUNT, "SUBTABLEPCT.COUNT", N_("Subtable %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_LAYERPCT_COUNT, "LAYERPCT.COUNT", N_("Layer %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_LAYERROWPCT_COUNT, "LAYERROWPCT.COUNT", N_("Layer Row %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_LAYERCOLPCT_COUNT, "LAYERCOLPCT.COUNT", N_("Layer Column %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_ROWPCT_VALIDN, "ROWPCT.VALIDN", N_("Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_COLPCT_VALIDN, "COLPCT.VALIDN", N_("Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_TABLEPCT_VALIDN, "TABLEPCT.VALIDN", N_("Table Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_SUBTABLEPCT_VALIDN, "SUBTABLEPCT.VALIDN", N_("Subtable Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_LAYERPCT_VALIDN, "LAYERPCT.VALIDN", N_("Layer Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_LAYERROWPCT_VALIDN, "LAYERROWPCT.VALIDN", N_("Layer Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_LAYERCOLPCT_VALIDN, "LAYERCOLPCT.VALIDN", N_("Layer Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_ROWPCT_TOTALN, "ROWPCT.TOTALN", N_("Row Total N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_COLPCT_TOTALN, "COLPCT.TOTALN", N_("Column Total N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_TABLEPCT_TOTALN, "TABLEPCT.TOTALN", N_("Table Total N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_SUBTABLEPCT_TOTALN, "SUBTABLEPCT.TOTALN", N_("Subtable Total N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_LAYERPCT_TOTALN, "LAYERPCT.TOTALN", N_("Layer Total N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_LAYERROWPCT_TOTALN, "LAYERROWPCT.TOTALN", N_("Layer Row Total N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_LAYERCOLPCT_TOTALN, "LAYERCOLPCT.TOTALN", N_("Layer Column Total N %"), CTF_PERCENT, CTFA_ALL) \
- \
- /* All variables (unweighted.) */ \
- S(CTSF_UCOUNT, "UCOUNT", N_("Unweighted Count"), CTF_COUNT, CTFA_ALL) \
- S(CTSF_UROWPCT_COUNT, "UROWPCT.COUNT", N_("Unweighted Row %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_UCOLPCT_COUNT, "UCOLPCT.COUNT", N_("Unweighted Column %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_UTABLEPCT_COUNT, "UTABLEPCT.COUNT", N_("Unweighted Table %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_USUBTABLEPCT_COUNT, "USUBTABLEPCT.COUNT", N_("Unweighted Subtable %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_ULAYERPCT_COUNT, "ULAYERPCT.COUNT", N_("Unweighted Layer %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_ULAYERROWPCT_COUNT, "ULAYERROWPCT.COUNT", N_("Unweighted Layer Row %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_ULAYERCOLPCT_COUNT, "ULAYERCOLPCT.COUNT", N_("Unweighted Layer Column %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_UROWPCT_VALIDN, "UROWPCT.VALIDN", N_("Unweighted Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_UCOLPCT_VALIDN, "UCOLPCT.VALIDN", N_("Unweighted Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_UTABLEPCT_VALIDN, "UTABLEPCT.VALIDN", N_("Unweighted Table Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_USUBTABLEPCT_VALIDN, "USUBTABLEPCT.VALIDN", N_("Unweighted Subtable Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_ULAYERPCT_VALIDN, "ULAYERPCT.VALIDN", N_("Unweighted Layer Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_ULAYERROWPCT_VALIDN, "ULAYERROWPCT.VALIDN", N_("Unweighted Layer Row Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_ULAYERCOLPCT_VALIDN, "ULAYERCOLPCT.VALIDN", N_("Unweighted Layer Column Valid N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_UROWPCT_TOTALN, "UROWPCT.TOTALN", N_("Unweighted Row Total N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_UCOLPCT_TOTALN, "UCOLPCT.TOTALN", N_("Unweighted Column Total N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_UTABLEPCT_TOTALN, "UTABLEPCT.TOTALN", N_("Unweighted Table Total N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_USUBTABLEPCT_TOTALN, "USUBTABLEPCT.TOTALN", N_("Unweighted Subtable Total N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_ULAYERPCT_TOTALN, "ULAYERPCT.TOTALN", N_("Unweighted Layer Total N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_ULAYERROWPCT_TOTALN, "ULAYERROWPCT.TOTALN", N_("Unweighted Layer Row Total N %"), CTF_PERCENT, CTFA_ALL) \
- S(CTSF_ULAYERCOLPCT_TOTALN, "ULAYERCOLPCT.TOTALN", N_("Unweighted Layer Column Total N %"), CTF_PERCENT, CTFA_ALL) \
- \
- /* Scale variables, totals, and subtotals. */ \
- S(CTSF_MAXIMUM, "MAXIMUM", N_("Maximum"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_MEAN, "MEAN", N_("Mean"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_MEDIAN, "MEDIAN", N_("Median"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_MINIMUM, "MINIMUM", N_("Minimum"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_MISSING, "MISSING", N_("Missing"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_MODE, "MODE", N_("Mode"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_PTILE, "PTILE", N_("Percentile"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_RANGE, "RANGE", N_("Range"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_SEMEAN, "SEMEAN", N_("Std Error of Mean"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_STDDEV, "STDDEV", N_("Std Deviation"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_SUM, "SUM", N_("Sum"), CTF_GENERAL, CTFA_SCALE) \
- S(CSTF_TOTALN, "TOTALN", N_("Total N"), CTF_COUNT, CTFA_SCALE) \
- S(CTSF_ETOTALN, "ETOTALN", N_("Adjusted Total N"), CTF_COUNT, CTFA_SCALE) \
- S(CTSF_VALIDN, "VALIDN", N_("Valid N"), CTF_COUNT, CTFA_SCALE) \
- S(CTSF_EVALIDN, "EVALIDN", N_("Adjusted Valid N"), CTF_COUNT, CTFA_SCALE) \
- S(CTSF_VARIANCE, "VARIANCE", N_("Variance"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_ROWPCT_SUM, "ROWPCT.SUM", N_("Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
- S(CTSF_COLPCT_SUM, "COLPCT.SUM", N_("Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
- S(CTSF_TABLEPCT_SUM, "TABLEPCT.SUM", N_("Table Sum %"), CTF_PERCENT, CTFA_SCALE) \
- S(CTSF_SUBTABLEPCT_SUM, "SUBTABLEPCT.SUM", N_("Subtable Sum %"), CTF_PERCENT, CTFA_SCALE) \
- 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) \
- \
- /* Scale variables, totals, and subtotals (unweighted). */ \
- S(CTSF_UMEAN, "UMEAN", N_("Unweighted Mean"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_UMEDIAN, "UMEDIAN", N_("Unweighted Median"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_UMISSING, "UMISSING", N_("Unweighted Missing"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_UMODE, "UMODE", N_("Unweighted Mode"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_UPTILE, "UPTILE", N_("Unweighted Percentile"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_USEMEAN, "USEMEAN", N_("Unweighted Std Error of Mean"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_USTDDEV, "USTDDEV", N_("Unweighted Std Deviation"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_USUM, "USUM", N_("Unweighted Sum"), CTF_GENERAL, CTFA_SCALE) \
- S(CSTF_UTOTALN, "UTOTALN", N_("Unweighted Total N"), CTF_COUNT, CTFA_SCALE) \
- S(CTSF_UVALIDN, "UVALIDN", N_("Unweighted Valid N"), CTF_COUNT, CTFA_SCALE) \
- S(CTSF_UVARIANCE, "UVARIANCE", N_("Unweighted Variance"), CTF_GENERAL, CTFA_SCALE) \
- S(CTSF_UROWPCT_SUM, "UROWPCT.SUM", N_("Unweighted Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
- S(CTSF_UCOLPCT_SUM, "UCOLPCT.SUM", N_("Unweighted Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
- S(CTSF_UTABLEPCT_SUM, "UTABLEPCT.SUM", N_("Unweighted Table Sum %"), CTF_PERCENT, CTFA_SCALE) \
- S(CTSF_USUBTABLEPCT_SUM, "USUBTABLEPCT.SUM", N_("Unweighted Subtable Sum %"), CTF_PERCENT, CTFA_SCALE) \
- S(CTSF_ULAYERPCT_SUM, "ULAYERPCT.SUM", N_("Unweighted Layer Sum %"), CTF_PERCENT, CTFA_SCALE) \
- S(CTSF_ULAYERROWPCT_SUM, "ULAYERROWPCT.SUM", N_("Unweighted Layer Row Sum %"), CTF_PERCENT, CTFA_SCALE) \
- S(CTSF_ULAYERCOLPCT_SUM, "ULAYERCOLPCT.SUM", N_("Unweighted Layer Column Sum %"), CTF_PERCENT, CTFA_SCALE) \
-
-#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_TABLEPCT_RESPONSES, "TABLEPCT.RESPONSES", N_("Table Responses %"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_SUBTABLEPCT_RESPONSES, "SUBTABLEPCT.RESPONSES", N_("Subtable Responses %"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_LAYERPCT_RESPONSES, "LAYERPCT.RESPONSES", N_("Layer Responses %"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_LAYERROWPCT_RESPONSES, "LAYERROWPCT.RESPONSES", N_("Layer Row Responses %"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_LAYERCOLPCT_RESPONSES, "LAYERCOLPCT.RESPONSES", N_("Layer Column Responses %"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_ROWPCT_RESPONSES_COUNT, "ROWPCT.RESPONSES.COUNT", N_("Row Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_COLPCT_RESPONSES_COUNT, "COLPCT.RESPONSES.COUNT", N_("Column Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_TABLEPCT_RESPONSES_COUNT, "TABLEPCT.RESPONSES.COUNT", N_("Table Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_SUBTABLEPCT_RESPONSES_COUNT, "SUBTABLEPCT.RESPONSES.COUNT", N_("Subtable Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_LAYERPCT_RESPONSES_COUNT, "LAYERPCT.RESPONSES.COUNT", N_("Layer Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_LAYERROWPCT_RESPONSES_COUNT, "LAYERROWPCT.RESPONSES.COUNT", N_("Layer Row Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_LAYERCOLPCT_RESPONSES_COUNT, "LAYERCOLPCT.RESPONSES.COUNT", N_("Layer Column Responses % (Base: Count)"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_ROWPCT_COUNT_RESPONSES, "ROWPCT.COUNT.RESPONSES", N_("Row Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_COLPCT_COUNT_RESPONSES, "COLPCT.COUNT.RESPONSES", N_("Column Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_TABLEPCT_COUNT_RESPONSES, "TABLEPCT.COUNT.RESPONSES", N_("Table Count % (Base: Responses)"), CTF_PERCENT, CTFA_MRSETS) \
- S(CTSF_SUBTABLEPCT_COUNT_RESPONSES, "SUBTABLEPCT.COUNT.RESPONSES", N_("Subtable Count % (Base: 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
{
#define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) ENUM,
- SUMMARIES
+#include "ctables.inc"
#undef S
};
enum {
#define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) +1
- N_CTSF_FUNCTIONS = SUMMARIES
+ N_CTSF_FUNCTIONS =
+#include "ctables.inc"
#undef S
};
const struct ctables_cell *example;
+ int sequence;
double d_valid; /* Dictionary weight. */
double d_count;
double d_total;
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:
{
CTFA_ALL, /* Any variables. */
CTFA_SCALE, /* Only scale variables, totals, and subtotals. */
- CTFA_MRSETS, /* Only multiple-response sets */
+ //CTFA_MRSETS, /* Only multiple-response sets */
};
struct ctables_summary_spec
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);
}
{
static enum ctables_function_availability availability[] = {
#define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = AVAILABILITY,
- SUMMARIES
+#include "ctables.inc"
#undef S
};
static bool
ctables_summary_function_is_count (enum ctables_summary_function 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:
- case CTSF_UCOUNT:
- case CTSF_UROWPCT_COUNT:
- case CTSF_UCOLPCT_COUNT:
- case CTSF_UTABLEPCT_COUNT:
- case CTSF_USUBTABLEPCT_COUNT:
- case CTSF_ULAYERPCT_COUNT:
- case CTSF_ULAYERROWPCT_COUNT:
- case CTSF_ULAYERCOLPCT_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:
- case CTSF_UROWPCT_VALIDN:
- case CTSF_UCOLPCT_VALIDN:
- case CTSF_UTABLEPCT_VALIDN:
- case CTSF_USUBTABLEPCT_VALIDN:
- case CTSF_ULAYERPCT_VALIDN:
- case CTSF_ULAYERROWPCT_VALIDN:
- case CTSF_ULAYERCOLPCT_VALIDN:
- case CTSF_UROWPCT_TOTALN:
- case CTSF_UCOLPCT_TOTALN:
- case CTSF_UTABLEPCT_TOTALN:
- case CTSF_USUBTABLEPCT_TOTALN:
- case CTSF_ULAYERPCT_TOTALN:
- case CTSF_ULAYERROWPCT_TOTALN:
- case CTSF_ULAYERCOLPCT_TOTALN:
- case CTSF_UMEAN:
- case CTSF_UMEDIAN:
- case CTSF_UMISSING:
- case CTSF_UMODE:
- case CTSF_UPTILE:
- case CTSF_USEMEAN:
- case CTSF_USTDDEV:
- case CTSF_USUM:
- case CSTF_UTOTALN:
- case CTSF_UVALIDN:
- case CTSF_UVARIANCE:
- case CTSF_UROWPCT_SUM:
- case CTSF_UCOLPCT_SUM:
- case CTSF_UTABLEPCT_SUM:
- case CTSF_USUBTABLEPCT_SUM:
- case CTSF_ULAYERPCT_SUM:
- case CTSF_ULAYERROWPCT_SUM:
- case CTSF_ULAYERCOLPCT_SUM:
- return false;
- }
- NOT_REACHED ();
+ return f == CTSF_COUNT || f == CTSF_ECOUNT || f == CTSF_UCOUNT;
}
-
static bool
parse_ctables_summary_function (struct lexer *lexer,
enum ctables_summary_function *f)
static struct pair names[] = {
#define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) \
{ ENUM, SS_LITERAL_INITIALIZER (NAME) },
- SUMMARIES
-
+#include "ctables.inc"
/* The .COUNT suffix may be omitted. */
S(CTSF_ROWPCT_COUNT, "ROWPCT", _, _, _)
S(CTSF_COLPCT_COUNT, "COLPCT", _, _, _)
{
static const enum ctables_format default_formats[] = {
#define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = FORMAT,
- SUMMARIES
+#include "ctables.inc"
#undef S
};
switch (default_formats[function])
{
static const char *default_labels[] = {
#define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = LABEL,
- SUMMARIES
+#include "ctables.inc"
#undef S
};
{
static const char *names[] = {
#define S(ENUM, NAME, LABEL, FORMAT, AVAILABILITY) [ENUM] = NAME,
- SUMMARIES
+#include "ctables.inc"
#undef S
};
return names[function];
const char *var_name = var_get_name (axis->var);
switch (ctables_function_availability (function))
{
+#if 0
case CTFA_MRSETS:
msg_at (SE, loc, _("Summary function %s applies only to multiple "
"response sets."), function_name);
msg_at (SN, axis->loc, _("'%s' is not a multiple response set."),
var_name);
return false;
+#endif
case CTFA_SCALE:
-#if 0
- if (!axis->scale)
+ if (!axis->scale && sv != CSV_TOTAL)
{
msg_at (SE, loc,
_("Summary function %s applies only to scale variables."),
var_name);
return false;
}
-#endif
break;
case CTFA_ALL:
struct ctables_axis *axis = xmalloc (sizeof *axis);
*axis = (struct ctables_axis) { .op = CTAO_VAR, .var = var };
- /* XXX should figure out default measures by reading data */
axis->scale = (lex_match_phrase (ctx->lexer, "[S]") ? true
: lex_match_phrase (ctx->lexer, "[C]") ? false
: var_get_measure (var) == MEASURE_SCALE);
&& fmt_check_type_compat (format, VAL_NUMERIC));
}
+ lex_get (lexer);
if (format->w < 2)
{
- msg (SE, _("Output format %s requires width 2 or greater."), type);
+ lex_next_error (lexer, -1, -1,
+ _("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);
+ lex_next_error (lexer, -1, -1, _("Output format %s requires width "
+ "greater than decimals."), type);
return false;
}
else
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:
ngettext ("These categories include %zu instance "
"of SUBTOTAL or HSUBTOTAL, so references "
"from computed categories must refer to "
- "subtotals by position.",
+ "subtotals by position, "
+ "e.g. SUBTOTAL[1].",
"These categories include %zu instances "
"of SUBTOTAL or HSUBTOTAL, so references "
"from computed categories must refer to "
- "subtotals by position.",
+ "subtotals by position, "
+ "e.g. SUBTOTAL[1].",
n_subtotals),
n_subtotals);
msg_at (SN, e->location,
"in the category list."),
pc_cat->pc->name);
msg_at (SN, e->location, _("This is the missing category."));
- msg_at (SN, cats_location,
- _("To fix the problem, add the missing category to the "
- "list of categories here."));
+ if (e->op == CTPO_CAT_SUBTOTAL)
+ msg_at (SN, cats_location,
+ _("To fix the problem, add subtotals to the "
+ "list of categories here."));
+ else if (e->op == CTPO_CAT_TOTAL)
+ msg (SN, _("To fix the problem, add TOTAL=YES to the variable's "
+ "CATEGORIES specification."));
+ else
+ msg_at (SN, cats_location,
+ _("To fix the problem, add the missing category to the "
+ "list of categories here."));
return false;
}
if (pc_cat->pc->hide_source_cats)
dict, e->subs[i], pc_cat, cats, cats_location))
return false;
return true;
-
- default:
- NOT_REACHED ();
}
+
+ NOT_REACHED ();
}
static bool
}
size_t allocated_cats = 0;
+ int cats_start_ofs = -1;
+ int cats_end_ofs = -1;
if (lex_match (lexer, T_LBRACK))
{
- int cats_start_ofs = lex_ofs (lexer);
+ cats_start_ofs = lex_ofs (lexer);
do
{
if (c->n_cats >= allocated_cats)
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++;
lex_match (lexer, T_COMMA);
}
while (!lex_match (lexer, T_RBRACK));
-
- struct msg_location *cats_location
- = lex_ofs_location (lexer, cats_start_ofs, lex_ofs (lexer) - 1);
- for (size_t i = 0; i < c->n_cats; i++)
- {
- struct ctables_category *cat = &c->cats[i];
- switch (cat->type)
- {
- 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;
- break;
-
- case CCT_NUMBER:
- case CCT_NRANGE:
- for (size_t j = 0; j < n_vars; j++)
- if (var_is_alpha (vars[j]))
- {
- msg_at (SE, cat->location,
- _("This category specification may be applied "
- "only to numeric variables, but this "
- "subcommand tries to apply it to string "
- "variable %s."),
- var_get_name (vars[j]));
- return false;
- }
- break;
-
- case CCT_STRING:
- if (parse_strings)
- {
- double n;
- if (!parse_category_string (cat->location, cat->string, dict,
- common_format->type, &n))
- return false;
-
- ss_dealloc (&cat->string);
-
- cat->type = CCT_NUMBER;
- cat->number = n;
- }
- else if (!all_strings (vars, n_vars, cat))
- return false;
- break;
-
- case CCT_SRANGE:
- if (parse_strings)
- {
- double n[2];
-
- if (!cat->srange[0].string)
- n[0] = -DBL_MAX;
- 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->location,
- cat->srange[1], dict,
- common_format->type, &n[1]))
- return false;
-
- ss_dealloc (&cat->srange[0]);
- ss_dealloc (&cat->srange[1]);
-
- cat->type = CCT_NRANGE;
- cat->nrange[0] = n[0];
- cat->nrange[1] = n[1];
- }
- else if (!all_strings (vars, n_vars, cat))
- return false;
- break;
-
- case CCT_MISSING:
- case CCT_OTHERNM:
- case CCT_SUBTOTAL:
- case CCT_TOTAL:
- case CCT_VALUE:
- case CCT_LABEL:
- case CCT_FUNCTION:
- case CCT_EXCLUDED_MISSING:
- break;
- }
- }
+ cats_end_ofs = lex_ofs (lexer) - 1;
}
struct ctables_category cat = {
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)
+ {
+ for (size_t i = 0; i < c->n_cats; i++)
+ {
+ struct ctables_category *cat = &c->cats[i];
+ switch (cat->type)
+ {
+ case CCT_POSTCOMPUTE:
+ cat->parse_format = parse_strings ? common_format->type : FMT_F;
+ 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:
+ case CCT_NRANGE:
+ for (size_t j = 0; j < n_vars; j++)
+ if (var_is_alpha (vars[j]))
+ {
+ msg_at (SE, cat->location,
+ _("This category specification may be applied "
+ "only to numeric variables, but this "
+ "subcommand tries to apply it to string "
+ "variable %s."),
+ var_get_name (vars[j]));
+ goto error;
+ }
+ break;
+
+ case CCT_STRING:
+ if (parse_strings)
+ {
+ double n;
+ if (!parse_category_string (cat->location, cat->string, dict,
+ common_format->type, &n))
+ goto error;
+
+ ss_dealloc (&cat->string);
+
+ cat->type = CCT_NUMBER;
+ cat->number = n;
+ }
+ else if (!all_strings (vars, n_vars, cat))
+ goto error;
+ break;
+
+ case CCT_SRANGE:
+ if (parse_strings)
+ {
+ double n[2];
+
+ if (!cat->srange[0].string)
+ n[0] = -DBL_MAX;
+ else if (!parse_category_string (cat->location,
+ cat->srange[0], dict,
+ common_format->type, &n[0]))
+ 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]))
+ goto error;
+
+ ss_dealloc (&cat->srange[0]);
+ ss_dealloc (&cat->srange[1]);
+
+ cat->type = CCT_NRANGE;
+ cat->nrange[0] = n[0];
+ cat->nrange[1] = n[1];
+ }
+ else if (!all_strings (vars, n_vars, cat))
+ goto error;
+ break;
+
+ case CCT_MISSING:
+ case CCT_OTHERNM:
+ case CCT_SUBTOTAL:
+ case CCT_TOTAL:
+ case CCT_VALUE:
+ case CCT_LABEL:
+ case CCT_FUNCTION:
+ case CCT_EXCLUDED_MISSING:
+ break;
+ }
+ }
+ }
+
+ 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];
s->count = 0;
break;
+ case CTSF_ROW_ID:
+ case CTSF_COL_ID:
+ case CTSF_TABLE_ID:
+ case CTSF_SUBTABLE_ID:
+ case CTSF_LAYER_ID:
+ case CTSF_LAYERROW_ID:
+ case CTSF_LAYERCOL_ID:
+ break;
+
case CTSF_MAXIMUM:
case CTSF_MINIMUM:
case CTSF_RANGE:
case CTSF_UVALIDN:
break;
+ case CTSF_ROW_ID:
+ case CTSF_COL_ID:
+ case CTSF_TABLE_ID:
+ case CTSF_SUBTABLE_ID:
+ case CTSF_LAYER_ID:
+ case CTSF_LAYERROW_ID:
+ case CTSF_LAYERCOL_ID:
+ break;
+
case CTSF_MAXIMUM:
case CTSF_MINIMUM:
case CTSF_RANGE:
s->count += 1.0;
break;
+ case CTSF_ROW_ID:
+ case CTSF_COL_ID:
+ case CTSF_TABLE_ID:
+ case CTSF_SUBTABLE_ID:
+ case CTSF_LAYER_ID:
+ case CTSF_LAYERROW_ID:
+ case CTSF_LAYERCOL_ID:
+ break;
+
case CTSF_MISSING:
if (is_missing)
s->count += d_weight;
case CTSF_UCOLPCT_SUM:
case CTSF_UCOLPCT_TOTALN:
case CTSF_UCOLPCT_VALIDN:
+ case CTSF_COL_ID:
return CTDT_COL;
case CTSF_LAYERCOLPCT_COUNT:
case CTSF_ULAYERCOLPCT_SUM:
case CTSF_ULAYERCOLPCT_TOTALN:
case CTSF_ULAYERCOLPCT_VALIDN:
+ case CTSF_LAYERCOL_ID:
return CTDT_LAYERCOL;
case CTSF_LAYERPCT_COUNT:
case CTSF_ULAYERPCT_SUM:
case CTSF_ULAYERPCT_TOTALN:
case CTSF_ULAYERPCT_VALIDN:
+ case CTSF_LAYER_ID:
return CTDT_LAYER;
case CTSF_LAYERROWPCT_COUNT:
case CTSF_ULAYERROWPCT_SUM:
case CTSF_ULAYERROWPCT_TOTALN:
case CTSF_ULAYERROWPCT_VALIDN:
+ case CTSF_LAYERROW_ID:
return CTDT_LAYERROW;
case CTSF_ROWPCT_COUNT:
case CTSF_UROWPCT_SUM:
case CTSF_UROWPCT_TOTALN:
case CTSF_UROWPCT_VALIDN:
+ case CTSF_ROW_ID:
return CTDT_ROW;
case CTSF_SUBTABLEPCT_COUNT:
case CTSF_USUBTABLEPCT_SUM:
case CTSF_USUBTABLEPCT_TOTALN:
case CTSF_USUBTABLEPCT_VALIDN:
+ case CTSF_SUBTABLE_ID:
return CTDT_SUBTABLE;
case CTSF_TABLEPCT_COUNT:
case CTSF_UTABLEPCT_SUM:
case CTSF_UTABLEPCT_TOTALN:
case CTSF_UTABLEPCT_VALIDN:
+ case CTSF_TABLE_ID:
return CTDT_TABLE;
}
case CTSF_UTABLEPCT_COUNT:
case CTSF_UTABLEPCT_TOTALN:
case CTSF_UTABLEPCT_VALIDN:
+ case CTSF_ROW_ID:
+ case CTSF_COL_ID:
+ case CTSF_TABLE_ID:
+ case CTSF_SUBTABLE_ID:
+ case CTSF_LAYER_ID:
+ case CTSF_LAYERROW_ID:
+ case CTSF_LAYERCOL_ID:
return false;
case CTSF_COLPCT_SUM:
case CTSF_UCOUNT:
return s->count;
+ case CTSF_ROW_ID:
+ case CTSF_COL_ID:
+ case CTSF_TABLE_ID:
+ case CTSF_SUBTABLE_ID:
+ case CTSF_LAYER_ID:
+ case CTSF_LAYERROW_ID:
+ case CTSF_LAYERCOL_ID:
+ return cell->domains[ctables_function_domain (ss->function)]->sequence;
+
case CTSF_ROWPCT_COUNT:
case CTSF_COLPCT_COUNT:
case CTSF_TABLEPCT_COUNT:
{
const char *a_label = var_lookup_value_label (var, a_val);
const char *b_label = var_lookup_value_label (var, b_val);
- int cmp = (a_label
- ? (b_label ? strcmp (a_label, b_label) : 1)
- : (b_label ? -1 : value_compare_3way (
- a_val, b_val, var_get_width (var))));
+ int cmp;
+ if (a_label)
+ {
+ if (!b_label)
+ return -1;
+ cmp = strcmp (a_label, b_label);
+ }
+ else
+ {
+ if (b_label)
+ return 1;
+ cmp = value_compare_3way (a_val, b_val, var_get_width (var));
+ }
if (cmp)
return a_cv->category->sort_ascending ? cmp : -cmp;
}
}
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);
return ctables_pcexpr_evaluate (&ctx, pc->expr);
}
+static char *
+ctables_format (double d, const struct fmt_spec *format,
+ const struct fmt_settings *settings)
+{
+ const union value v = { .f = d };
+ char *s = data_out_stretchy (&v, "UTF-8", format, settings, NULL);
+
+ /* The custom-currency specifications for NEQUAL, PAREN, and PCTPAREN don't
+ produce the results we want for negative numbers, putting the negative
+ sign in the wrong spot, before the prefix instead of after it. We can't,
+ in fact, produce the desired results using a custom-currency
+ specification. Instead, we postprocess the output, moving the negative
+ sign into place:
+
+ NEQUAL: "-N=3" => "N=-3"
+ PAREN: "-(3)" => "(-3)"
+ PCTPAREN: "-(3%)" => "(-3%)"
+
+ This transformation doesn't affect NEGPAREN. */
+ char *minus_src = strchr (s, '-');
+ if (minus_src && (minus_src == s || minus_src[-1] != 'E'))
+ {
+ char *n_equals = strstr (s, "N=");
+ char *lparen = strchr (s, '(');
+ char *minus_dst = n_equals ? n_equals + 1 : lparen;
+ if (minus_dst)
+ move_element (s, minus_dst - s + 1, 1, minus_src - s, minus_dst - s);
+ }
+ return s;
+}
+
static void
ctables_table_output (struct ctables *ct, struct ctables_table *t)
{
struct ctables_cell *cell = sorted[j];
struct ctables_cell *prev = j > 0 ? sorted[j - 1] : NULL;
+ struct ctables_domain *domain = cell->domains[CTDT_SUBTABLE];
+ if (!domain->sequence)
+ {
+ static int x;
+ domain->sequence = ++x;
+ }
+ domain = cell->domains[CTDT_TABLE];
+ if (!domain->sequence)
+ {
+ static int x;
+ domain->sequence = ++x;
+ }
+
size_t n_common = 0;
if (j > 0)
{
}
free (sorted);
free (groups);
+ free (levels);
+ free (sections);
}
}
else if (d == SYSMIS && ct->missing)
value = pivot_value_new_user_text (ct->missing, SIZE_MAX);
else if (is_ctables_format)
- {
- char *s = data_out_stretchy (&(union value) { .f = d },
- "UTF-8", &format,
- &ct->ctables_formats, NULL);
- value = pivot_value_new_user_text_nocopy (s);
- }
+ value = pivot_value_new_user_text_nocopy (
+ ctables_format (d, &format, &ct->ctables_formats));
else
{
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);
}
}
return true;
const struct ctables_nest *n0 = &stack->nests[0];
- assert (n0->n > 0);
+ if (n0->n == 0)
+ {
+ assert (stack->n == 1);
+ return true;
+ }
+
const struct variable *v0 = n0->vars[n0->n - 1];
struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)];
t->clabels_example = v0;
struct ctables_nest *nest = xmalloc (sizeof *nest);
*nest = (struct ctables_nest) { .n = 0 };
t->stacks[a] = (struct ctables_stack) { .nests = nest, .n = 1 };
+
+ /* There's no point in moving labels away from an axis that has no
+ labels, so avoid dealing with the special cases around that. */
+ t->label_axis[a] = a;
}
struct ctables_stack *stack = &t->stacks[t->summary_axis];
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 pcompute_start = lex_ofs (lexer) - 1;
- if (!lex_force_match (lexer, T_AND) || !lex_force_id (lexer))
+ if (!lex_match (lexer, T_AND))
+ {
+ lex_error_expecting (lexer, "&");
+ return false;
+ }
+ if (!lex_force_id (lexer))
return false;
char *name = ss_xstrdup (lex_tokss (lexer));
}
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;
}
if (!ct->e_weight)
goto error;
}
- else if (lex_match_id (lexer, " HIDESMALLCOUNTS"))
+ else if (lex_match_id (lexer, "HIDESMALLCOUNTS"))
{
if (lex_match_id (lexer, "COUNT"))
{
if (n_summaries > 1)
{
msg (SE, _("Summaries may appear only on one axis."));
- if (summaries[PIVOT_AXIS_ROW])
- msg_at (SN, summaries[PIVOT_AXIS_ROW]->loc,
- _("This variable on the rows axis has a summary."));
- if (summaries[PIVOT_AXIS_COLUMN])
- msg_at (SN, summaries[PIVOT_AXIS_COLUMN]->loc,
- _("This variable on the columns axis has a summary."));
- if (summaries[PIVOT_AXIS_LAYER])
- msg_at (SN, summaries[PIVOT_AXIS_LAYER]->loc,
- _("This variable on the layers axis has a summary."));
+ for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
+ if (summaries[a])
+ {
+ msg_at (SN, summaries[a]->loc,
+ a == PIVOT_AXIS_ROW
+ ? _("This variable on the rows axis has a summary.")
+ : a == PIVOT_AXIS_COLUMN
+ ? _("This variable on the columns axis has a summary.")
+ : _("This variable on the layers axis has a summary."));
+ if (scales[a])
+ msg_at (SN, summaries[a]->loc,
+ _("This is a scale variable, so it always has a "
+ "summary even if the syntax does not explicitly "
+ "specify one."));
+ }
goto error;
}
for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
break;
}
if (!lex_force_match (lexer, T_SLASH))
- break;
+ goto error;
while (!lex_match_id (lexer, "TABLE") && lex_token (lexer) != T_ENDCMD)
{
}
else if (lex_match_id (lexer, "CLABELS"))
{
- while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
+ if (lex_match_id (lexer, "AUTO"))
{
- if (lex_match_id (lexer, "AUTO"))
- {
- t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW;
- t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN;
- }
- else if (lex_match_id (lexer, "ROWLABELS"))
- {
- lex_match (lexer, T_EQUALS);
- if (lex_match_id (lexer, "OPPOSITE"))
- t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_COLUMN;
- else if (lex_match_id (lexer, "LAYER"))
- t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_LAYER;
- else
- {
- lex_error_expecting (lexer, "OPPOSITE", "LAYER");
- goto error;
- }
- }
- else if (lex_match_id (lexer, "COLLABELS"))
+ t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_ROW;
+ t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_COLUMN;
+ }
+ else if (lex_match_id (lexer, "ROWLABELS"))
+ {
+ lex_match (lexer, T_EQUALS);
+ if (lex_match_id (lexer, "OPPOSITE"))
+ t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_COLUMN;
+ else if (lex_match_id (lexer, "LAYER"))
+ t->label_axis[PIVOT_AXIS_ROW] = PIVOT_AXIS_LAYER;
+ else
{
- lex_match (lexer, T_EQUALS);
- if (lex_match_id (lexer, "OPPOSITE"))
- t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_ROW;
- else if (lex_match_id (lexer, "LAYER"))
- t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_LAYER;
- else
- {
- lex_error_expecting (lexer, "OPPOSITE", "LAYER");
- goto error;
- }
+ lex_error_expecting (lexer, "OPPOSITE", "LAYER");
+ goto error;
}
+ }
+ else if (lex_match_id (lexer, "COLLABELS"))
+ {
+ lex_match (lexer, T_EQUALS);
+ if (lex_match_id (lexer, "OPPOSITE"))
+ t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_ROW;
+ else if (lex_match_id (lexer, "LAYER"))
+ t->label_axis[PIVOT_AXIS_COLUMN] = PIVOT_AXIS_LAYER;
else
{
- lex_error_expecting (lexer, "AUTO", "ROWLABELS",
- "COLLABELS");
+ lex_error_expecting (lexer, "OPPOSITE", "LAYER");
goto error;
}
}
+ else
+ {
+ lex_error_expecting (lexer, "AUTO", "ROWLABELS",
+ "COLLABELS");
+ goto error;
+ }
}
else if (lex_match_id (lexer, "CRITERIA"))
{
else if (lex_match_id (lexer, "INCLUDEMRSETS"))
{
lex_match (lexer, T_EQUALS);
- if (parse_bool (lexer, &t->chisq->include_mrsets))
+ if (!parse_bool (lexer, &t->chisq->include_mrsets))
goto error;
}
else if (lex_match_id (lexer, "CATEGORIES"))