output: Make errors, warnings, and notes into a new "message_item".
[pspp-builds.git] / src / language / command.c
index 62538c64ff677465e18c25767c79d7aba3bcada3..448fae7ea803463f11a54edbec50a23c816875a4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include <ctype.h>
 #include <errno.h>
 #include <unistd.h>
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#if HAVE_READLINE
+#include <readline/readline.h>
+#endif
 
 #include <data/casereader.h>
 #include <data/dictionary.h>
 #include <libpspp/message.h>
 #include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <output/manager.h>
-#include <output/table.h>
 #include <libpspp/getl.h>
-
-#if HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-
-#if HAVE_READLINE
-#include <readline/readline.h>
-#endif
+#include <output/text-item.h>
 
 #include "xalloc.h"
 #include "xmalloca.h"
@@ -143,11 +140,7 @@ cmd_parse_in_state (struct lexer *lexer, struct dataset *ds,
 {
   int result;
 
-  som_new_series ();
-
   result = do_parse_command (lexer, ds, state);
-  if (cmd_result_is_failure (result))
-    lex_discard_rest_of_command (lexer);
 
   assert (!proc_is_open (ds));
   unset_cmd_algorithm ();
@@ -175,8 +168,9 @@ static enum cmd_result
 do_parse_command (struct lexer *lexer,
                  struct dataset *ds, enum cmd_state state)
 {
-  const struct command *command;
+  const struct command *command = NULL;
   enum cmd_result result;
+  bool opened = false;
 
   /* Read the command's first token. */
   prompt_set_style (PROMPT_FIRST);
@@ -203,53 +197,54 @@ do_parse_command (struct lexer *lexer,
       result = CMD_FAILURE;
       goto finish;
     }
-  else if (command->function == NULL)
+  text_item_submit (text_item_create (TEXT_ITEM_COMMAND_OPEN, command->name));
+  opened = true;
+
+  if (command->function == NULL)
     {
-      msg (SE, _("%s is unimplemented."), command->name);
+      msg (SE, _("%s is not yet implemented."), command->name);
       result = CMD_NOT_IMPLEMENTED;
-      goto finish;
     }
-  else if ((command->flags & F_TESTING) && !get_testing_mode ())
+  else if ((command->flags & F_TESTING) && !settings_get_testing_mode ())
     {
       msg (SE, _("%s may be used only in testing mode."), command->name);
       result = CMD_FAILURE;
-      goto finish;
     }
-  else if ((command->flags & F_ENHANCED) && get_syntax () != ENHANCED)
+  else if ((command->flags & F_ENHANCED) && settings_get_syntax () != ENHANCED)
     {
       msg (SE, _("%s may be used only in enhanced syntax mode."),
            command->name);
       result = CMD_FAILURE;
-      goto finish;
     }
   else if (!in_correct_state (command, state))
     {
       report_state_mismatch (command, state);
       result = CMD_FAILURE;
-      goto finish;
     }
-
-  /* Execute command. */
-  msg_set_command_name (command->name);
-  tab_set_command_name (command->name);
-  result = command->function (lexer, ds);
-  tab_set_command_name (NULL);
-  msg_set_command_name (NULL);
+  else
+    {
+      /* Execute command. */
+      result = command->function (lexer, ds);
+    }
 
   assert (cmd_result_is_valid (result));
 
  finish:
-  if ( cmd_result_is_failure (result))
+  if (cmd_result_is_failure (result))
     {
-      const struct source_stream *cs = lex_get_source_stream (lexer);
-
-      if ( source_stream_current_error_mode (cs) == ERRMODE_STOP )
+      lex_discard_rest_of_command (lexer);
+      if (source_stream_current_error_mode (
+            lex_get_source_stream (lexer)) == ERRMODE_STOP )
        {
          msg (MW, _("Error encountered while ERROR=STOP is effective."));
          result = CMD_CASCADING_FAILURE;
        }
     }
 
+  if (opened)
+    text_item_submit (text_item_create (TEXT_ITEM_COMMAND_CLOSE,
+                                        command->name));
+
   return result;
 }
 
@@ -621,37 +616,77 @@ report_state_mismatch (const struct command *command, enum cmd_state state)
   assert (!in_correct_state (command, state));
   if (state == CMD_STATE_INITIAL || state == CMD_STATE_DATA)
     {
-      const char *allowed[3];
-      int allowed_cnt;
-      char *s;
-
-      allowed_cnt = 0;
-      if (command->states & S_INITIAL)
-        allowed[allowed_cnt++] = _("before the active file has been defined");
-      else if (command->states & S_DATA)
-        allowed[allowed_cnt++] = _("after the active file has been defined");
-      if (command->states & S_INPUT_PROGRAM)
-        allowed[allowed_cnt++] = _("inside INPUT PROGRAM");
-      if (command->states & S_FILE_TYPE)
-        allowed[allowed_cnt++] = _("inside FILE TYPE");
-
-      if (allowed_cnt == 1)
-        s = xstrdup (allowed[0]);
-      else if (allowed_cnt == 2)
-        s = xasprintf (_("%s or %s"), allowed[0], allowed[1]);
-      else if (allowed_cnt == 3)
-        s = xasprintf (_("%s, %s, or %s"), allowed[0], allowed[1], allowed[2]);
-      else
-        NOT_REACHED ();
-
-      msg (SE, _("%s is allowed only %s."), command->name, s);
-
-      free (s);
+      switch (command->states)
+        {
+          /* One allowed state. */
+        case S_INITIAL:
+          msg (SE, _("%s is allowed only before the active file has "
+                     "been defined."), command->name);
+          break;
+        case S_DATA:
+          msg (SE, _("%s is allowed only after the active file has "
+                     "been defined."), command->name);
+          break;
+        case S_INPUT_PROGRAM:
+          msg (SE, _("%s is allowed only inside INPUT PROGRAM."),
+               command->name);
+          break;
+        case S_FILE_TYPE:
+          msg (SE, _("%s is allowed only inside FILE TYPE."), command->name);
+          break;
+
+          /* Two allowed states. */
+        case S_INITIAL | S_DATA:
+          NOT_REACHED ();
+        case S_INITIAL | S_INPUT_PROGRAM:
+          msg (SE, _("%s is allowed only before the active file has "
+                     "been defined or inside INPUT PROGRAM."), command->name);
+          break;
+        case S_INITIAL | S_FILE_TYPE:
+          msg (SE, _("%s is allowed only before the active file has "
+                     "been defined or inside FILE TYPE."), command->name);
+          break;
+        case S_DATA | S_INPUT_PROGRAM:
+          msg (SE, _("%s is allowed only after the active file has "
+                     "been defined or inside INPUT PROGRAM."), command->name);
+          break;
+        case S_DATA | S_FILE_TYPE:
+          msg (SE, _("%s is allowed only after the active file has "
+                     "been defined or inside FILE TYPE."), command->name);
+          break;
+        case S_INPUT_PROGRAM | S_FILE_TYPE:
+          msg (SE, _("%s is allowed only inside INPUT PROGRAM "
+                     "or inside FILE TYPE."), command->name);
+          break;
+
+          /* Three allowed states. */
+        case S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE:
+          msg (SE, _("%s is allowed only after the active file has "
+                     "been defined, inside INPUT PROGRAM, or inside "
+                     "FILE TYPE."), command->name);
+          break;
+        case S_INITIAL | S_INPUT_PROGRAM | S_FILE_TYPE:
+          msg (SE, _("%s is allowed only before the active file has "
+                     "been defined, inside INPUT PROGRAM, or inside "
+                     "FILE TYPE."), command->name);
+          break;
+        case S_INITIAL | S_DATA | S_FILE_TYPE:
+          NOT_REACHED ();
+        case S_INITIAL | S_DATA | S_INPUT_PROGRAM:
+          NOT_REACHED ();
+
+          /* Four allowed states. */
+        case S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE:
+          NOT_REACHED ();
+
+        default:
+          NOT_REACHED ();
+        }
     }
   else if (state == CMD_STATE_INPUT_PROGRAM)
-    msg (SE, _("%s is not allowed inside INPUT PROGRAM."), command->name);
+    msg (SE, _("%s is not allowed inside %s."), command->name, "INPUT PROGRAM" );
   else if (state == CMD_STATE_FILE_TYPE)
-    msg (SE, _("%s is not allowed inside FILE TYPE."), command->name);
+    msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE");
 
   return false;
 }
@@ -678,8 +713,8 @@ cmd_complete (const char *prefix, const struct command **cmd)
 
   for (; *cmd < commands + command_cnt; (*cmd)++)
     if (!memcasecmp ((*cmd)->name, prefix, strlen (prefix))
-        && (!((*cmd)->flags & F_TESTING) || get_testing_mode ())
-        && (!((*cmd)->flags & F_ENHANCED) || get_syntax () == ENHANCED)
+        && (!((*cmd)->flags & F_TESTING) || settings_get_testing_mode ())
+        && (!((*cmd)->flags & F_ENHANCED) || settings_get_syntax () == ENHANCED)
         && !((*cmd)->flags & F_ABBREV)
         && ((*cmd)->function != NULL)
         && in_correct_state (*cmd, completion_state))
@@ -728,7 +763,7 @@ cmd_execute (struct lexer *lexer, struct dataset *ds)
 int
 cmd_erase (struct lexer *lexer, struct dataset *ds UNUSED)
 {
-  if (get_safer_mode ())
+  if (settings_get_safer_mode ())
     {
       msg (SE, _("This command not allowed when the SAFER option is set."));
       return CMD_FAILURE;
@@ -836,7 +871,7 @@ cmd_host (struct lexer *lexer, struct dataset *ds UNUSED)
 {
   int look_ahead;
 
-  if (get_safer_mode ())
+  if (settings_get_safer_mode ())
     {
       msg (SE, _("This command not allowed when the SAFER option is set."));
       return CMD_FAILURE;