/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2009, 2010 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 <config.h>
-#include <language/command.h>
+#include "language/command.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
-#include <unistd.h>
-
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <data/variable.h>
-#include <language/lexer/lexer.h>
-#include <language/prompt.h>
-#include <libpspp/alloc.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <output/manager.h>
-#include <output/table.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 "data/procedure.h"
+#include "data/settings.h"
+#include "data/variable.h"
+#include "language/lexer/lexer.h"
+#include "language/prompt.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+#include "libpspp/getl.h"
+#include "output/text-item.h"
+
+#include "xalloc.h"
+#include "xmalloca.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
{
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 ();
/* Parses an entire command, from command name to terminating
dot. */
static enum cmd_result
-do_parse_command (struct lexer *lexer, struct dataset *ds, enum cmd_state state)
+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);
set_completion_state (state);
lex_get (lexer);
if (lex_token (lexer) == T_STOP)
- return CMD_EOF;
+ {
+ result = CMD_EOF;
+ goto finish;
+ }
else if (lex_token (lexer) == '.')
{
/* Null commands can result from extra empty lines. */
- return CMD_SUCCESS;
+ result = CMD_SUCCESS;
+ goto finish;
}
+
prompt_set_style (PROMPT_LATER);
/* Parse the command name. */
command = parse_command_name (lexer);
if (command == NULL)
- return CMD_FAILURE;
- else if (command->function == NULL)
{
- msg (SE, _("%s is unimplemented."), command->name);
- return CMD_NOT_IMPLEMENTED;
+ result = CMD_FAILURE;
+ goto finish;
}
- else if ((command->flags & F_TESTING) && !get_testing_mode ())
+ text_item_submit (text_item_create (TEXT_ITEM_COMMAND_OPEN, command->name));
+ opened = true;
+
+ if (command->function == NULL)
+ {
+ msg (SE, _("%s is not yet implemented."), command->name);
+ result = CMD_NOT_IMPLEMENTED;
+ }
+ else if ((command->flags & F_TESTING) && !settings_get_testing_mode ())
{
msg (SE, _("%s may be used only in testing mode."), command->name);
- return CMD_FAILURE;
+ result = CMD_FAILURE;
}
- 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);
- return CMD_FAILURE;
+ result = CMD_FAILURE;
}
else if (!in_correct_state (command, state))
{
report_state_mismatch (command, state);
- return CMD_FAILURE;
+ result = CMD_FAILURE;
+ }
+ else
+ {
+ /* Execute command. */
+ result = command->function (lexer, ds);
}
-
- /* 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);
assert (cmd_result_is_valid (result));
+
+ finish:
+ if (cmd_result_is_failure (result))
+ {
+ 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;
}
for (i = 0; i < word_cnt; i++)
{
if (i != 0)
- ds_put_char (&s, ' ');
+ ds_put_byte (&s, ' ');
ds_put_cstr (&s, words[i]);
}
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;
}
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))
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;
return CMD_SUCCESS;
}
-#if HAVE_FORK && HAVE_EXECL
-/* Spawn an interactive shell process. */
-static bool
-shell (void)
-{
- int pid;
-
- pid = fork ();
- switch (pid)
- {
- case 0:
- {
- const char *shell_fn;
- char *shell_process;
-
- {
- int i;
-
- for (i = 3; i < 20; i++)
- close (i);
- }
-
- shell_fn = getenv ("SHELL");
- if (shell_fn == NULL)
- shell_fn = "/bin/sh";
-
- {
- const char *cp = strrchr (shell_fn, '/');
- cp = cp ? &cp[1] : shell_fn;
- shell_process = local_alloc (strlen (cp) + 8);
- strcpy (shell_process, "-");
- strcat (shell_process, cp);
- if (strcmp (cp, "sh"))
- shell_process[0] = '+';
- }
-
- execl (shell_fn, shell_process, NULL);
-
- _exit (1);
- }
-
- case -1:
- msg (SE, _("Couldn't fork: %s."), strerror (errno));
- return false;
-
- default:
- assert (pid > 0);
- while (wait (NULL) != pid)
- ;
- return true;
- }
-}
-#else /* !(HAVE_FORK && HAVE_EXECL) */
-/* Don't know how to spawn an interactive shell. */
-static bool
-shell (void)
-{
- msg (SE, _("Interactive shell not supported on this platform."));
- return false;
-}
-#endif
-
-/* 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 (command) == -1)
- msg (SE, _("Error executing command: %s."), strerror (errno));
-
- return true;
-}
-
-/* Parses, performs the HOST command. */
-int
-cmd_host (struct lexer *lexer, struct dataset *ds UNUSED)
-{
- int look_ahead;
-
- if (get_safer_mode ())
- {
- msg (SE, _("This command not allowed when the SAFER option is set."));
- return CMD_FAILURE;
- }
-
- look_ahead = lex_look_ahead (lexer);
- if (look_ahead == '.')
- {
- lex_get (lexer);
- return shell () ? CMD_SUCCESS : CMD_FAILURE;
- }
- else if (look_ahead == '\'' || look_ahead == '"')
- {
- bool ok;
-
- lex_get (lexer);
- if (!lex_force_string (lexer))
- NOT_REACHED ();
- ok = run_command (ds_cstr (lex_tokstr (lexer)));
-
- lex_get (lexer);
- return ok ? lex_end_of_command (lexer) : CMD_FAILURE;
- }
- else
- {
- bool ok = run_command (lex_rest_of_line (lexer));
- lex_discard_line (lexer);
- return ok ? CMD_SUCCESS : CMD_FAILURE;
- }
-}
-
/* Parses, performs the NEW FILE command. */
int
cmd_new_file (struct lexer *lexer, struct dataset *ds)