f9ab6f2e4c0d127356f2bf7fc7fa5bbd06d078a2
[pspp-builds.git] / src / language / tests / check-model.q
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2007, 2009 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 #include <limits.h>
19
20 #include <language/tests/check-model.h>
21
22 #include <errno.h>
23
24 #include <language/lexer/lexer.h>
25 #include <libpspp/model-checker.h>
26
27 #include "error.h"
28 #include "fwriteerror.h"
29
30 #include "gettext.h"
31 #define _(msgid) gettext (msgid)
32 #define N_(msgid) msgid
33
34 /* (headers) */
35
36 /* (specification)
37    "CHECK MODEL" (chm_):
38     search=strategy:broad/deep/random,
39            :mxd(n:max_depth),
40            :hash(n:hash_bits);
41     path=integer list;
42     queue=:limit(n:queue_limit,"%s>0"),
43           drop:newest/oldest/random;
44     seed=integer;
45     stop=:states(n:max_unique_states,"%s>0"),
46          :errors(n:max_errors),
47          :timeout(d:time_limit,"%s>0");
48     progress=progress:none/dots/fancy/verbose;
49     output=:verbosity(n:verbosity),
50            :errverbosity(n:err_verbosity),
51            :file(s:output_file).
52 */
53 /* (declarations) */
54 /* (functions) */
55
56 static struct mc_options *parse_options (struct lexer *);
57
58 /* Parses a syntax description of model checker options from
59    LEXER and passes them, along with AUX, to the CHECKER
60    function, which must wrap a call to mc_run and return the
61    mc_results that it returned.  This function then prints a
62    description of the mc_results to the output file.  Returns
63    true if the model checker run found no errors, false
64    otherwise. */
65 bool
66 check_model (struct lexer *lexer,
67              struct mc_results *(*checker) (struct mc_options *, void *aux),
68              void *aux)
69 {
70   struct mc_options *options;
71   struct mc_results *results;
72   FILE *output_file;
73   bool ok;
74
75   options = parse_options (lexer);
76   if (options == NULL)
77     return false;
78   output_file = mc_options_get_output_file (options);
79
80   results = checker (options, aux);
81
82   mc_results_print (results, output_file);
83
84   if (output_file != stdout && output_file != stderr)
85     {
86       if (fwriteerror (output_file) < 0)
87         {
88           /* We've already discarded the name of the output file.
89              Oh well. */
90           error (0, errno, "error closing output file");
91         }
92     }
93
94   ok = mc_results_get_error_count (results) == 0;
95   mc_results_destroy (results);
96
97   return ok;
98 }
99
100 /* Parses options from LEXER and returns a corresponding
101    mc_options, or a null pointer if parsing fails. */
102 static struct mc_options *
103 parse_options (struct lexer *lexer)
104 {
105   struct cmd_check_model cmd;
106   struct mc_options *options;
107
108   if (!parse_check_model (lexer, NULL, &cmd, NULL))
109     return NULL;
110
111   options = mc_options_create ();
112   if (cmd.strategy != -1)
113     mc_options_set_strategy (options,
114                              cmd.strategy == CHM_BROAD ? MC_BROAD
115                              : cmd.strategy == CHM_DEEP ? MC_DEEP
116                              : cmd.strategy == CHM_RANDOM ? MC_RANDOM
117                              : -1);
118   if (cmd.sbc_path > 0)
119     {
120       if (cmd.sbc_search > 0)
121         msg (SW, _("PATH and SEARCH subcommands are mutually exclusive.  "
122                    "Ignoring PATH."));
123       else
124         {
125           struct subc_list_int *list = &cmd.il_path[0];
126           int count = subc_list_int_count (list);
127           if (count > 0)
128             {
129               struct mc_path path;
130               int i;
131
132               mc_path_init (&path);
133               for (i = 0; i < count; i++)
134                 mc_path_push (&path, subc_list_int_at (list, i));
135               mc_options_set_follow_path (options, &path);
136               mc_path_destroy (&path);
137             }
138           else
139             msg (SW, _("At least one value must be specified on PATH."));
140         }
141     }
142   if (cmd.max_depth != LONG_MIN)
143     mc_options_set_max_depth (options, cmd.max_depth);
144   if (cmd.hash_bits != LONG_MIN)
145     {
146       int hash_bits;
147       mc_options_set_hash_bits (options, cmd.hash_bits);
148       hash_bits = mc_options_get_hash_bits (options);
149       if (hash_bits != cmd.hash_bits)
150         msg (SW, _("Hash bits adjusted to %d."), hash_bits);
151     }
152   if (cmd.queue_limit != LONG_MIN)
153     mc_options_set_queue_limit (options, cmd.queue_limit);
154   if (cmd.drop != -1)
155     {
156       enum mc_queue_limit_strategy drop
157         = (cmd.drop == CHM_NEWEST ? MC_DROP_NEWEST
158            : cmd.drop == CHM_OLDEST ? MC_DROP_OLDEST
159            : cmd.drop == CHM_RANDOM ? MC_DROP_RANDOM
160            : -1);
161       mc_options_set_queue_limit_strategy (options, drop);
162     }
163   if (cmd.sbc_search > 0)
164     mc_options_set_seed (options, cmd.n_seed[0]);
165   if (cmd.max_unique_states != LONG_MIN)
166     mc_options_set_max_unique_states (options, cmd.max_unique_states);
167   if (cmd.max_errors != LONG_MIN)
168     mc_options_set_max_errors (options, cmd.max_errors);
169   if (cmd.time_limit != SYSMIS)
170     mc_options_set_time_limit (options, cmd.time_limit);
171   if (cmd.verbosity != LONG_MIN)
172     mc_options_set_verbosity (options, cmd.verbosity);
173   if (cmd.err_verbosity != LONG_MIN)
174     mc_options_set_failure_verbosity (options, cmd.err_verbosity);
175   if (cmd.progress != -1)
176     {
177       if (cmd.progress == CHM_NONE)
178         mc_options_set_progress_usec (options, 0);
179       else if (cmd.progress == CHM_DOTS)
180         mc_options_set_progress_func (options, mc_progress_dots);
181       else if (cmd.progress == CHM_FANCY)
182         mc_options_set_progress_func (options, mc_progress_fancy);
183       else if (cmd.progress == CHM_VERBOSE)
184         mc_options_set_progress_func (options, mc_progress_verbose);
185     }
186   if (cmd.output_file != NULL)
187     {
188       FILE *output_file = fopen (cmd.output_file, "w");
189       if (output_file == NULL)
190         {
191           error (0, errno, _("error opening \"%s\" for writing"),
192                  cmd.output_file);
193           free_check_model (&cmd);
194           mc_options_destroy (options);
195           return NULL;
196         }
197       mc_options_set_output_file (options, output_file);
198     }
199
200
201   free_check_model (&cmd);
202
203   return options;
204 }
205
206 /*
207   Local Variables:
208   mode: c
209   End:
210 */