1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2016 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/>. */
21 #include "data/attributes.h"
22 #include "data/dataset.h"
23 #include "data/dictionary.h"
24 #include "data/format.h"
25 #include "data/variable.h"
26 #include "language/command.h"
27 #include "language/lexer/lexer.h"
28 #include "libpspp/array.h"
29 #include "libpspp/assertion.h"
30 #include "libpspp/i18n.h"
31 #include "libpspp/message.h"
32 #include "libpspp/str.h"
34 #include "gl/xalloc.h"
37 #define _(msgid) gettext (msgid)
62 compare_ints (int a, int b)
64 return a < b ? -1 : a > b;
68 compare_formats (const struct fmt_spec *a, const struct fmt_spec *b)
70 int retval = compare_ints (fmt_to_io (a->type), fmt_to_io (b->type));
72 retval = compare_ints (a->w, b->w);
74 retval = compare_ints (a->d, b->d);
79 compare_var_labels (const struct variable *a, const struct variable *b)
81 const char *a_label = var_get_label (a);
82 const char *b_label = var_get_label (b);
83 return utf8_strcasecmp (a_label ? a_label : "",
84 b_label ? b_label : "");
88 map_measure (enum measure m)
90 return (m == MEASURE_NOMINAL ? 0
91 : m == MEASURE_ORDINAL ? 1
96 map_role (enum var_role r)
98 return (r == ROLE_INPUT ? 0
99 : r == ROLE_TARGET ? 1
102 : r == ROLE_PARTITION ? 4
107 get_attribute (const struct variable *v, const char *name)
109 const struct attrset *set = var_get_attributes (v);
110 const struct attribute *attr = attrset_lookup (set, name);
111 const char *value = attr ? attribute_get_value (attr, 0) : NULL;
112 return value ? value : "";
116 map_alignment (enum alignment a)
118 return (a == ALIGN_LEFT ? 0
119 : a == ALIGN_RIGHT ? 1
124 compare_vars (const void *a_, const void *b_, const void *c_)
126 const struct variable *const *ap = a_;
127 const struct variable *const *bp = b_;
128 const struct variable *a = *ap;
129 const struct variable *b = *bp;
130 const struct criterion *c = c_;
136 retval = utf8_strverscasecmp (var_get_name (a), var_get_name (b));
140 retval = compare_ints (var_get_width (a), var_get_width (b));
144 retval = compare_formats (var_get_print_format (a),
145 var_get_print_format (b));
149 retval = compare_var_labels (a, b);
153 retval = compare_ints (var_has_value_labels (a),
154 var_has_value_labels (b));
157 case K_MISSING_VALUES:
158 retval = compare_ints (var_has_missing_values (a),
159 var_has_missing_values (b));
163 retval = compare_ints (map_measure (var_get_measure (a)),
164 map_measure (var_get_measure (b)));
168 retval = compare_ints (map_role (var_get_role (a)),
169 map_role (var_get_role (b)));
173 retval = compare_ints (var_get_display_width (a),
174 var_get_display_width (b));
178 retval = compare_ints (map_alignment (var_get_alignment (a)),
179 map_alignment (var_get_alignment (b)));
183 retval = utf8_strcasecmp (get_attribute (a, c->attr_name),
184 get_attribute (b, c->attr_name));
191 /* Make this a stable sort. */
194 size_t a_index = var_get_dict_index (a);
195 size_t b_index = var_get_dict_index (b);
196 retval = a_index < b_index ? -1 : a_index > b_index;
205 /* Performs SORT VARIABLES command. */
207 cmd_sort_variables (struct lexer *lexer, struct dataset *ds)
209 enum cmd_result result = CMD_FAILURE;
211 lex_match (lexer, T_BY);
213 /* Parse sort key. */
214 struct criterion c = { .attr_name = NULL };
215 if (lex_match_id (lexer, "NAME"))
217 else if (lex_match_id (lexer, "TYPE"))
219 else if (lex_match_id (lexer, "FORMAT"))
221 else if (lex_match_id (lexer, "LABEL"))
223 else if (lex_match_id (lexer, "VALUES"))
224 c.key = K_VALUE_LABELS;
225 else if (lex_match_id (lexer, "MISSING"))
226 c.key = K_MISSING_VALUES;
227 else if (lex_match_id (lexer, "MEASURE"))
229 else if (lex_match_id (lexer, "ROLE"))
231 else if (lex_match_id (lexer, "COLUMNS"))
233 else if (lex_match_id (lexer, "ALIGNMENT"))
235 else if (lex_match_id (lexer, "ATTRIBUTE"))
237 if (!lex_force_id (lexer))
240 c.attr_name = xstrdup (lex_tokcstr (lexer));
245 lex_error_expecting (lexer, "NAME", "TYPE", "FORMAT", "LABEL",
246 "VALUES", "MISSING", "MEASURE", "ROLE",
247 "COLUMNS", "ALIGNMENT", "ATTRIBUTE");
251 /* Parse sort direction. */
252 if (lex_match (lexer, T_LPAREN))
254 if (lex_match_id (lexer, "A") || lex_match_id (lexer, "UP"))
255 c.descending = false;
256 else if (lex_match_id (lexer, "D") || lex_match_id (lexer, "DOWN"))
260 lex_error_expecting (lexer, "A", "D");
263 if (!lex_force_match (lexer, T_RPAREN))
267 c.descending = false;
269 /* Sort variables. */
270 struct dictionary *d = dataset_dict (ds);
271 struct variable **vars;
273 dict_get_vars_mutable (d, &vars, &n_vars, 0);
274 sort (vars, n_vars, sizeof *vars, compare_vars, &c);
275 dict_reorder_vars (d, CONST_CAST (struct variable *const *, vars), n_vars);
278 result = CMD_SUCCESS;