1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "data/mrset.h"
23 #include "data/dictionary.h"
24 #include "data/identifier.h"
25 #include "data/val-type.h"
26 #include "data/variable.h"
27 #include "libpspp/message.h"
28 #include "libpspp/pxd.h"
30 #include "gl/xalloc.h"
33 #define _(msgid) gettext (msgid)
35 /* Creates and returns a clone of OLD. The caller is responsible for freeing
36 the new multiple response set (using mrset_destroy()). */
38 mrset_clone (const struct mrset *old)
42 new = xmalloc (sizeof *new);
43 new->name = xstrdup (old->name);
44 new->label = old->label != NULL ? xstrdup (old->label) : NULL;
45 new->type = old->type;
46 new->vars = xmemdup (old->vars, old->n_vars * sizeof *old->vars);
47 new->n_vars = old->n_vars;
49 new->cat_source = old->cat_source;
50 new->label_from_var_label = old->label_from_var_label;
51 value_clone (&new->counted, &old->counted, old->width);
52 new->width = old->width;
57 /* Frees MRSET and the data that it contains. */
59 mrset_destroy (struct mrset *mrset)
66 value_destroy (&mrset->counted, mrset->width);
71 /* Returns true if the UTF-8 encoded NAME is a valid name for a multiple
72 response set in a dictionary encoded in DICT_ENCODING, false otherwise. If
73 ISSUE_ERROR is true, issues an explanatory error message on failure. */
75 mrset_is_valid_name (const char *name, const char *dict_encoding,
78 if (!id_is_valid (name, dict_encoding, issue_error))
84 msg (SE, _("%s is not a valid name for a multiple response "
85 "set. Multiple response set names must begin with "
93 /* Checks various constraints on MRSET:
95 - MRSET's name begins with '$' and is valid as an identifier in DICT.
97 - MRSET has a valid type.
99 - MRSET has at least 2 variables.
101 - All of MRSET's variables are in DICT.
103 - All of MRSET's variables are the same type (numeric or string).
105 - If MRSET is a multiple dichotomy set, its counted value has the same type
106 as and is no wider than its narrowest variable.
108 Returns true if all the constraints are satisfied, otherwise false. */
110 mrset_ok (const struct mrset *mrset, const struct dictionary *dict)
115 if (mrset->name == NULL
116 || !mrset_is_valid_name (mrset->name, dict_get_encoding (dict), false)
117 || (mrset->type != MRSET_MD && mrset->type != MRSET_MC)
118 || mrset->vars == NULL
119 || mrset->n_vars < 2)
122 type = var_get_type (mrset->vars[0]);
123 if (mrset->type == MRSET_MD && type != val_type_from_width (mrset->width))
125 for (i = 0; i < mrset->n_vars; i++)
126 if (!dict_contains_var (dict, mrset->vars[i])
127 || type != var_get_type (mrset->vars[i])
128 || (mrset->type == MRSET_MD
129 && mrset->width > var_get_width (mrset->vars[i])))
136 mrset_save (const struct mrset *mrset, struct pxd *pxd)
138 struct pxd_builder b;
141 pxd_builder_init (&b, pxd);
143 pxd_builder_put_string (&b, mrset->name);
144 pxd_builder_put_string (&b, mrset->label != NULL ? mrset->label : "");
145 pxd_builder_put_u8 (&b, mrset->type);
147 pxd_builder_put_size_t (&b, mrset->n_vars);
148 for (i = 0; i < mrset->n_vars; i++)
149 pxd_builder_put_string (&b, var_get_name (mrset->vars[i]));
151 if (mrset->type == MRSET_MD)
153 pxd_builder_put_u8 (&b, mrset->cat_source);
154 pxd_builder_put_bool (&b, mrset->label_from_var_label);
155 pxd_builder_put_u16 (&b, mrset->width);
156 pxd_builder_put_value (&b, &mrset->counted, mrset->width);
159 return pxd_builder_commit (&b);
163 mrset_load (struct pxd_object *object, const struct pxd *pxd,
164 const struct dictionary *dict)
170 mrset = xzalloc (sizeof *mrset);
172 pxd_parser_init (&p, object, pxd);
174 mrset->name = pxd_parser_get_string (&p);
176 mrset->label = pxd_parser_get_string (&p);
177 if (mrset->label[0] == '\0')
183 mrset->type = pxd_parser_get_u8 (&p);
185 mrset->n_vars = pxd_parser_get_size_t (&p);
186 mrset->vars = xmalloc (mrset->n_vars * sizeof *mrset->vars);
187 for (i = 0; i < mrset->n_vars; i++)
189 char *name = pxd_parser_get_string (&p);
190 mrset->vars[i] = dict_lookup_var_assert (dict, name);
194 if (mrset->type == MRSET_MD)
196 mrset->cat_source = pxd_parser_get_u8 (&p);
197 mrset->label_from_var_label = pxd_parser_get_bool (&p);
198 mrset->width = pxd_parser_get_u16 (&p);
199 pxd_parser_get_value (&p, &mrset->counted, mrset->width);
202 value_init (&mrset->counted, 0);