/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2009, 2010, 2012, 2013, 2014 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2009, 2010, 2012, 2013, 2014
+ 2021, Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "libpspp/message.h"
#include "libpspp/pool.h"
#include "libpspp/str.h"
+#include "output/pivot-table.h"
#include "gl/xalloc.h"
#include "gl/c-xvasprintf.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
-
-/* FIXME: Implement PRINT subcommand. */
+#define N_(msgid) (msgid)
/* Explains how to recode one value. */
struct arc_item
{
int width; /* Variable width. */
int src_idx; /* Case index of source variable. */
+ char *src_name; /* Name of source variable. */
+ struct fmt_spec format; /* Print format in source variable. */
struct variable *dst; /* Target variable. */
struct missing_values mv; /* Missing values of source variable. */
char *label; /* Variable label of source variable. */
bool blank_valid;
};
-static trns_proc_func autorecode_trns_proc;
-static trns_free_func autorecode_trns_free;
+static const struct trns_class autorecode_trns_class;
static int compare_arc_items (const void *, const void *, const void *aux);
static void arc_free (struct autorecode_pgm *);
size_t n_dsts = 0;
enum arc_direction direction = ASCENDING;
+ bool print = false;
/* Create procedure. */
- struct autorecode_pgm *arc = xzalloc (sizeof *arc);
+ struct autorecode_pgm *arc = XZALLOC (struct autorecode_pgm);
arc->blank_valid = true;
/* Parse variable lists. */
if (lex_match_id (lexer, "DESCENDING"))
direction = DESCENDING;
else if (lex_match_id (lexer, "PRINT"))
- {
- /* Not yet implemented. */
- }
+ print = true;
else if (lex_match_id (lexer, "GROUP"))
group = true;
else if (lex_match_id (lexer, "BLANK"))
spec->width = var_get_width (src_vars[i]);
spec->src_idx = var_get_case_index (src_vars[i]);
+ spec->src_name = xstrdup (var_get_name (src_vars[i]));
+ spec->format = *var_get_print_format (src_vars[i]);
const char *label = var_get_label (src_vars[i]);
- spec->label = label ? xstrdup (label) : NULL;
+ spec->label = xstrdup_if_nonnull (label);
if (group && i > 0)
spec->items = arc->specs[0].items;
struct arc_item *item = xmalloc (sizeof *item);
item->width = width;
value_clone (&item->from, value, width);
- item->missing = mv_is_value_missing_varwidth (&spec->mv, value, spec->width,
- MV_ANY);
+ item->missing = mv_is_value_missing_varwidth (&spec->mv, value,
+ spec->width);
item->value_label = ds_steal_cstr (&value_label);
hmap_insert (&spec->items->ht, &item->hmap_node, hash);
for (j = 0; j < n_items; j++)
items[j]->to = j + 1;
+ if (print && (!group || i == 0))
+ {
+ struct pivot_value *title
+ = (group
+ ? pivot_value_new_text (N_("Recoding grouped variables."))
+ : spec->label && spec->label[0]
+ ? pivot_value_new_text_format (N_("Recoding %s into %s (%s)."),
+ spec->src_name,
+ var_get_name (spec->dst),
+ spec->label)
+ : pivot_value_new_text_format (N_("Recoding %s into %s."),
+ spec->src_name,
+ var_get_name (spec->dst)));
+ struct pivot_table *table = pivot_table_create__ (title, "Recoding");
+
+ pivot_dimension_create (
+ table, PIVOT_AXIS_COLUMN, N_("Attributes"),
+ N_("New Value"), N_("Value Label"));
+
+ struct pivot_dimension *old_values = pivot_dimension_create (
+ table, PIVOT_AXIS_ROW, N_("Old Value"));
+ old_values->root->show_label = true;
+
+ for (size_t k = 0; k < n_items; k++)
+ {
+ const struct arc_item *item = items[k];
+ int old_value_idx = pivot_category_create_leaf (
+ old_values->root, pivot_value_new_value (
+ &item->from, item->width,
+ (item->width
+ ? &(struct fmt_spec) { .type = FMT_F, .w = item->width }
+ : &spec->format),
+ dict_get_encoding (dict)));
+ pivot_table_put2 (table, 0, old_value_idx,
+ pivot_value_new_integer (item->to));
+
+ const char *value_label = item->value_label;
+ if (value_label && value_label[0])
+ pivot_table_put2 (table, 1, old_value_idx,
+ pivot_value_new_user_text (value_label, -1));
+ }
+
+ pivot_table_submit (table);
+ }
+
/* Assign user-missing values.
User-missing values in the source variable(s) must be marked
mv_init (&mv, 0);
if (n_missing > 3)
mv_add_range (&mv, lo, hi);
- else if (n_missing > 0)
+ else
for (size_t k = 0; k < n_missing; k++)
mv_add_num (&mv, lo + k);
var_set_missing_values (spec->dst, &mv);
/* Free array. */
free (items);
}
- add_transformation (ds, autorecode_trns_proc, autorecode_trns_free, arc);
+ add_transformation (ds, &autorecode_trns_class, arc);
for (size_t i = 0; i < n_dsts; i++)
free (dst_names[i]);
free (item);
}
free (spec->label);
+ free (spec->src_name);
mv_destroy (&spec->mv);
}
size_t n_rec_items =
- (arc->n_specs == 1 || arc->specs[0].items == arc->specs[1].items
+ (arc->n_specs >= 2 && arc->specs[0].items == arc->specs[1].items
? 1
: arc->n_specs);
+
for (size_t i = 0; i < n_rec_items; i++)
{
struct arc_spec *spec = &arc->specs[i];
return direction == ASCENDING ? cmp : -cmp;
}
-static int
+static enum trns_result
autorecode_trns_proc (void *arc_, struct ccase **c,
casenumber case_idx UNUSED)
{
size_t hash = value_hash (value, width, 0);
const struct arc_item *item = find_arc_item (spec->items, value, width,
hash);
- case_data_rw (*c, spec->dst)->f = item ? item->to : SYSMIS;
+ *case_num_rw (*c, spec->dst) = item ? item->to : SYSMIS;
}
return TRNS_CONTINUE;
arc_free (arc);
return true;
}
+
+static const struct trns_class autorecode_trns_class = {
+ .name = "AUTORECODE",
+ .execute = autorecode_trns_proc,
+ .destroy = autorecode_trns_free,
+};