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