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. */
193 retval
= a
< b
? -1 : a
> b
;
201 /* Performs SORT VARIABLES command. */
203 cmd_sort_variables (struct lexer
*lexer
, struct dataset
*ds
)
205 enum cmd_result result
= CMD_FAILURE
;
207 lex_match (lexer
, T_BY
);
209 /* Parse sort key. */
210 struct criterion c
= { .attr_name
= NULL
};
211 if (lex_match_id (lexer
, "NAME"))
213 else if (lex_match_id (lexer
, "TYPE"))
215 else if (lex_match_id (lexer
, "FORMAT"))
217 else if (lex_match_id (lexer
, "LABEL"))
219 else if (lex_match_id (lexer
, "VALUES"))
220 c
.key
= K_VALUE_LABELS
;
221 else if (lex_match_id (lexer
, "MISSING"))
222 c
.key
= K_MISSING_VALUES
;
223 else if (lex_match_id (lexer
, "MEASURE"))
225 else if (lex_match_id (lexer
, "ROLE"))
227 else if (lex_match_id (lexer
, "COLUMNS"))
229 else if (lex_match_id (lexer
, "ALIGNMENT"))
231 else if (lex_match_id (lexer
, "ATTRIBUTE"))
233 if (!lex_force_id (lexer
))
236 c
.attr_name
= xstrdup (lex_tokcstr (lexer
));
240 /* Parse sort direction. */
241 if (lex_match (lexer
, T_LPAREN
))
243 if (lex_match_id (lexer
, "A") || lex_match_id (lexer
, "UP"))
244 c
.descending
= false;
245 else if (lex_match_id (lexer
, "D") || lex_match_id (lexer
, "DOWN"))
249 lex_error (lexer
, NULL
);
252 if (!lex_force_match (lexer
, T_RPAREN
))
256 c
.descending
= false;
258 /* Sort variables. */
259 struct dictionary
*d
= dataset_dict (ds
);
260 struct variable
**vars
;
262 dict_get_vars_mutable (d
, &vars
, &n_vars
, 0);
263 sort (vars
, n_vars
, sizeof *vars
, compare_vars
, &c
);
264 dict_reorder_vars (d
, CONST_CAST (struct variable
*const *, vars
), n_vars
);
267 result
= CMD_SUCCESS
;