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