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