Implement DATASET commands.
[pspp-builds.git] / 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/tab.h"
26
27 #include "gettext.h"
28 #define _(msgid) gettext (msgid)
29 \f
30 static int
31 parse_window (struct lexer *lexer, unsigned int allowed,
32               enum dataset_display def)
33 {
34   if (!lex_match_id (lexer, "WINDOW"))
35     return def;
36   lex_match (lexer, T_EQUALS);
37
38   if (allowed & (1 << DATASET_MINIMIZED) && lex_match_id (lexer, "MINIMIZED"))
39     return DATASET_MINIMIZED;
40   else if (allowed & (1 << DATASET_ASIS) && lex_match_id (lexer, "ASIS"))
41     return DATASET_ASIS;
42   else if (allowed & (1 << DATASET_FRONT) && lex_match_id (lexer, "FRONT"))
43     return DATASET_FRONT;
44   else if (allowed & (1 << DATASET_HIDDEN) && lex_match_id (lexer, "HIDDEN"))
45     return DATASET_HIDDEN;
46
47   lex_error (lexer, NULL);
48   return -1;
49 }
50
51 static struct dataset *
52 parse_dataset_name (struct lexer *lexer, struct session *session)
53 {
54   struct dataset *ds;
55
56   if (!lex_force_id (lexer))
57     return NULL;
58
59   ds = session_lookup_dataset (session, lex_tokcstr (lexer));
60   if (ds != NULL)
61     lex_get (lexer);
62   else
63     msg (SE, _("There is no dataset named %s."), lex_tokcstr (lexer));
64   return ds;
65 }
66
67 int
68 cmd_dataset_name (struct lexer *lexer, struct dataset *active)
69 {
70   int display;
71
72   if (!lex_force_id (lexer))
73     return CMD_FAILURE;
74   dataset_set_name (active, lex_tokcstr (lexer));
75   lex_get (lexer);
76
77   display = parse_window (lexer, (1 << DATASET_ASIS) | (1 << DATASET_FRONT),
78                           DATASET_ASIS);
79   if (display < 0)
80     return CMD_FAILURE;
81   else if (display != DATASET_ASIS)
82     dataset_set_display (active, display);
83
84   return CMD_SUCCESS;
85 }
86
87 int
88 cmd_dataset_activate (struct lexer *lexer, struct dataset *active)
89 {
90   struct session *session = dataset_session (active);
91   struct dataset *ds;
92   int display;
93
94   ds = parse_dataset_name (lexer, session);
95   if (ds == NULL)
96     return CMD_FAILURE;
97
98   if (ds != active)
99     {
100       proc_execute (active);
101       session_set_active_dataset (session, ds);
102       if (dataset_name (active)[0] == '\0')
103         dataset_destroy (active);
104       return CMD_SUCCESS;
105     }
106
107   display = parse_window (lexer, (1 << DATASET_ASIS) | (1 << DATASET_FRONT),
108                           DATASET_ASIS);
109   if (display < 0)
110     return CMD_FAILURE;
111   else if (display != DATASET_ASIS)
112     dataset_set_display (ds, display);
113
114   return CMD_SUCCESS;
115 }
116
117 int
118 cmd_dataset_copy (struct lexer *lexer, struct dataset *old)
119 {
120   struct session *session = dataset_session (old);
121   struct dataset *new;
122   int display;
123   char *name;
124
125   /* Parse the entire command first.  proc_execute() can attempt to parse
126      BEGIN DATA...END DATA and it will fail confusingly if we are in the
127      middle of the command at the point.  */
128   if (!lex_force_id (lexer))
129     return CMD_FAILURE;
130   name = xstrdup (lex_tokcstr (lexer));
131   lex_get (lexer);
132
133   display = parse_window (lexer, ((1 << DATASET_MINIMIZED)
134                                   | (1 << DATASET_HIDDEN)
135                                   | (1 << DATASET_FRONT)),
136                           DATASET_MINIMIZED);
137   if (display < 0)
138     {
139       free (name);
140       return CMD_FAILURE;
141     }
142
143   if (session_lookup_dataset (session, name) == old)
144     {
145       new = old;
146       dataset_set_name (old, "");
147     }
148   else
149     {
150       proc_execute (old);
151       new = dataset_clone (old, name);
152     }
153   dataset_set_display (new, display);
154
155   free (name);
156   return CMD_SUCCESS;
157 }
158
159 int
160 cmd_dataset_declare (struct lexer *lexer, struct dataset *ds)
161 {
162   struct session *session = dataset_session (ds);
163   struct dataset *new;
164   int display;
165
166   if (!lex_force_id (lexer))
167     return CMD_FAILURE;
168
169   new = session_lookup_dataset (session, lex_tokcstr (lexer));
170   if (new == NULL)
171     new = dataset_create (session, lex_tokcstr (lexer));
172   lex_get (lexer);
173
174   display = parse_window (lexer, ((1 << DATASET_MINIMIZED)
175                                   | (1 << DATASET_HIDDEN)
176                                   | (1 << DATASET_FRONT)),
177                           DATASET_MINIMIZED);
178   if (display < 0)
179     return CMD_FAILURE;
180   dataset_set_display (new, display);
181
182   return CMD_SUCCESS;
183 }
184
185 static void
186 dataset_close_cb (struct dataset *ds, void *session_)
187 {
188   struct session *session = session_;
189
190   if (ds != session_active_dataset (session))
191     dataset_destroy (ds);
192 }
193
194 int
195 cmd_dataset_close (struct lexer *lexer, struct dataset *ds)
196 {
197   struct session *session = dataset_session (ds);
198
199   if (lex_match (lexer, T_ALL))
200     {
201       session_for_each_dataset (session, dataset_close_cb, session);
202       dataset_set_name (session_active_dataset (session), "");
203     }
204   else
205     {
206       if (!lex_match (lexer, T_ASTERISK))
207         {
208           ds = parse_dataset_name (lexer, session);
209           if (ds == NULL)
210             return CMD_FAILURE;
211         }
212
213       if (ds == session_active_dataset (session))
214         dataset_set_name (ds, "");
215       else
216         dataset_destroy (ds);
217     }
218
219   return CMD_SUCCESS;
220 }
221
222 static void
223 dataset_display_cb (struct dataset *ds, void *p_)
224 {
225   struct dataset ***p = p_;
226   **p = ds;
227   (*p)++;
228 }
229
230 static int
231 sort_datasets (const void *a_, const void *b_)
232 {
233   struct dataset *const *a = a_;
234   struct dataset *const *b = b_;
235
236   return strcmp (dataset_name (*a), dataset_name (*b));
237 }
238
239 int
240 cmd_dataset_display (struct lexer *lexer UNUSED, struct dataset *ds)
241 {
242   struct session *session = dataset_session (ds);
243   struct dataset **datasets, **p;
244   struct tab_table *t;
245   size_t i, n;
246
247   n = session_n_datasets (session);
248   datasets = xmalloc (n * sizeof *datasets);
249   p = datasets;
250   session_for_each_dataset (session, dataset_display_cb, &p);
251   qsort (datasets, n, sizeof *datasets, sort_datasets);
252
253   t = tab_create (1, n + 1);
254   tab_headers (t, 0, 0, 1, 0);
255   tab_box (t, TAL_1, TAL_1, -1, TAL_1, 0, 0, tab_nc (t) - 1, tab_nr (t) - 1);
256   tab_hline (t, TAL_2, 0, 0, 1);
257   tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Dataset"));
258   for (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       if (ds == session_active_dataset (session))
268         tab_text_format (t, 0, i + 1, TAB_LEFT, "%s %s",
269                          name, _("(active dataset)"));
270       else
271         tab_text (t, 0, i + 1, TAB_LEFT, name);
272     }
273   tab_title (t, "Open datasets.");
274   tab_submit (t);
275
276   free (datasets);
277
278   return CMD_SUCCESS;
279 }