Move all command implementations into a single 'commands' directory.
[pspp] / src / language / commands / repeat.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2007, 2009-2012 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 <stdlib.h>
20
21 #include "data/dataset.h"
22 #include "data/dictionary.h"
23 #include "data/settings.h"
24 #include "language/command.h"
25 #include "language/lexer/lexer.h"
26 #include "language/lexer/segment.h"
27 #include "language/lexer/token.h"
28 #include "language/lexer/variable-parser.h"
29 #include "libpspp/assertion.h"
30 #include "libpspp/cast.h"
31 #include "libpspp/hash-functions.h"
32 #include "libpspp/hmap.h"
33 #include "libpspp/i18n.h"
34 #include "libpspp/message.h"
35 #include "libpspp/str.h"
36 #include "libpspp/misc.h"
37 #include "output/output-item.h"
38
39 #include "gl/ftoastr.h"
40 #include "gl/minmax.h"
41 #include "gl/xalloc.h"
42 #include "gl/xmemdup0.h"
43
44 #include "gettext.h"
45 #define _(msgid) gettext (msgid)
46
47 struct dummy_var
48   {
49     struct hmap_node hmap_node;
50     struct substring name;
51     char **values;
52     size_t n_values;
53     int start_ofs, end_ofs;
54   };
55
56 static bool parse_specification (struct lexer *, struct dictionary *,
57                                  struct hmap *dummies);
58 static bool parse_commands (struct lexer *, struct hmap *dummies);
59 static void destroy_dummies (struct hmap *dummies);
60
61 static bool parse_ids (struct lexer *, const struct dictionary *,
62                        struct dummy_var *);
63 static bool parse_numbers (struct lexer *, struct dummy_var *);
64 static bool parse_strings (struct lexer *, struct dummy_var *);
65
66 int
67 cmd_do_repeat (struct lexer *lexer, struct dataset *ds)
68 {
69   struct hmap dummies = HMAP_INITIALIZER (dummies);
70   bool ok = parse_specification (lexer, dataset_dict (ds), &dummies);
71   ok = parse_commands (lexer, &dummies) && ok;
72   destroy_dummies (&dummies);
73
74   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
75 }
76
77 static const struct dummy_var *
78 find_dummy_var (struct hmap *hmap, struct substring name)
79 {
80   const struct dummy_var *dv;
81
82   HMAP_FOR_EACH_WITH_HASH (dv, struct dummy_var, hmap_node,
83                            utf8_hash_case_substring (name, 0), hmap)
84     if (!utf8_sscasecmp (dv->name, name))
85       return dv;
86
87   return NULL;
88 }
89
90 /* Parses the whole DO REPEAT command specification.
91    Returns success. */
92 static bool
93 parse_specification (struct lexer *lexer, struct dictionary *dict,
94                      struct hmap *dummies)
95 {
96   struct dummy_var *first_dv = NULL;
97
98   do
99     {
100       int start_ofs = lex_ofs (lexer);
101
102       /* Get a stand-in variable name and make sure it's unique. */
103       if (!lex_force_id (lexer))
104         goto error;
105       struct substring name = lex_tokss (lexer);
106       if (dict_lookup_var (dict, name.string))
107         lex_msg (lexer, SW,
108                  _("Dummy variable name `%s' hides dictionary variable `%s'."),
109                  name.string, name.string);
110       if (find_dummy_var (dummies, name))
111         {
112           lex_error (lexer, _("Dummy variable name `%s' is given twice."),
113                      name.string);
114           goto error;
115         }
116
117       /* Make a new macro. */
118       struct dummy_var *dv = xmalloc (sizeof *dv);
119       *dv = (struct dummy_var) {
120         .name = ss_clone (name),
121         .start_ofs = start_ofs,
122       };
123       hmap_insert (dummies, &dv->hmap_node, utf8_hash_case_substring (name, 0));
124
125       /* Skip equals sign. */
126       lex_get (lexer);
127       if (!lex_force_match (lexer, T_EQUALS))
128         goto error;
129
130       /* Get the details of the variable's possible values. */
131       bool ok;
132       if (lex_token (lexer) == T_ID || lex_token (lexer) == T_ALL)
133         ok = parse_ids (lexer, dict, dv);
134       else if (lex_is_number (lexer))
135         ok = parse_numbers (lexer, dv);
136       else if (lex_is_string (lexer))
137         ok = parse_strings (lexer, dv);
138       else
139         {
140           lex_error (lexer, _("Syntax error expecting substitution values."));
141           goto error;
142         }
143       if (!ok)
144         goto error;
145       assert (dv->n_values > 0);
146       if (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
147         {
148           lex_error (lexer, _("Syntax error expecting `/' or end of command."));
149           goto error;
150         }
151       dv->end_ofs = lex_ofs (lexer) - 1;
152
153       /* If this is the first variable then it defines how many replacements
154          there must be; otherwise enforce this number of replacements. */
155       if (first_dv == NULL)
156         first_dv = dv;
157       else if (first_dv->n_values != dv->n_values)
158         {
159           msg (SE, _("Each dummy variable must have the same number of "
160                      "substitutions."));
161
162           lex_ofs_msg (lexer, SN, first_dv->start_ofs, first_dv->end_ofs,
163                        ngettext ("Dummy variable %s had %zu substitution.",
164                                  "Dummy variable %s had %zu substitutions.",
165                                  first_dv->n_values),
166                        first_dv->name.string, first_dv->n_values);
167           lex_ofs_msg (lexer, SN, dv->start_ofs, dv->end_ofs,
168                        ngettext ("Dummy variable %s had %zu substitution.",
169                                  "Dummy variable %s had %zu substitutions.",
170                                  dv->n_values),
171                        dv->name.string, dv->n_values);
172           goto error;
173         }
174
175       lex_match (lexer, T_SLASH);
176     }
177   while (!lex_match (lexer, T_ENDCMD));
178
179   while (lex_match (lexer, T_ENDCMD))
180     continue;
181
182   return true;
183
184 error:
185   lex_discard_rest_of_command (lexer);
186   while (lex_match (lexer, T_ENDCMD))
187     continue;
188   destroy_dummies (dummies);
189   hmap_init (dummies);
190   return false;
191 }
192
193 static size_t
194 count_values (struct hmap *dummies)
195 {
196   if (hmap_is_empty (dummies))
197     return 0;
198   const struct dummy_var *dv = HMAP_FIRST (struct dummy_var, hmap_node, dummies);
199   return dv->n_values;
200 }
201
202 static void
203 do_parse_commands (struct substring s, enum segmenter_mode mode,
204                    struct hmap *dummies,
205                    struct string *outputs, size_t n_outputs)
206 {
207   struct segmenter segmenter = segmenter_init (mode, false);
208   while (!ss_is_empty (s))
209     {
210       enum segment_type type;
211       int n = segmenter_push (&segmenter, s.string, s.length, true, &type);
212       assert (n >= 0);
213
214       if (type == SEG_DO_REPEAT_COMMAND)
215         {
216           for (;;)
217             {
218               int k = segmenter_push (&segmenter, s.string + n, s.length - n,
219                                       true, &type);
220               if (type != SEG_NEWLINE && type != SEG_DO_REPEAT_COMMAND)
221                 break;
222
223               n += k;
224             }
225
226           do_parse_commands (ss_head (s, n), mode, dummies,
227                              outputs, n_outputs);
228         }
229       else if (type != SEG_END)
230         {
231           const struct dummy_var *dv
232             = (type == SEG_IDENTIFIER ? find_dummy_var (dummies, ss_head (s, n))
233                : NULL);
234           for (size_t i = 0; i < n_outputs; i++)
235             if (dv != NULL)
236               ds_put_cstr (&outputs[i], dv->values[i]);
237             else
238               ds_put_substring (&outputs[i], ss_head (s, n));
239         }
240
241       ss_advance (&s, n);
242     }
243 }
244
245 static bool
246 parse_commands (struct lexer *lexer, struct hmap *dummies)
247 {
248   char *file_name = xstrdup_if_nonnull (lex_get_file_name (lexer));
249   int line_number = lex_ofs_start_point (lexer, lex_ofs (lexer)).line;
250
251   struct string input = DS_EMPTY_INITIALIZER;
252   while (lex_is_string (lexer))
253     {
254       ds_put_substring (&input, lex_tokss (lexer));
255       ds_put_byte (&input, '\n');
256       lex_get (lexer);
257     }
258
259   size_t n_values = count_values (dummies);
260   struct string *outputs = xmalloc (n_values * sizeof *outputs);
261   for (size_t i = 0; i < n_values; i++)
262     ds_init_empty (&outputs[i]);
263
264   do_parse_commands (ds_ss (&input), lex_get_syntax_mode (lexer),
265                      dummies, outputs, n_values);
266
267   ds_destroy (&input);
268
269   while (lex_match (lexer, T_ENDCMD))
270     continue;
271
272   bool ok = lex_match_phrase (lexer, "END REPEAT");
273   if (!ok)
274     lex_error (lexer, _("Syntax error expecting END REPEAT."));
275   bool print = ok && lex_match_id (lexer, "PRINT");
276   lex_discard_rest_of_command (lexer);
277
278   for (size_t i = 0; i < n_values; i++)
279     {
280       struct string *output = &outputs[n_values - i - 1];
281       if (print)
282         {
283           struct substring s = output->ss;
284           ss_chomp_byte (&s, '\n');
285           char *label = xasprintf (_("Expansion %zu of %zu"), i + 1, n_values);
286           output_item_submit (
287             text_item_create_nocopy (TEXT_ITEM_LOG, ss_xstrdup (s), label));
288         }
289       const char *encoding = lex_get_encoding (lexer);
290       struct lex_reader *reader = lex_reader_for_substring_nocopy (ds_ss (output), encoding);
291       lex_reader_set_file_name (reader, file_name);
292       reader->line_number = line_number;
293       lex_include (lexer, reader);
294     }
295   free (file_name);
296   free (outputs);
297
298   return ok;
299 }
300
301 static void
302 destroy_dummies (struct hmap *dummies)
303 {
304   struct dummy_var *dv, *next;
305
306   HMAP_FOR_EACH_SAFE (dv, next, struct dummy_var, hmap_node, dummies)
307     {
308       hmap_delete (dummies, &dv->hmap_node);
309
310       ss_dealloc (&dv->name);
311       for (size_t i = 0; i < dv->n_values; i++)
312         free (dv->values[i]);
313       free (dv->values);
314       free (dv);
315     }
316   hmap_destroy (dummies);
317 }
318
319 /* Parses a set of ids for DO REPEAT. */
320 static bool
321 parse_ids (struct lexer *lexer, const struct dictionary *dict,
322            struct dummy_var *dv)
323 {
324   return parse_mixed_vars (lexer, dict, &dv->values, &dv->n_values, PV_NONE);
325 }
326
327 /* Adds REPLACEMENT to MACRO's list of replacements, which has
328    *USED elements and has room for *ALLOCATED.  Allocates memory
329    from POOL. */
330 static void
331 add_replacement (struct dummy_var *dv, char *value, size_t *allocated)
332 {
333   if (dv->n_values == *allocated)
334     dv->values = x2nrealloc (dv->values, allocated, sizeof *dv->values);
335   dv->values[dv->n_values++] = value;
336 }
337
338 /* Parses a list or range of numbers for DO REPEAT. */
339 static bool
340 parse_numbers (struct lexer *lexer, struct dummy_var *dv)
341 {
342   size_t allocated = 0;
343
344   do
345     {
346       if (!lex_force_num (lexer))
347         return false;
348
349       if (lex_next_token (lexer, 1) == T_TO)
350         {
351           if (!lex_is_integer (lexer))
352             {
353               lex_error (lexer, _("Ranges may only have integer bounds."));
354               return false;
355             }
356
357           long a = lex_integer (lexer);
358           lex_get (lexer);
359           lex_get (lexer);
360
361           if (!lex_force_int_range (lexer, NULL, a, LONG_MAX))
362             return false;
363
364           long b = lex_integer (lexer);
365           if (b < a)
366             {
367               lex_next_error (lexer, -2, 0,
368                               _("%ld TO %ld is an invalid range."), a, b);
369               return false;
370             }
371           lex_get (lexer);
372
373           for (long i = a; i <= b; i++)
374             add_replacement (dv, xasprintf ("%ld", i), &allocated);
375         }
376       else
377         {
378           char s[DBL_BUFSIZE_BOUND];
379
380           c_dtoastr (s, sizeof s, 0, 0, lex_number (lexer));
381           add_replacement (dv, xstrdup (s), &allocated);
382           lex_get (lexer);
383         }
384
385       lex_match (lexer, T_COMMA);
386     }
387   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD);
388
389   return true;
390 }
391
392 /* Parses a list of strings for DO REPEAT. */
393 static bool
394 parse_strings (struct lexer *lexer, struct dummy_var *dv)
395 {
396   size_t allocated = 0;
397
398   do
399     {
400       if (!lex_force_string (lexer))
401         return false;
402
403       add_replacement (dv, token_to_string (lex_next (lexer, 0)), &allocated);
404
405       lex_get (lexer);
406       lex_match (lexer, T_COMMA);
407     }
408   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD);
409
410   return true;
411 }
412 \f
413 int
414 cmd_end_repeat (struct lexer *lexer, struct dataset *ds UNUSED)
415 {
416   lex_ofs_error (lexer, 0, 1, _("No matching %s."), "DO REPEAT");
417   return CMD_CASCADING_FAILURE;
418 }