gui: Eliminate dataset-related global variables.
[pspp-builds.git] / src / ui / gui / executor.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007, 2009, 2010, 2011  Free Software Foundation
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 "ui/gui/executor.h"
20
21 #include "data/dataset.h"
22 #include "data/lazy-casereader.h"
23 #include "language/command.h"
24 #include "language/lexer/lexer.h"
25 #include "libpspp/cast.h"
26 #include "output/driver.h"
27 #include "ui/gui/psppire-data-store.h"
28 #include "ui/gui/psppire-output-window.h"
29
30 /* Lazy casereader callback function used by execute_syntax. */
31 static struct casereader *
32 create_casereader_from_data_store (void *data_store_)
33 {
34   PsppireDataStore *data_store = data_store_;
35   return psppire_data_store_get_reader (data_store);
36 }
37
38 gboolean
39 execute_syntax (PsppireDataWindow *window, struct lex_reader *lex_reader)
40 {
41   struct lexer *lexer;
42   gboolean retval = TRUE;
43
44   struct casereader *reader;
45   const struct caseproto *proto;
46   casenumber case_cnt;
47   unsigned long int lazy_serial;
48
49   /* When the user executes a number of snippets of syntax in a
50      row, none of which read from the active dataset, the GUI becomes
51      progressively less responsive.  The reason is that each syntax
52      execution encapsulates the active dataset data in another
53      datasheet layer.  The cumulative effect of having a number of
54      layers of datasheets wastes time and space.
55
56      To solve the problem, we use a "lazy casereader", a wrapper
57      around the casereader obtained from the data store, that
58      only actually instantiates that casereader when it is
59      needed.  If the data store casereader is never needed, then
60      it is reused the next time syntax is run, without wrapping
61      it in another layer. */
62   proto = psppire_data_store_get_proto (window->data_store);
63   case_cnt = psppire_data_store_get_case_count (window->data_store);
64   reader = lazy_casereader_create (proto, case_cnt,
65                                    create_casereader_from_data_store,
66                                    window->data_store, &lazy_serial);
67   dataset_set_source (window->dataset, reader);
68
69   g_return_val_if_fail (dataset_has_source (window->dataset), FALSE);
70
71   lexer = lex_create ();
72   psppire_set_lexer (lexer);
73   lex_append (lexer, lex_reader);
74
75   for (;;)
76     {
77       enum cmd_result result = cmd_parse (lexer, window->dataset);
78
79       if ( cmd_result_is_failure (result))
80         {
81           retval = FALSE;
82           if ( lex_get_error_mode (lexer) == LEX_ERROR_STOP )
83             break;
84         }
85
86       if ( result == CMD_EOF || result == CMD_FINISH)
87         break;
88     }
89
90   proc_execute (window->dataset);
91
92   psppire_dict_replace_dictionary (window->data_store->dict,
93                                    dataset_dict (window->dataset));
94
95   reader = dataset_steal_source (window->dataset);
96   if (!lazy_casereader_destroy (reader, lazy_serial))
97     psppire_data_store_set_reader (window->data_store, reader);
98
99   /* Destroy the lexer only after obtaining the dataset, because the dataset
100      might depend on the lexer, if the casereader specifies inline data.  (In
101      such a case then we'll always get an error message--the inline data is
102      missing, otherwise it would have been parsed in the loop above.) */
103   lex_destroy (lexer);
104   psppire_set_lexer (NULL);
105
106   output_flush ();
107
108   return retval;
109 }
110
111 /* Executes null-terminated string SYNTAX as syntax.
112    Returns SYNTAX. */
113 gchar *
114 execute_syntax_string (PsppireDataWindow *window, gchar *syntax)
115 {
116   execute_const_syntax_string (window, syntax);
117   return syntax;
118 }
119
120 /* Executes null-terminated string SYNTAX as syntax. */
121 void
122 execute_const_syntax_string (PsppireDataWindow *window, const gchar *syntax)
123 {
124   execute_syntax (window, lex_reader_for_string (syntax));
125 }