Reduce platform dependence.
[pspp-builds.git] / src / language / command.c
index f98277aa75048f665c33c0bde1646d70701ecd08..70d5b02e747416e9f08554d4c57868196aef3812 100644 (file)
@@ -1,6 +1,5 @@
 /* PSPP - computes sample statistics.
    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
-   Written by Ben Pfaff <blp@gnu.org>.
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -32,7 +31,7 @@
 #include <data/settings.h>
 #include <data/variable.h>
 #include <language/lexer/lexer.h>
-#include <language/line-buffer.h>
+#include <language/prompt.h>
 #include <libpspp/alloc.h>
 #include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
@@ -108,7 +107,7 @@ struct command
     enum states states;         /* States in which command is allowed. */
     enum flags flags;           /* Other command requirements. */
     const char *name;          /* Command name. */
-    int (*function) (struct dataset *);        /* Function to call. */
+    int (*function) (struct lexer *, struct dataset *);        /* Function to call. */
   };
 
 /* Define the command array. */
@@ -130,22 +129,23 @@ static void set_completion_state (enum cmd_state);
 \f
 /* Command parser. */
 
-static const struct command *parse_command_name (void);
-static enum cmd_result do_parse_command (struct dataset *ds, enum cmd_state);
+static const struct command *parse_command_name (struct lexer *lexer);
+static enum cmd_result do_parse_command (struct lexer *, struct dataset *, enum cmd_state);
 
 /* Parses an entire command, from command name to terminating
    dot.  On failure, skips to the terminating dot.
    Returns the command's success or failure result. */
 enum cmd_result
-cmd_parse (struct dataset *ds, enum cmd_state state) 
+cmd_parse_in_state (struct lexer *lexer, struct dataset *ds,
+                   enum cmd_state state)
 {
   int result;
-  
+
   som_new_series ();
 
-  result = do_parse_command (ds, state);
-  if (cmd_result_is_failure (result)) 
-    lex_discard_rest_of_command ();
+  result = do_parse_command (lexer, ds, state);
+  if (cmd_result_is_failure (result))
+    lex_discard_rest_of_command (lexer);
 
   unset_cmd_algorithm ();
   dict_clear_aux (dataset_dict (ds));
@@ -153,29 +153,40 @@ cmd_parse (struct dataset *ds, enum cmd_state state)
   return result;
 }
 
+enum cmd_result
+cmd_parse (struct lexer *lexer, struct dataset *ds)
+{
+  const struct dictionary *dict = dataset_dict (ds);
+  return cmd_parse_in_state (lexer, ds,
+                            proc_has_source (ds) &&
+                            dict_get_var_cnt (dict) > 0 ?
+                            CMD_STATE_DATA : CMD_STATE_INITIAL);
+}
+
+
 /* Parses an entire command, from command name to terminating
    dot. */
 static enum cmd_result
