lexer: New function lex_force_match_phrase().
[pspp] / src / language / utilities / host.c
index 1ab7cc1d02eef6a530ddd7159a3dcf342ad159af..22d25c0eb09711e45cf5d07ce4fa84b0ac862416 100644 (file)
@@ -38,7 +38,7 @@
 #include "libpspp/str.h"
 #include "libpspp/string-array.h"
 #include "libpspp/temp-file.h"
-#include "output/text-item.h"
+#include "output/driver.h"
 
 #include "gl/error.h"
 #include "gl/intprops.h"
 #define N_(msgid) msgid
 \f
 #if !HAVE_FORK
+#define TIME_LIMIT_SUPPORTED 0
 static bool
 run_commands (const struct string_array *commands, double time_limit)
 {
-  if (time_limit != DBL_MAX)
-    {
-      msg (SE, _("Time limit not supported on this platform."));
-      return false;
-    }
+  assert (time_limit == DBL_MAX);
 
   for (size_t i = 0; i < commands->n; i++)
     {
@@ -80,6 +77,7 @@ run_commands (const struct string_array *commands, double time_limit)
   return true;
 }
 #else
+#define TIME_LIMIT_SUPPORTED 1
 static bool
 run_command (const char *command, struct timespec timeout)
 {
@@ -122,6 +120,11 @@ run_command (const char *command, struct timespec timeout)
     {
       /* Running in the child. */
 
+#if __GNU__
+      /* Hurd doesn't support inheriting process timers in a way that works. */
+      if (setpgid (0, 0) < 0)
+        error (1, errno, _("Failed to set process group."));
+#else
       /* Set up timeout. */
       if (timeout.tv_sec < TYPE_MAXIMUM (time_t))
         {
@@ -140,6 +143,7 @@ run_command (const char *command, struct timespec timeout)
           if (setitimer (ITIMER_REAL, &it, NULL) < 0)
             error (1, errno, _("Failed to set timeout."));
         }
+#endif
 
       /* Set up file descriptors:
          - /dev/null for stdin
@@ -174,7 +178,15 @@ run_command (const char *command, struct timespec timeout)
   int error = 0;
   for (;;)
     {
-      pid_t retval = waitpid (pid, &status, 0);
+#if __GNU__
+      if (timespec_cmp (current_timespec (), timeout) >= 0)
+        kill (-pid, SIGALRM);
+
+      int flags = WNOHANG;
+#else
+      int flags = 0;
+#endif
+      pid_t retval = waitpid (pid, &status, flags);
       if (retval == pid)
         break;
       else if (retval < 0)
@@ -185,6 +197,10 @@ run_command (const char *command, struct timespec timeout)
               break;
             }
         }
+#if __GNU__
+      else if (retval == 0)
+        sleep (1);
+#endif
       else
         NOT_REACHED ();
     }
@@ -243,7 +259,7 @@ run_command (const char *command, struct timespec timeout)
       if (end > output && end[-1] == '\n')
         end[-1] = '\0';
 
-      text_item_submit (text_item_create_nocopy (TEXT_ITEM_LOG, output));
+      output_log_nocopy (output);
     }
   free (locale_output);
 
@@ -271,13 +287,13 @@ cmd_host (struct lexer *lexer, struct dataset *ds UNUSED)
 {
   if (settings_get_safer_mode ())
     {
-      msg (SE, _("This command not allowed when the %s option is set."), "SAFER");
+      lex_next_error (lexer, -1, -1,
+                      _("This command not allowed when the %s option is set."),
+                      "SAFER");
       return CMD_FAILURE;
     }
 
-  if (!lex_force_match_id (lexer, "COMMAND")
-      || !lex_force_match (lexer, T_EQUALS)
-      || !lex_force_match (lexer, T_LBRACK)
+  if (!lex_force_match_phrase (lexer, "COMMAND=[")
       || !lex_force_string (lexer))
     return CMD_FAILURE;
 
@@ -296,6 +312,7 @@ cmd_host (struct lexer *lexer, struct dataset *ds UNUSED)
   double time_limit = DBL_MAX;
   if (lex_match_id (lexer, "TIMELIMIT"))
     {
+      int time_limit_start = lex_ofs (lexer) - 1;
       if (!lex_force_match (lexer, T_EQUALS)
           || !lex_force_num (lexer))
         {
@@ -306,6 +323,15 @@ cmd_host (struct lexer *lexer, struct dataset *ds UNUSED)
       double num = lex_number (lexer);
       lex_get (lexer);
       time_limit = num < 0.0 ? 0.0 : num;
+
+      int time_limit_end = lex_ofs (lexer) - 1;
+      if (!TIME_LIMIT_SUPPORTED)
+        {
+          lex_ofs_error (lexer, time_limit_start, time_limit_end,
+                         _("Time limit not supported on this platform."));
+          string_array_destroy (&commands);
+          return false;
+        }
     }
 
   enum cmd_result result = lex_end_of_command (lexer);