DATASET: Improve error messages and coding style.
[pspp] / src / language / data-io / dataset.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2010, 2011 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "language/command.h"
20
21 #include "data/dataset.h"
22 #include "data/session.h"
23 #include "language/lexer/lexer.h"
24 #include "libpspp/message.h"
25 #include "output/pivot-table.h"
26
27 #include "gettext.h"
28 #define N_(msgid) msgid
29 #define _(msgid) gettext (msgid)
30 \f
31 static int
32 parse_window (struct lexer *lexer, unsigned int allowed,
33               enum dataset_display def)
34 {
35   if (!lex_match_id (lexer, "WINDOW"))
36     return def;
37   lex_match (lexer, T_EQUALS);
38
39   if (allowed & (1 << DATASET_MINIMIZED) && lex_match_id (lexer, "MINIMIZED"))
40     return DATASET_MINIMIZED;
41   else if (allowed & (1 << DATASET_ASIS) && lex_match_id (lexer, "ASIS"))
42     return DATASET_ASIS;
43   else if (allowed & (1 << DATASET_FRONT) && lex_match_id (lexer, "FRONT"))
44     return DATASET_FRONT;
45   else if (allowed & (1 << DATASET_HIDDEN) && lex_match_id (lexer, "HIDDEN"))
46     return DATASET_HIDDEN;
47
48   const char *allowed_s[4];
49   size_t n_allowed = 0;
50   if (allowed & (1 << DATASET_MINIMIZED))
51     allowed_s[n_allowed++] = "MINIMIZED";
52   if (allowed & (1 << DATASET_ASIS))
53     allowed_s[n_allowed++] = "ASIS";
54   if (allowed & (1 << DATASET_FRONT))
55     allowed_s[n_allowed++] = "FRONT";
56   if (allowed & (1 << DATASET_HIDDEN))
57     allowed_s[n_allowed++] = "HIDDEN";
58   lex_error_expecting_array (lexer, allowed_s, n_allowed);
59   return -1;
60 }
61
62 static struct dataset *
63 parse_dataset_name (struct lexer *lexer, struct session *session)
64 {
65   if (!lex_force_id (lexer))
66     return NULL;
67
68   struct dataset *ds = session_lookup_dataset (session, lex_tokcstr (lexer));
69   if (ds != NULL)
70     lex_get (lexer);
71   else
72     lex_error (lexer, _("There is no dataset named %s."), lex_tokcstr (lexer));
73   return ds;
74 }
75
76 int
77 cmd_dataset_name (struct lexer *lexer, struct dataset *active)
78 {
79   if (!lex_force_id (lexer))
80     return CMD_FAILURE;
81   dataset_set_name (active, lex_tokcstr (lexer));
82   lex_get (lexer);
83
84   int display = parse_window (lexer, (1 << DATASET_ASIS) | (1 << DATASET_FRONT),
85                               DATASET_ASIS);
86   if (display < 0)
87     return CMD_FAILURE;
88   else if (display != DATASET_ASIS)
89     dataset_set_display (active, display);
90
91   return CMD_SUCCESS;
92 }
93
94 int
95 cmd_dataset_activate (struct lexer *lexer, struct dataset *active)
96 {
97   struct session *session = dataset_session (active);
98   struct dataset *ds;
99   int display;
100
101   ds = parse_dataset_name (lexer, session);
102   if (ds == NULL)
103     return CMD_FAILURE;
104
105   if (ds != active)
106     {
107       proc_execute (active);
108       session_set_active_dataset (session, ds);
109       if (dataset_name (active)[0] == '\0')
110         dataset_destroy (active);
111       return CMD_SUCCESS;
112     }
113
114   display = parse_window (lexer, (1 << DATASET_ASIS) | (1 << DATASET_FRONT),
115                           DATASET_ASIS);
116   if (display < 0)
117     return CMD_FAILURE;
118   else if (display != DATASET_ASIS)
119     dataset_set_display (ds, display);
120
121   return CMD_SUCCESS;
122 }
123
124 int
125 cmd_dataset_copy (struct lexer *lexer, struct dataset *old)
126 {
127   struct session *session = dataset_session (old);
128
129   /* Parse the entire command first.  proc_execute() can attempt to parse
130      BEGIN DATA...END DATA and it will fail confusingly if we are in the
131      middle of the command at the point.  */
132   if (!lex_force_id (lexer))
133     return CMD_FAILURE;
134   char *name = xstrdup (lex_tokcstr (lexer));
135   lex_get (lexer);
136
137   int display = parse_window (lexer, ((1 << DATASET_MINIMIZED)
138                                       | (1 << DATASET_HIDDEN)
139                                       | (1 << DATASET_FRONT)),
140                               DATASET_MINIMIZED);
141   if (display < 0)
142     {
143       free (name);
144       return CMD_FAILURE;
145     }
146
147   struct dataset *new;
148   if (session_lookup_dataset (session, name) == old)
149     {
150       new = old;
151       dataset_set_name (old, "");
152     }
153   else
154     {
155       proc_execute (old);
156       new = dataset_clone (old, name);
157     }
158   dataset_set_display (new, display);
159
160   free (name);
161   return CMD_SUCCESS;
162 }
163
164 int
165 cmd_dataset_declare (struct lexer *lexer, struct dataset *ds)
166 {
167   struct session *session = dataset_session (ds);
168
169   if (!lex_force_id (lexer))
170     return CMD_FAILURE;
171
172   struct dataset *new = session_lookup_dataset (session, lex_tokcstr (lexer));
173   if (new == NULL)
174     new = dataset_create (session, lex_tokcstr (lexer));
175   lex_get (lexer);
176
177   int display = parse_window (lexer, ((1 << DATASET_MINIMIZED)
178                                   | (1 << DATASET_HIDDEN)
179                                   | (1 << DATASET_FRONT)),
180                           DATASET_MINIMIZED);
181   if (display < 0)
182     return CMD_FAILURE;
183   dataset_set_display (new, display);
184
185   return CMD_SUCCESS;
186 }
187
188 static void
189 dataset_close_cb (struct dataset *ds, void *session_)
190 {
191   struct session *session = session_;
192
193   if (ds != session_active_dataset (session))
194     dataset_destroy (ds);
195 }
196
197 int
198 cmd_dataset_close (struct lexer *lexer, struct dataset *ds)
199 {
200   struct session *session = dataset_session (ds);
201
202   if (lex_match (lexer, T_ALL))
203     {
204       session_for_each_dataset (session, dataset_close_cb, session);
205       dataset_set_name (session_active_dataset (session), "");
206     }
207   else
208     {
209       if (!lex_match (lexer, T_ASTERISK))
210         {
211           ds = parse_dataset_name (lexer, session);
212           if (ds == NULL)
213             return CMD_FAILURE;
214         }
215
216       if (ds == session_active_dataset (session))
217         dataset_set_name (ds, "");
218       else
219         dataset_destroy (ds);
220     }
221
222   return CMD_SUCCESS;
223 }
224
225 static void
226 dataset_display_cb (struct dataset *ds, void *p_)
227 {
228   struct dataset ***p = p_;
229   **p = ds;
230   (*p)++;
231 }
232
233 static int
234 sort_datasets (const void *a_, const void *b_)
235 {
236   struct dataset *const *a = a_;
237   struct dataset *const *b = b_;
238
239   return strcmp (dataset_name (*a), dataset_name (*b));
240 }
241
242 int
243 cmd_dataset_display (struct lexer *lexer UNUSED, struct dataset *ds)
244 {
245   struct session *session = dataset_session (ds);
246   size_t n = session_n_datasets (session);
247   struct dataset **datasets = xmalloc (n * sizeof *datasets);
248   struct dataset **p = datasets;
249   session_for_each_dataset (session, dataset_display_cb, &p);
250   qsort (datasets, n, sizeof *datasets, sort_datasets);
251
252   struct pivot_table *table = pivot_table_create (N_("Datasets"));
253
254   struct pivot_dimension *datasets_dim = pivot_dimension_create (
255     table, PIVOT_AXIS_ROW, N_("Dataset"));
256   datasets_dim->hide_all_labels = true;
257
258   for (size_t i = 0; i < n; i++)
259     {
260       struct dataset *ds = datasets[i];
261       const char *name;
262
263       name = dataset_name (ds);
264       if (name[0] == '\0')
265         name = _("unnamed dataset");
266
267       char *text = (ds == session_active_dataset (session)
268                     ? xasprintf ("%s (%s)", name, _("active dataset"))
269                     : xstrdup (name));
270
271       int dataset_idx = pivot_category_create_leaf (
272         datasets_dim->root, pivot_value_new_integer (i));
273
274       pivot_table_put1 (table, dataset_idx,
275                         pivot_value_new_user_text_nocopy (text));
276     }
277
278   free (datasets);
279
280   pivot_table_submit (table);
281
282   return CMD_SUCCESS;
283 }