-do_parse_command (struct dataset *ds, enum cmd_state state)
+do_parse_command (struct lexer *lexer, struct dataset *ds, enum cmd_state state)
 {
   const struct command *command;
   enum cmd_result result;
 
   /* Read the command's first token. */
-  getl_set_prompt_style (GETL_PROMPT_FIRST);
+  prompt_set_style (PROMPT_FIRST);
   set_completion_state (state);
-  lex_get ();
-  if (token == T_STOP)
+  lex_get (lexer);
+  if (lex_token (lexer) == T_STOP)
     return CMD_EOF;
-  else if (token == '.') 
+  else if (lex_token (lexer) == '.') 
     {
       /* Null commands can result from extra empty lines. */
       return CMD_SUCCESS; 
     }
-  getl_set_prompt_style (GETL_PROMPT_LATER);
+  prompt_set_style (PROMPT_LATER);
 
   /* Parse the command name. */
-  command = parse_command_name ();
+  command = parse_command_name (lexer);
   if (command == NULL)
     return CMD_FAILURE;
   else if (command->function == NULL) 
@@ -203,7 +214,7 @@ do_parse_command (struct dataset *ds, enum cmd_state state)
   /* Execute command. */
   msg_set_command_name (command->name);
   tab_set_command_name (command->name);
-  result = command->function (ds);
+  result = command->function (lexer, ds);
   tab_set_command_name (NULL);
   msg_set_command_name (NULL);
     
@@ -441,10 +452,10 @@ free_words (char *words[], size_t word_cnt)
 /* Flags an error that the command whose name is given by the
    WORD_CNT words in WORDS is unknown. */
 static void
-unknown_command_error (char *const words[], size_t word_cnt) 
+unknown_command_error (struct lexer *lexer, char *const words[], size_t word_cnt) 
 {
   if (word_cnt == 0) 
-    lex_error (_("expecting command name"));
+    lex_error (lexer, _("expecting command name"));
   else 
     {
       struct string s;
@@ -468,29 +479,30 @@ unknown_command_error (char *const words[], size_t word_cnt)
    struct command if successful.
    If not successful, return a null pointer. */
 static const struct command *
-parse_command_name (void)
+parse_command_name (struct lexer *lexer)
 {
   char *words[16];
   int word_cnt;
   int complete_word_cnt;
   int dash_possible;
 
-  if (token == T_EXP || token == '*' || token == '[') 
+  if (lex_token (lexer) == T_EXP || 
+                 lex_token (lexer) == '*' || lex_token (lexer) == '[') 
     return find_command ("COMMENT");
 
   dash_possible = 0;
   word_cnt = complete_word_cnt = 0;
-  while (token == T_ID || (dash_possible && token == '-')) 
+  while (lex_token (lexer) == T_ID || (dash_possible && lex_token (lexer) == '-')) 
     {
       int cmd_match_cnt;
       
       assert (word_cnt < sizeof words / sizeof *words);
-      if (token == T_ID) 
+      if (lex_token (lexer) == T_ID) 
         {
-          words[word_cnt] = ds_xstrdup (&tokstr);
+          words[word_cnt] = ds_xstrdup (lex_tokstr (lexer));
           str_uppercase (words[word_cnt]); 
         }
-      else if (token == '-')
+      else if (lex_token (lexer) == '-')
         words[word_cnt] = xstrdup ("-");
       word_cnt++;
 
@@ -504,7 +516,7 @@ parse_command_name (void)
           if (command != NULL) 
             {
               if (!(command->flags & F_KEEP_FINAL_TOKEN))
-                lex_get ();
+                lex_get (lexer);
               free_words (words, word_cnt);
               return command;
             }
@@ -515,7 +527,7 @@ parse_command_name (void)
           if (get_complete_match (words, word_cnt) != NULL)
             complete_word_cnt = word_cnt;
         }
-      lex_get ();
+      lex_get (lexer);
     }
 
   /* If we saw a complete command name earlier, drop back to
@@ -542,9 +554,9 @@ parse_command_name (void)
         {
           word_cnt--;
           if (strcmp (words[word_cnt], "-")) 
-            lex_put_back_id (words[word_cnt]);
+            lex_put_back_id (lexer, words[word_cnt]);
           else
-            lex_put_back ('-');
+            lex_put_back (lexer, '-');
           free (words[word_cnt]);
         }
 
@@ -553,7 +565,7 @@ parse_command_name (void)
     }
 
   /* We didn't get a valid command name. */
-  unknown_command_error (words, word_cnt);
+  unknown_command_error (lexer, words, word_cnt);
   free_words (words, word_cnt);
   return NULL;
 }
@@ -649,40 +661,40 @@ cmd_complete (const char *prefix, const struct command **cmd)
 
 /* Parse and execute FINISH command. */
 int
-cmd_finish (struct dataset *ds UNUSED)
+cmd_finish (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
 {
   return CMD_FINISH;
 }
 
 /* Parses the N command. */
 int
-cmd_n_of_cases (struct dataset *ds)
+cmd_n_of_cases (struct lexer *lexer, struct dataset *ds)
 {
   /* Value for N. */
   int x;
 
-  if (!lex_force_int ())
+  if (!lex_force_int (lexer))
     return CMD_FAILURE;
-  x = lex_integer ();
-  lex_get ();
-  if (!lex_match_id ("ESTIMATED"))
+  x = lex_integer (lexer);
+  lex_get (lexer);
+  if (!lex_match_id (lexer, "ESTIMATED"))
     dict_set_case_limit (dataset_dict (ds), x);
 
-  return lex_end_of_command ();
+  return lex_end_of_command (lexer);
 }
 
 /* Parses, performs the EXECUTE procedure. */
 int
-cmd_execute (struct dataset *ds)
+cmd_execute (struct lexer *lexer, struct dataset *ds)
 {
   if (!procedure (ds, NULL, NULL))
     return CMD_CASCADING_FAILURE;
-  return lex_end_of_command ();
+  return lex_end_of_command (lexer);
 }
 
 /* Parses, performs the ERASE command. */
 int
-cmd_erase (struct dataset *ds UNUSED)
+cmd_erase (struct lexer *lexer, struct dataset *ds UNUSED)
 {
   if (get_safer_mode ()) 
     { 
@@ -690,25 +702,25 @@ cmd_erase (struct dataset *ds UNUSED)
       return CMD_FAILURE; 
     } 
   
-  if (!lex_force_match_id ("FILE"))
+  if (!lex_force_match_id (lexer, "FILE"))
     return CMD_FAILURE;
-  lex_match ('=');
-  if (!lex_force_string ())
+  lex_match (lexer, '=');
+  if (!lex_force_string (lexer))
     return CMD_FAILURE;
 
-  if (remove (ds_cstr (&tokstr)) == -1)
+  if (remove (ds_cstr (lex_tokstr (lexer))) == -1)
     {
       msg (SW, _("Error removing `%s': %s."),
-          ds_cstr (&tokstr), strerror (errno));
+          ds_cstr (lex_tokstr (lexer)), strerror (errno));
       return CMD_FAILURE;
     }
 
   return CMD_SUCCESS;
 }
 
-#ifdef unix
-/* Spawn a shell process. */
-static int
+#if HAVE_FORK && HAVE_EXECL
+/* Spawn an interactive shell process. */
+static bool
 shell (void)
 {
   int pid;
@@ -749,71 +761,48 @@ shell (void)
 
     case -1:
       msg (SE, _("Couldn't fork: %s."), strerror (errno));
-      return 0;
+      return false;
 
     default:
       assert (pid > 0);
       while (wait (NULL) != pid)
        ;
-      return 1;
+      return true;
     }
 }
-#endif /* unix */
-
-/* Parses the HOST command argument and executes the specified
-   command.  Returns a suitable command return code. */
-static int
-run_command (void)
+#else /* !(HAVE_FORK && HAVE_EXECL) */
+/* Don't know how to spawn an interactive shell. */
+static bool
+shell (void)
 {
-  const char *cmd;
-  int string;
-
-  /* Handle either a string argument or a full-line argument. */
-  {
-    int c = lex_look_ahead ();
+  msg (SE, _("Interactive shell not supported on this platform."));
+  return false;
+}
+#endif
 
-    if (c == '\'' || c == '"')
-      {
-       lex_get ();
-       if (!lex_force_string ())
-         return CMD_FAILURE;
-       cmd = ds_cstr (&tokstr);
-       string = 1;
-      }
-    else
-      {
-       cmd = lex_rest_of_line (NULL);
-        lex_discard_line ();
-       string = 0;
-      }
-  }
+/* Executes the specified COMMAND in a subshell.  Returns true if
+   successful, false otherwise. */
+static bool
+run_command (const char *command)
+{
+  if (system (NULL) == 0) 
+    {
+      msg (SE, _("Command shell not supported on this platform."));
+      return false;
+    }
 
   /* Execute the command. */
-  if (system (cmd) == -1)
+  if (system (command) == -1)
     msg (SE, _("Error executing command: %s."), strerror (errno));
 
-  /* Finish parsing. */
-  if (string)
-    {
-      lex_get ();
-
-      if (token != '.')
-       {
-         lex_error (_("expecting end of command"));
-         return CMD_FAILURE;
-       }
-    }
-  else
-    token = '.';
-
-  return CMD_SUCCESS;
+  return true;
 }
 
 /* Parses, performs the HOST command. */
 int
-cmd_host (struct dataset *ds UNUSED)
+cmd_host (struct lexer *lexer, struct dataset *ds UNUSED)
 {
-  int code;
+  int look_ahead;
 
   if (get_safer_mode ()) 
     { 
@@ -821,44 +810,45 @@ cmd_host (struct dataset *ds UNUSED)
       return CMD_FAILURE; 
     } 
 
-#ifdef unix
-  /* Figure out whether to invoke an interactive shell or to execute a
-     single shell command. */
-  if (lex_look_ahead () == '.')
+  look_ahead = lex_look_ahead (lexer);
+  if (look_ahead == '.') 
     {
-      lex_get ();
-      code = shell () ? CMD_FAILURE : CMD_SUCCESS;
+      lex_get (lexer);
+      return shell () ? CMD_SUCCESS : CMD_FAILURE;
     }
-  else
-    code = run_command ();
-#else /* !unix */
-  /* Make sure that the system has a command interpreter, then run a
-     command. */
-  if (system (NULL) != 0)
-    code = run_command ();
-  else
+  else if (look_ahead == '\'' || look_ahead == '"')
     {
-      msg (SE, _("No operating system support for this command."));
-      code = CMD_FAILURE;
-    }
-#endif /* !unix */
+      bool ok;
+      
+      lex_get (lexer);
+      if (!lex_force_string (lexer))
+        NOT_REACHED ();
+      ok = run_command (ds_cstr (lex_tokstr (lexer)));
 
-  return code;
+      lex_get (lexer);
+      return ok ? lex_end_of_command (lexer) : CMD_FAILURE;
+    }
+  else 
+    {
+      bool ok = run_command (lex_rest_of_line (lexer, NULL));
+      lex_discard_line (lexer);
+      return ok ? CMD_SUCCESS : CMD_FAILURE;
+    }
 }
 
 /* Parses, performs the NEW FILE command. */
 int
-cmd_new_file (struct dataset *ds)
+cmd_new_file (struct lexer *lexer, struct dataset *ds)
 {
   discard_variables (ds);
 
-  return lex_end_of_command ();
+  return lex_end_of_command (lexer);
 }
 
 /* Parses a comment. */
 int
-cmd_comment (struct dataset *ds UNUSED)
+cmd_comment (struct lexer *lexer, struct dataset *ds UNUSED)
 {
-  lex_skip_comment ();
+  lex_skip_comment (lexer);
   return CMD_SUCCESS;
 }