HOST: Use more modern syntax.
[pspp] / src / language / command.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2009, 2010 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 <stdio.h>
22 #include <stdlib.h>
23 #include <ctype.h>
24 #include <errno.h>
25
26 #include "data/casereader.h"
27 #include "data/dictionary.h"
28 #include "data/procedure.h"
29 #include "data/settings.h"
30 #include "data/variable.h"
31 #include "language/lexer/lexer.h"
32 #include "language/prompt.h"
33 #include "libpspp/assertion.h"
34 #include "libpspp/compiler.h"
35 #include "libpspp/message.h"
36 #include "libpspp/str.h"
37 #include "libpspp/getl.h"
38 #include "output/text-item.h"
39
40 #include "xalloc.h"
41 #include "xmalloca.h"
42
43 #include "gettext.h"
44 #define _(msgid) gettext (msgid)
45 #define N_(msgid) msgid
46 \f
47 /* Returns true if RESULT is a valid "enum cmd_result",
48    false otherwise. */
49 static inline bool
50 cmd_result_is_valid (enum cmd_result result)
51 {
52   return (result == CMD_SUCCESS || result == CMD_EOF || result == CMD_FINISH
53           || (result >= CMD_PRIVATE_FIRST && result <= CMD_PRIVATE_LAST)
54           || result == CMD_FAILURE || result == CMD_NOT_IMPLEMENTED
55           || result == CMD_CASCADING_FAILURE);
56 }
57
58 /* Returns true if RESULT indicates success,
59    false otherwise. */
60 bool
61 cmd_result_is_success (enum cmd_result result)
62 {
63   assert (cmd_result_is_valid (result));
64   return result > 0;
65 }
66
67 /* Returns true if RESULT indicates failure,
68    false otherwise. */
69 bool
70 cmd_result_is_failure (enum cmd_result result)
71 {
72   assert (cmd_result_is_valid (result));
73   return result < 0;
74 }
75 \f
76 /* Command processing states. */
77 enum states
78   {
79     S_INITIAL = 0x01,         /* Allowed before active file defined. */
80     S_DATA = 0x02,            /* Allowed after active file defined. */
81     S_INPUT_PROGRAM = 0x04,   /* Allowed in INPUT PROGRAM. */
82     S_FILE_TYPE = 0x08,       /* Allowed in FILE TYPE. */
83     S_ANY = 0x0f              /* Allowed anywhere. */
84   };
85
86 /* Other command requirements. */
87 enum flags
88   {
89     F_ENHANCED = 0x10,        /* Allowed only in enhanced syntax mode. */
90     F_TESTING = 0x20,         /* Allowed only in testing mode. */
91     F_KEEP_FINAL_TOKEN = 0x40,/* Don't skip final token in command name. */
92     F_ABBREV = 0x80           /* Not a candidate for name completion. */
93   };
94
95 /* A single command. */
96 struct command
97   {
98     enum states states;         /* States in which command is allowed. */
99     enum flags flags;           /* Other command requirements. */
100     const char *name;           /* Command name. */
101     int (*function) (struct lexer *, struct dataset *); /* Function to call. */
102   };
103
104 /* Define the command array. */
105 #define DEF_CMD(STATES, FLAGS, NAME, FUNCTION) {STATES, FLAGS, NAME, FUNCTION},
106 #define UNIMPL_CMD(NAME, DESCRIPTION) {S_ANY, 0, NAME, NULL},
107 static const struct command commands[] =
108   {
109 #include "command.def"
110   };
111 #undef DEF_CMD
112 #undef UNIMPL_CMD
113
114 static const size_t command_cnt = sizeof commands / sizeof *commands;
115
116 static bool in_correct_state (const struct command *, enum cmd_state);
117 static bool report_state_mismatch (const struct command *, enum cmd_state);
118 static const struct command *find_command (const char *name);
119 static void set_completion_state (enum cmd_state);
120 \f
121 /* Command parser. */
122
123 static const struct command *parse_command_name (struct lexer *lexer);
124 static enum cmd_result do_parse_command (struct lexer *, struct dataset *, enum cmd_state);
125
126 /* Parses an entire command, from command name to terminating
127    dot.  On failure, skips to the terminating dot.
128    Returns the command's success or failure result. */
129 enum cmd_result
130 cmd_parse_in_state (struct lexer *lexer, struct dataset *ds,
131                     enum cmd_state state)
132 {
133   int result;
134
135   result = do_parse_command (lexer, ds, state);
136
137   assert (!proc_is_open (ds));
138   unset_cmd_algorithm ();
139   dict_clear_aux (dataset_dict (ds));
140   if (!dataset_end_of_command (ds))
141     result = CMD_CASCADING_FAILURE;
142
143   return result;
144 }
145
146 enum cmd_result
147 cmd_parse (struct lexer *lexer, struct dataset *ds)
148 {
149   const struct dictionary *dict = dataset_dict (ds);
150   return cmd_parse_in_state (lexer, ds,
151                              proc_has_active_file (ds) &&
152                              dict_get_var_cnt (dict) > 0 ?
153                              CMD_STATE_DATA : CMD_STATE_INITIAL);
154 }
155
156
157 /* Parses an entire command, from command name to terminating
158    dot. */
159 static enum cmd_result
160 do_parse_command (struct lexer *lexer,
161                   struct dataset *ds, enum cmd_state state)
162 {
163   const struct command *command = NULL;
164   enum cmd_result result;
165   bool opened = false;
166
167   /* Read the command's first token. */
168   prompt_set_style (PROMPT_FIRST);
169   set_completion_state (state);
170   lex_get (lexer);
171   if (lex_token (lexer) == T_STOP)
172     {
173       result = CMD_EOF;
174       goto finish;
175     }
176   else if (lex_token (lexer) == '.')
177     {
178       /* Null commands can result from extra empty lines. */
179       result = CMD_SUCCESS;
180       goto finish;
181     }
182
183   prompt_set_style (PROMPT_LATER);
184
185   /* Parse the command name. */
186   command = parse_command_name (lexer);
187   if (command == NULL)
188     {
189       result = CMD_FAILURE;
190       goto finish;
191     }
192   text_item_submit (text_item_create (TEXT_ITEM_COMMAND_OPEN, command->name));
193   opened = true;
194
195   if (command->function == NULL)
196     {
197       msg (SE, _("%s is not yet implemented."), command->name);
198       result = CMD_NOT_IMPLEMENTED;
199     }
200   else if ((command->flags & F_TESTING) && !settings_get_testing_mode ())
201     {
202       msg (SE, _("%s may be used only in testing mode."), command->name);
203       result = CMD_FAILURE;
204     }
205   else if ((command->flags & F_ENHANCED) && settings_get_syntax () != ENHANCED)
206     {
207       msg (SE, _("%s may be used only in enhanced syntax mode."),
208            command->name);
209       result = CMD_FAILURE;
210     }
211   else if (!in_correct_state (command, state))
212     {
213       report_state_mismatch (command, state);
214       result = CMD_FAILURE;
215     }
216   else
217     {
218       /* Execute command. */
219       result = command->function (lexer, ds);
220     }
221
222   assert (cmd_result_is_valid (result));
223
224  finish:
225   if (cmd_result_is_failure (result))
226     {
227       lex_discard_rest_of_command (lexer);
228       if (source_stream_current_error_mode (
229             lex_get_source_stream (lexer)) == ERRMODE_STOP )
230         {
231           msg (MW, _("Error encountered while ERROR=STOP is effective."));
232           result = CMD_CASCADING_FAILURE;
233         }
234     }
235
236   if (opened)
237     text_item_submit (text_item_create (TEXT_ITEM_COMMAND_CLOSE,
238                                         command->name));
239
240   return result;
241 }
242
243 static size_t
244 match_strings (const char *a, size_t a_len,
245                const char *b, size_t b_len)
246 {
247   size_t match_len = 0;
248
249   while (a_len > 0 && b_len > 0)
250     {
251       /* Mismatch always returns zero. */
252       if (toupper ((unsigned char) *a++) != toupper ((unsigned char) *b++))
253         return 0;
254
255       /* Advance. */
256       a_len--;
257       b_len--;
258       match_len++;
259     }
260
261   return match_len;
262 }
263
264 /* Returns the first character in the first word in STRING,
265    storing the word's length in *WORD_LEN.  If no words remain,
266    returns a null pointer and stores 0 in *WORD_LEN.  Words are
267    sequences of alphanumeric characters or single
268    non-alphanumeric characters.  Words are delimited by
269    spaces. */
270 static const char *
271 find_word (const char *string, size_t *word_len)
272 {
273   /* Skip whitespace and asterisks. */
274   while (isspace ((unsigned char) *string))
275     string++;
276
277   /* End of string? */
278   if (*string == '\0')
279     {
280       *word_len = 0;
281       return NULL;
282     }
283
284   /* Special one-character word? */
285   if (!isalnum ((unsigned char) *string))
286     {
287       *word_len = 1;
288       return string;
289     }
290
291   /* Alphanumeric word. */
292   *word_len = 1;
293   while (isalnum ((unsigned char) string[*word_len]))
294     (*word_len)++;
295
296   return string;
297 }
298
299 /* Returns true if strings A and B can be confused based on
300    their first three letters. */
301 static bool
302 conflicting_3char_prefixes (const char *a, const char *b)
303 {
304   size_t aw_len, bw_len;
305   const char *aw, *bw;
306
307   aw = find_word (a, &aw_len);
308   bw = find_word (b, &bw_len);
309   assert (aw != NULL && bw != NULL);
310
311   /* Words that are the same don't conflict. */
312   if (aw_len == bw_len && !buf_compare_case (aw, bw, aw_len))
313     return false;
314
315   /* Words that are otherwise the same in the first three letters
316      do conflict. */
317   return ((aw_len > 3 && bw_len > 3)
318           || (aw_len == 3 && bw_len > 3)
319           || (bw_len == 3 && aw_len > 3)) && !buf_compare_case (aw, bw, 3);
320 }
321
322 /* Returns true if CMD can be confused with another command
323    based on the first three letters of its first word. */
324 static bool
325 conflicting_3char_prefix_command (const struct command *cmd)
326 {
327   assert (cmd >= commands && cmd < commands + command_cnt);
328
329   return ((cmd > commands
330            && conflicting_3char_prefixes (cmd[-1].name, cmd[0].name))
331           || (cmd < commands + command_cnt
332               && conflicting_3char_prefixes (cmd[0].name, cmd[1].name)));
333 }
334
335 /* Ways that a set of words can match a command name. */
336 enum command_match
337   {
338     MISMATCH,           /* Not a match. */
339     PARTIAL_MATCH,      /* The words begin the command name. */
340     COMPLETE_MATCH      /* The words are the command name. */
341   };
342
343 /* Figures out how well the WORD_CNT words in WORDS match CMD,
344    and returns the appropriate enum value.  If WORDS are a
345    partial match for CMD and the next word in CMD is a dash, then
346    *DASH_POSSIBLE is set to 1 if DASH_POSSIBLE is non-null;
347    otherwise, *DASH_POSSIBLE is unchanged. */
348 static enum command_match
349 cmd_match_words (const struct command *cmd,
350                  char *const words[], size_t word_cnt,
351                  int *dash_possible)
352 {
353   const char *word;
354   size_t word_len;
355   size_t word_idx;
356
357   for (word = find_word (cmd->name, &word_len), word_idx = 0;
358        word != NULL && word_idx < word_cnt;
359        word = find_word (word + word_len, &word_len), word_idx++)
360     if (word_len != strlen (words[word_idx])
361         || buf_compare_case (word, words[word_idx], word_len))
362       {
363         size_t match_chars = match_strings (word, word_len,
364                                             words[word_idx],
365                                             strlen (words[word_idx]));
366         if (match_chars == 0)
367           {
368             /* Mismatch. */
369             return MISMATCH;
370           }
371         else if (match_chars == 1 || match_chars == 2)
372           {
373             /* One- and two-character abbreviations are not
374                acceptable. */
375             return MISMATCH;
376           }
377         else if (match_chars == 3)
378           {
379             /* Three-character abbreviations are acceptable
380                in the first word of a command if there are
381                no name conflicts.  They are always
382                acceptable after the first word. */
383             if (word_idx == 0 && conflicting_3char_prefix_command (cmd))
384               return MISMATCH;
385           }
386         else /* match_chars > 3 */
387           {
388             /* Four-character and longer abbreviations are
389                always acceptable.  */
390           }
391       }
392
393   if (word == NULL && word_idx == word_cnt)
394     {
395       /* cmd->name = "FOO BAR", words[] = {"FOO", "BAR"}. */
396       return COMPLETE_MATCH;
397     }
398   else if (word == NULL)
399     {
400       /* cmd->name = "FOO BAR", words[] = {"FOO", "BAR", "BAZ"}. */
401       return MISMATCH;
402     }
403   else
404     {
405       /* cmd->name = "FOO BAR BAZ", words[] = {"FOO", "BAR"}. */
406       if (word[0] == '-' && dash_possible != NULL)
407         *dash_possible = 1;
408       return PARTIAL_MATCH;
409     }
410 }
411
412 /* Returns the number of commands for which the WORD_CNT words in
413    WORDS are a partial or complete match.  If some partial match
414    has a dash as the next word, then *DASH_POSSIBLE is set to 1,
415    otherwise it is set to 0. */
416 static int
417 count_matching_commands (char *const words[], size_t word_cnt,
418                          int *dash_possible)
419 {
420   const struct command *cmd;
421   int cmd_match_count;
422
423   cmd_match_count = 0;
424   *dash_possible = 0;
425   for (cmd = commands; cmd < commands + command_cnt; cmd++)
426     if (cmd_match_words (cmd, words, word_cnt, dash_possible) != MISMATCH)
427       cmd_match_count++;
428
429   return cmd_match_count;
430 }
431
432 /* Returns the command for which the WORD_CNT words in WORDS are
433    a complete match.  Returns a null pointer if no such command
434    exists. */
435 static const struct command *
436 get_complete_match (char *const words[], size_t word_cnt)
437 {
438   const struct command *cmd;
439
440   for (cmd = commands; cmd < commands + command_cnt; cmd++)
441     if (cmd_match_words (cmd, words, word_cnt, NULL) == COMPLETE_MATCH)
442       return cmd;
443
444   return NULL;
445 }
446
447 /* Returns the command with the given exact NAME.
448    Aborts if no such command exists. */
449 static const struct command *
450 find_command (const char *name)
451 {
452   const struct command *cmd;
453
454   for (cmd = commands; cmd < commands + command_cnt; cmd++)
455     if (!strcmp (cmd->name, name))
456       return cmd;
457   NOT_REACHED ();
458 }
459
460 /* Frees the WORD_CNT words in WORDS. */
461 static void
462 free_words (char *words[], size_t word_cnt)
463 {
464   size_t idx;
465
466   for (idx = 0; idx < word_cnt; idx++)
467     free (words[idx]);
468 }
469
470 /* Flags an error that the command whose name is given by the
471    WORD_CNT words in WORDS is unknown. */
472 static void
473 unknown_command_error (struct lexer *lexer, char *const words[], size_t word_cnt)
474 {
475   if (word_cnt == 0)
476     lex_error (lexer, _("expecting command name"));
477   else
478     {
479       struct string s;
480       size_t i;
481
482       ds_init_empty (&s);
483       for (i = 0; i < word_cnt; i++)
484         {
485           if (i != 0)
486             ds_put_char (&s, ' ');
487           ds_put_cstr (&s, words[i]);
488         }
489
490       msg (SE, _("Unknown command %s."), ds_cstr (&s));
491
492       ds_destroy (&s);
493     }
494 }
495
496 /* Parse the command name and return a pointer to the corresponding
497    struct command if successful.
498    If not successful, return a null pointer. */
499 static const struct command *
500 parse_command_name (struct lexer *lexer)
501 {
502   char *words[16];
503   int word_cnt;
504   int complete_word_cnt;
505   int dash_possible;
506
507   if (lex_token (lexer) == T_EXP ||
508                   lex_token (lexer) == '*' || lex_token (lexer) == '[')
509     return find_command ("COMMENT");
510
511   dash_possible = 0;
512   word_cnt = complete_word_cnt = 0;
513   while (lex_token (lexer) == T_ID || (dash_possible && lex_token (lexer) == '-'))
514     {
515       int cmd_match_cnt;
516
517       assert (word_cnt < sizeof words / sizeof *words);
518       if (lex_token (lexer) == T_ID)
519         {
520           words[word_cnt] = ds_xstrdup (lex_tokstr (lexer));
521           str_uppercase (words[word_cnt]);
522         }
523       else if (lex_token (lexer) == '-')
524         words[word_cnt] = xstrdup ("-");
525       word_cnt++;
526
527       cmd_match_cnt = count_matching_commands (words, word_cnt,
528                                                &dash_possible);
529       if (cmd_match_cnt == 0)
530         break;
531       else if (cmd_match_cnt == 1)
532         {
533           const struct command *command = get_complete_match (words, word_cnt);
534           if (command != NULL)
535             {
536               if (!(command->flags & F_KEEP_FINAL_TOKEN))
537                 lex_get (lexer);
538               free_words (words, word_cnt);
539               return command;
540             }
541         }
542       else /* cmd_match_cnt > 1 */
543         {
544           /* Do we have a complete command name so far? */
545           if (get_complete_match (words, word_cnt) != NULL)
546             complete_word_cnt = word_cnt;
547         }
548       lex_get (lexer);
549     }
550
551   /* If we saw a complete command name earlier, drop back to
552      it. */
553   if (complete_word_cnt)
554     {
555       int pushback_word_cnt;
556       const struct command *command;
557
558       /* Get the command. */
559       command = get_complete_match (words, complete_word_cnt);
560       assert (command != NULL);
561
562       /* Figure out how many words we want to keep.
563          We normally want to swallow the entire command. */
564       pushback_word_cnt = complete_word_cnt + 1;
565       if (command->flags & F_KEEP_FINAL_TOKEN)
566         pushback_word_cnt--;
567
568       /* FIXME: We only support one-token pushback. */
569       assert (pushback_word_cnt + 1 >= word_cnt);
570
571       while (word_cnt > pushback_word_cnt)
572         {
573           word_cnt--;
574           if (strcmp (words[word_cnt], "-"))
575             lex_put_back_id (lexer, words[word_cnt]);
576           else
577             lex_put_back (lexer, '-');
578           free (words[word_cnt]);
579         }
580
581       free_words (words, word_cnt);
582       return command;
583     }
584
585   /* We didn't get a valid command name. */
586   unknown_command_error (lexer, words, word_cnt);
587   free_words (words, word_cnt);
588   return NULL;
589 }
590
591 /* Returns true if COMMAND is allowed in STATE,
592    false otherwise. */
593 static bool
594 in_correct_state (const struct command *command, enum cmd_state state)
595 {
596   return ((state == CMD_STATE_INITIAL && command->states & S_INITIAL)
597           || (state == CMD_STATE_DATA && command->states & S_DATA)
598           || (state == CMD_STATE_INPUT_PROGRAM
599               && command->states & S_INPUT_PROGRAM)
600           || (state == CMD_STATE_FILE_TYPE && command->states & S_FILE_TYPE));
601 }
602
603 /* Emits an appropriate error message for trying to invoke
604    COMMAND in STATE. */
605 static bool
606 report_state_mismatch (const struct command *command, enum cmd_state state)
607 {
608   assert (!in_correct_state (command, state));
609   if (state == CMD_STATE_INITIAL || state == CMD_STATE_DATA)
610     {
611       switch (command->states)
612         {
613           /* One allowed state. */
614         case S_INITIAL:
615           msg (SE, _("%s is allowed only before the active file has "
616                      "been defined."), command->name);
617           break;
618         case S_DATA:
619           msg (SE, _("%s is allowed only after the active file has "
620                      "been defined."), command->name);
621           break;
622         case S_INPUT_PROGRAM:
623           msg (SE, _("%s is allowed only inside INPUT PROGRAM."),
624                command->name);
625           break;
626         case S_FILE_TYPE:
627           msg (SE, _("%s is allowed only inside FILE TYPE."), command->name);
628           break;
629
630           /* Two allowed states. */
631         case S_INITIAL | S_DATA:
632           NOT_REACHED ();
633         case S_INITIAL | S_INPUT_PROGRAM:
634           msg (SE, _("%s is allowed only before the active file has "
635                      "been defined or inside INPUT PROGRAM."), command->name);
636           break;
637         case S_INITIAL | S_FILE_TYPE:
638           msg (SE, _("%s is allowed only before the active file has "
639                      "been defined or inside FILE TYPE."), command->name);
640           break;
641         case S_DATA | S_INPUT_PROGRAM:
642           msg (SE, _("%s is allowed only after the active file has "
643                      "been defined or inside INPUT PROGRAM."), command->name);
644           break;
645         case S_DATA | S_FILE_TYPE:
646           msg (SE, _("%s is allowed only after the active file has "
647                      "been defined or inside FILE TYPE."), command->name);
648           break;
649         case S_INPUT_PROGRAM | S_FILE_TYPE:
650           msg (SE, _("%s is allowed only inside INPUT PROGRAM "
651                      "or inside FILE TYPE."), command->name);
652           break;
653
654           /* Three allowed states. */
655         case S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE:
656           msg (SE, _("%s is allowed only after the active file has "
657                      "been defined, inside INPUT PROGRAM, or inside "
658                      "FILE TYPE."), command->name);
659           break;
660         case S_INITIAL | S_INPUT_PROGRAM | S_FILE_TYPE:
661           msg (SE, _("%s is allowed only before the active file has "
662                      "been defined, inside INPUT PROGRAM, or inside "
663                      "FILE TYPE."), command->name);
664           break;
665         case S_INITIAL | S_DATA | S_FILE_TYPE:
666           NOT_REACHED ();
667         case S_INITIAL | S_DATA | S_INPUT_PROGRAM:
668           NOT_REACHED ();
669
670           /* Four allowed states. */
671         case S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE:
672           NOT_REACHED ();
673
674         default:
675           NOT_REACHED ();
676         }
677     }
678   else if (state == CMD_STATE_INPUT_PROGRAM)
679     msg (SE, _("%s is not allowed inside %s."), command->name, "INPUT PROGRAM" );
680   else if (state == CMD_STATE_FILE_TYPE)
681     msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE");
682
683   return false;
684 }
685 \f
686 /* Command name completion. */
687
688 static enum cmd_state completion_state = CMD_STATE_INITIAL;
689
690 static void
691 set_completion_state (enum cmd_state state)
692 {
693   completion_state = state;
694 }
695
696 /* Returns the next possible completion of a command name that
697    begins with PREFIX, in the current command state, or a null
698    pointer if no completions remain.
699    Before calling the first time, set *CMD to a null pointer. */
700 const char *
701 cmd_complete (const char *prefix, const struct command **cmd)
702 {
703   if (*cmd == NULL)
704     *cmd = commands;
705
706   for (; *cmd < commands + command_cnt; (*cmd)++)
707     if (!memcasecmp ((*cmd)->name, prefix, strlen (prefix))
708         && (!((*cmd)->flags & F_TESTING) || settings_get_testing_mode ())
709         && (!((*cmd)->flags & F_ENHANCED) || settings_get_syntax () == ENHANCED)
710         && !((*cmd)->flags & F_ABBREV)
711         && ((*cmd)->function != NULL)
712         && in_correct_state (*cmd, completion_state))
713       return (*cmd)++->name;
714
715   return NULL;
716 }
717 \f
718 /* Simple commands. */
719
720 /* Parse and execute FINISH command. */
721 int
722 cmd_finish (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
723 {
724   return CMD_FINISH;
725 }
726
727 /* Parses the N command. */
728 int
729 cmd_n_of_cases (struct lexer *lexer, struct dataset *ds)
730 {
731   /* Value for N. */
732   int x;
733
734   if (!lex_force_int (lexer))
735     return CMD_FAILURE;
736   x = lex_integer (lexer);
737   lex_get (lexer);
738   if (!lex_match_id (lexer, "ESTIMATED"))
739     dict_set_case_limit (dataset_dict (ds), x);
740
741   return lex_end_of_command (lexer);
742 }
743
744 /* Parses, performs the EXECUTE procedure. */
745 int
746 cmd_execute (struct lexer *lexer, struct dataset *ds)
747 {
748   bool ok = casereader_destroy (proc_open (ds));
749   if (!proc_commit (ds) || !ok)
750     return CMD_CASCADING_FAILURE;
751   return lex_end_of_command (lexer);
752 }
753
754 /* Parses, performs the ERASE command. */
755 int
756 cmd_erase (struct lexer *lexer, struct dataset *ds UNUSED)
757 {
758   if (settings_get_safer_mode ())
759     {
760       msg (SE, _("This command not allowed when the SAFER option is set."));
761       return CMD_FAILURE;
762     }
763
764   if (!lex_force_match_id (lexer, "FILE"))
765     return CMD_FAILURE;
766   lex_match (lexer, '=');
767   if (!lex_force_string (lexer))
768     return CMD_FAILURE;
769
770   if (remove (ds_cstr (lex_tokstr (lexer))) == -1)
771     {
772       msg (SW, _("Error removing `%s': %s."),
773            ds_cstr (lex_tokstr (lexer)), strerror (errno));
774       return CMD_FAILURE;
775     }
776
777   return CMD_SUCCESS;
778 }
779
780 /* Parses, performs the NEW FILE command. */
781 int
782 cmd_new_file (struct lexer *lexer, struct dataset *ds)
783 {
784   proc_discard_active_file (ds);
785
786   return lex_end_of_command (lexer);
787 }
788
789 /* Parses a comment. */
790 int
791 cmd_comment (struct lexer *lexer, struct dataset *ds UNUSED)
792 {
793   lex_skip_comment (lexer);
794   return CMD_SUCCESS;
795 }