[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[pre-lexer 07/21] HOST: Use more modern syntax.
From: |
Ben Pfaff |
Subject: |
[pre-lexer 07/21] HOST: Use more modern syntax. |
Date: |
Thu, 23 Sep 2010 21:20:43 -0700 |
An old SPSS paper manual I have describes the syntax that PSPP
implemented for HOST up until this commit, but newer versions
describe the syntax that this commit adopts.
---
NEWS | 4 +-
doc/utilities.texi | 7 ++
src/language/command.c | 158 ++++------------------------------
src/language/command.def | 2 +-
src/language/utilities/automake.mk | 1 +
src/language/utilities/host.c | 167 ++++++++++++++++++++++++++++++++++++
tests/bugs/overwrite-input-file.sh | 2 +-
tests/bugs/signals.sh | 4 +-
8 files changed, 198 insertions(+), 147 deletions(-)
create mode 100644 src/language/utilities/host.c
diff --git a/NEWS b/NEWS
index 921e804..0e64c43 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,5 @@
PSPP NEWS -- history of user-visible changes.
-Time-stamp: <2010-08-29 15:12:21 blp>
+Time-stamp: <2010-09-10 20:46:06 blp>
Copyright (C) 1996-9, 2000, 2008, 2009, 2010 Free Software Foundation, Inc.
See the end for copying conditions.
@@ -14,6 +14,8 @@ Changes from 0.7.3 to 0.7.5:
* The PRESERVE and RESTORE commands are now implemented.
+ * The HOST command has been updated to use more modern syntax.
+
Changes from 0.7.2 to 0.7.3:
* Charts are now produced with Cairo and Pango, instead of libplot.
diff --git a/doc/utilities.texi b/doc/utilities.texi
index d4e7d3d..9f57a76 100644
--- a/doc/utilities.texi
+++ b/doc/utilities.texi
@@ -212,12 +212,19 @@ control to the operating system.
@display
HOST.
+HOST COMMAND=['command'...].
@end display
@cmd{HOST} suspends the current PSPP session and temporarily returns control
to the operating system.
This command cannot be used if the SAFER setting is active.
+If the COMMAND subcommand is specified, as a sequence of shell
+commands as quoted strings within square brackets, then PSPP executes
+them together in a single subshell.
+
+If no subcommands are specified, then PSPP invokes an interactive
+subshell.
@node INCLUDE
@section INCLUDE
diff --git a/src/language/command.c b/src/language/command.c
index 448fae7..9f90db9 100644
--- a/src/language/command.c
+++ b/src/language/command.c
@@ -1,5 +1,5 @@
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2009 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
@@ -16,34 +16,26 @@
#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>
-#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/message.h>
-#include <libpspp/str.h>
-#include <libpspp/getl.h>
-#include <output/text-item.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/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"
@@ -785,124 +777,6 @@ cmd_erase (struct lexer *lexer, struct dataset *ds UNUSED)
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 = xmalloca (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 (settings_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)
diff --git a/src/language/command.def b/src/language/command.def
index 8400fde..8861d91 100644
--- a/src/language/command.def
+++ b/src/language/command.def
@@ -24,7 +24,7 @@ DEF_CMD (S_ANY, 0, "EXIT", cmd_finish)
DEF_CMD (S_ANY, 0, "FILE HANDLE", cmd_file_handle)
DEF_CMD (S_ANY, F_KEEP_FINAL_TOKEN, "FILE LABEL", cmd_file_label)
DEF_CMD (S_ANY, 0, "FINISH", cmd_finish)
-DEF_CMD (S_ANY, F_KEEP_FINAL_TOKEN, "HOST", cmd_host)
+DEF_CMD (S_ANY, 0, "HOST", cmd_host)
DEF_CMD (S_ANY, 0, "INCLUDE", cmd_include)
DEF_CMD (S_ANY, 0, "INSERT", cmd_insert)
DEF_CMD (S_ANY, 0, "N OF CASES", cmd_n_of_cases)
diff --git a/src/language/utilities/automake.mk
b/src/language/utilities/automake.mk
index c4ca92b..3a3e16d 100644
--- a/src/language/utilities/automake.mk
+++ b/src/language/utilities/automake.mk
@@ -8,6 +8,7 @@ language_utilities_sources = \
src/language/utilities/cd.c \
src/language/utilities/date.c \
src/language/utilities/echo.c \
+ src/language/utilities/host.c \
src/language/utilities/title.c \
src/language/utilities/include.c \
src/language/utilities/permissions.c
diff --git a/src/language/utilities/host.c b/src/language/utilities/host.c
new file mode 100644
index 0000000..ae34436
--- /dev/null
+++ b/src/language/utilities/host.c
@@ -0,0 +1,167 @@
+/* PSPP - a program for statistical analysis.
+ 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include "data/settings.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
+#include "gl/xmalloca.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+#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 = xmalloca (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;
+}
+
+int
+cmd_host (struct lexer *lexer, struct dataset *ds UNUSED)
+{
+ if (settings_get_safer_mode ())
+ {
+ msg (SE, _("This command not allowed when the SAFER option is set."));
+ return CMD_FAILURE;
+ }
+
+ if (lex_token (lexer) == '.')
+ return shell () ? CMD_SUCCESS : CMD_FAILURE;
+ else if (lex_match_id (lexer, "COMMAND"))
+ {
+ struct string command;
+ bool ok;
+
+ lex_match (lexer, '=');
+ if (!lex_force_match (lexer, '['))
+ return CMD_FAILURE;
+
+ ds_init_empty (&command);
+ while (lex_token (lexer) == T_STRING)
+ {
+ if (!ds_is_empty (&command))
+ ds_put_char (&command, '\n');
+ ds_put_substring (&command, ds_ss (lex_tokstr (lexer)));
+ lex_get (lexer);
+ }
+ if (!lex_force_match (lexer, ']'))
+ {
+ ds_destroy (&command);
+ return CMD_FAILURE;
+ }
+
+ ok = run_command (ds_cstr (&command));
+ ds_destroy (&command);
+
+ return ok ? lex_end_of_command (lexer) : CMD_FAILURE;
+ }
+ else
+ {
+ lex_error (lexer, NULL);
+ return CMD_FAILURE;
+ }
+}
diff --git a/tests/bugs/overwrite-input-file.sh
b/tests/bugs/overwrite-input-file.sh
index cbb29b4..f1beabc 100755
--- a/tests/bugs/overwrite-input-file.sh
+++ b/tests/bugs/overwrite-input-file.sh
@@ -98,7 +98,7 @@ COMPUTE Y = X + 1.
XSAVE OUTFILE='foo.sav'.
XEXPORT OUTFILE='foo.por'.
PRINT OUTFILE='foo.data'.
-HOST kill -TERM \$PPID
+HOST COMMAND=['kill -TERM \$PPID'].
EOF
if [ $? -ne 0 ] ; then no_result ; fi
diff --git a/tests/bugs/signals.sh b/tests/bugs/signals.sh
index f46c4de..20ca070 100755
--- a/tests/bugs/signals.sh
+++ b/tests/bugs/signals.sh
@@ -59,7 +59,7 @@ mkdir -p $TEMPDIR
cd $TEMPDIR
activity="sending SIGINT to pspp"
-echo 'host kill -INT $PPID' | $PSPP -o pspp.csv > /dev/null 2> $TEMPDIR/stderr1
+echo 'host command=["kill -INT $PPID"].' | $PSPP -o pspp.csv > /dev/null 2>
$TEMPDIR/stderr1
if [ $? -ne 0 ] ; then no_result ; fi
# SIGINT should have caused a clean shutdown
@@ -68,7 +68,7 @@ activity="checking for absence of error messages 1"
if [ $? -ne 0 ] ; then fail ; fi
activity="sending SIGSEGV to pspp"
-echo 'host kill -SEGV $PPID' | $PSPP -o pspp.csv > /dev/null 2>
$TEMPDIR/stderr2
+echo 'host command=["kill -SEGV $PPID"].' | $PSPP -o pspp.csv > /dev/null 2>
$TEMPDIR/stderr2
if [ $? -eq 0 ] ; then no_result ; fi
# SIGSEGV should have caused an error message
--
1.7.1
- [pre-lexer 02/21] i18n: Use UTF8 macro instead of "UTF8" literal string., (continued)
- [pre-lexer 02/21] i18n: Use UTF8 macro instead of "UTF8" literal string., Ben Pfaff, 2010/09/24
- [pre-lexer 09/21] lexer: Improve translatability of lex_error()., Ben Pfaff, 2010/09/24
- [pre-lexer 15/21] message: Consistently initialize locator; use 0 for "no line number"., Ben Pfaff, 2010/09/24
- [pre-lexer 06/21] AGGREGATE: Simplify code., Ben Pfaff, 2010/09/24
- [pre-lexer 17/21] calendar: Use sensible error reporting in calendar_gregorian_to_offset()., Ben Pfaff, 2010/09/24
- [pre-lexer 16/21] message: Add column range to struct msg_locator., Ben Pfaff, 2010/09/24
- [pre-lexer 05/21] PERMISSIONS: Add missing check for string token., Ben Pfaff, 2010/09/24
- [pre-lexer 10/21] lexer: Remove DUMP_TOKENS debugging feature., Ben Pfaff, 2010/09/24
- [pre-lexer 18/21] data-in: Eliminate "implied_decimals" parameter from data_in()., Ben Pfaff, 2010/09/24
- [pre-lexer 21/21] data-in: Get rid of first_column, last_column arguments., Ben Pfaff, 2010/09/24
- [pre-lexer 07/21] HOST: Use more modern syntax.,
Ben Pfaff <=
- Re: [pre-lexer 00/21] preparation for work on lexer, John Darrington, 2010/09/24