bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

DJGPP specific patch for bison-1.875d


From: Juan Manuel Guerrero
Subject: DJGPP specific patch for bison-1.875d
Date: Tue, 07 Dec 2004 17:07:58 +0200

This is a proposition to port bison to non posix systems like djgpp/msdos.
There are two issues to be treated:
1) output file names
2) fork() to run m4

The first issue is handled in system.h. Using djgpp's pathconf(), the binary
will detect at runtime if long file name support is available (some sort of
win32 OS) or not (msdos/freedos, etc). Depending on the OS used, the posix
extensions (.tab and .output) will be used or the non posix ones (_tab and
.out) will be used. To achive this goal the TAB_EXT and OUTPUT_EXT have been
redefined.

The second issue can only be solved using temporary files. First bison's stdout
is redirected to a temp. file which will gather all output. This file is closed
and reopened as m4 stdin. A second temp file is opened and assigned to m4's
stdout to gather all its output. Then m4 is spawned() and after successfull
return the second temp. file is closed and reopened as bison's stdin.
This is implemented in subpipe.c. The design goal is to have as less as possible
impact in the existing code. subpipe.c has been modified in the following way:

#if HAVE_WORKING_VFORK || HAVE_WORKING_FORK
/*
 *  Here are all the *original* and *unaltered* posix functions: 
 *
 * init_subpipe()
 * create_subpipe()
 * reap_subpipe()
 */
#else /* !HAVE_WORKING_VFORK && !HAVE_WORKING_FORK */
# if __DJGPP__
/*
 *  Here are all the djgpp specific versions of the posix functions: 
 *
 * init_subpipe()
 * create_subpipe()
 * reap_subpipe()
 */
# else /* !__DJGPP__ */
#  error "vfork, fork or an emulation is required."
# endif /* !__DJGPP__ */
#endif /* !HAVE_WORKING_VFORK and !HAVE_WORKING_FORK */

The djgpp specific versions of the posix functions: init_subpipe(),
create_subpipe() and reap_subpipe() use exactly the same arguments
and return types as the posix ones. This is to keep the impact on other
code as minimal possible. To start m4 on non posix systems the output.c
file needs the following adjustment:

#if !HAVE_WORKING_VFORK && !HAVE_WORKING_FORK
  run_m4 (filter_fd);
#endif

in function output_skeleton().


The proposed patch has been tested with bison-1.875 and bison-1.875d on linux
and different types of win32 and plain dos. Because I do not know which the
appropriate cvs trunk is, I have made the patch against 1.875d. The patch is
intended for inspection. Comments, objections, suggestions are welcome.

Regards,
Juan M. Guerrero



2004-12-07  Guerrero, Juan Manuel  <address@hidden>

        * src/system.h [MSDOS]: __DJGPP__ conditional added.  Use pathconf
          to choose POSIX or DOS file extensions at run time.
        * lib/subpipe.c: Use conditionals HAVE_WORKING_VFORK and
          HAVE_WORKING_FORK to select the appropriate versions of the functions
          init_subpipe, create_subpipe and reap_subpipe.
          [HAVE_WORKING_VFORK, HAVE_WORKING_FORK] [__DJGPP__]: implementation
          of DJGPP specific versions of init_subpipe, create_subpipe,
          reap_subpipe and run_m4 to emulate the missing fork/pipe
          functionality on MSDOS.
        * src/output.c (output_skeleton) [HAVE_WORKING_VFORK,
          HAVE_WORKING_FORK]: Call function run_m4 to generate parser output
          file on non posix systems. 
        * lib/subpipe.h [HAVE_WORKING_VFORK, HAVE_WORKING_FORK]: Add run_m4
          declaration on non posix systems.



diff -apruNU5 bison-1.875d.orig/lib/subpipe.c bison-1.875d/lib/subpipe.c
--- bison-1.875d.orig/lib/subpipe.c     2004-04-28 06:30:04.000000000 +0000
+++ bison-1.875d/lib/subpipe.c  2004-12-07 15:42:00.000000000 +0000
@@ -71,10 +71,12 @@
 
 #include "gettext.h"
 #define _(Msgid)  gettext (Msgid)
 
 
+#if HAVE_WORKING_VFORK || HAVE_WORKING_FORK
+
 /* Initialize this module.  */
 
 void
 init_subpipe (void)
 {
@@ -176,5 +178,250 @@ reap_subpipe (pid_t pid, char const *pro
                 : "subsidiary program `%s' failed (exit status %d)"),
               program, status);
     }
 #endif
 }
+#else /* !HAVE_WORKING_VFORK and !HAVE_WORKING_FORK */
+# if __DJGPP__
+/* Initialize this module.  */
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <process.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "xalloc.h"
+
+static int old_stdin;
+static int old_stdout;
+static char **arguments;
+static char tmp_file_name[2][L_tmpnam];
+
+#define remove_tmp_file(fd, name)                                     \
+  do {                                                                \
+    close ((fd));                                                     \
+    if (unlink ((name)))                                              \
+      error (EXIT_FAILURE, 0, _("removing of `%s' failed"), (name));  \
+  } while (0)
+
+
+void
+init_subpipe (void)
+{
+  int fd;
+
+  strcpy (tmp_file_name[0], "/dev/env/TMPDIR/bnXXXXXX");
+  fd = mkstemp (tmp_file_name[0]);
+  if (fd < 0)
+    error (EXIT_FAILURE, 0, _("creation of tmpfile failed"));
+  close (fd);
+  
+  strcpy (tmp_file_name[1], "/dev/env/TMPDIR/bnXXXXXX");
+  fd = mkstemp (tmp_file_name[1]);
+  if (fd < 0)
+    error (EXIT_FAILURE, 0, _("creation of tmpfile failed"));
+  close (fd);
+}
+
+
+/* Create a subprocess that is run as a filter.  ARGV is the
+   NULL-terminated argument vector for the subprocess.  Store read and
+   write file descriptors for communication with the subprocess into
+   FD[0] and FD[1]: input meant for the process can be written into
+   FD[0], and output from the process can be read from FD[1].  Return
+   the subprocess id.
+
+   Because DOS has neither fork nor pipe functionality to run the subprocess
+   as a filter, the filter is reproduced using temporary files. First bison's
+   stdout is redirected to a temp. file. After bison has produced all of is
+   output, this file is closed and connected to m4's stdin. All m4's output
+   is redirected from m4's stdout to a second temp. file and reopened as
+   bison's stdin.  */
+
+pid_t
+create_subpipe (char const * const *argv, int fd[2])
+{
+  int argc;
+  int from_in_fd;  /* pipe from bison to m4. */
+  pid_t pid;
+
+
+  pid = getpid ();
+
+  /*
+   *  Save original stdin and stdout
+   *  for later restauration.
+   */
+  old_stdin = dup (STDIN_FILENO);
+  if (old_stdin < 0)
+    error (EXIT_FAILURE, 0, _("saving stdin failed"));
+
+  old_stdout = dup (STDOUT_FILENO);
+  if (old_stdout < 0)
+    error (EXIT_FAILURE, 0, _("saving stdout failed"));
+
+  /*
+   *  Save argv for later use.
+   */
+  for (argc = 0; argv[argc]; argc++)
+    ;
+  argc++;
+  arguments = xmalloc (argc * sizeof(arguments[0]));
+  for (argc = 0; argv[argc]; argc++)
+  {
+    arguments[argc] = xmalloc ((strlen (argv[argc]) + 1) * 
sizeof(arguments[0][0]));
+    strcpy (arguments[argc], argv[argc]);
+  }
+  arguments[argc] = NULL;
+
+  /*
+   *  All bison's output will be gathered in this temp. file
+   *  and will be redirected to m4's stdin later.
+   */
+  from_in_fd = open (tmp_file_name[0], O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR);
+  if (from_in_fd < 0)
+    error (EXIT_FAILURE, 0, _("opening of tmpfile failed"));
+  if (dup2 (from_in_fd, STDOUT_FILENO) < 0)
+  {
+    remove_tmp_file (from_in_fd, tmp_file_name[0]);
+    error (EXIT_FAILURE, 0, _("redirecting bison's stdout to tmpfile failed"));
+  }
+  close (from_in_fd);
+
+
+  fd[0] = STDOUT_FILENO;
+  return pid;
+}
+
+
+/* A signal handler that just records that a signal has happened.  */
+static int child_interrupted;
+
+static void
+signal_catcher (int signo)
+{
+  child_interrupted++;
+}
+
+
+void
+run_m4 (int fd[2])
+{
+  char *program;
+  int from_out_fd = open (tmp_file_name[0], O_RDONLY, S_IRUSR);                
   /* pipe from bison to m4. */
+  int to_in_fd = open (tmp_file_name[1], O_WRONLY | O_CREAT | O_TRUNC, 
S_IWUSR);  /* pipe from m4 to bison. */
+  int status;
+  void (*previous_handler)(int);
+
+
+  program = strrchr (arguments[0], '/');
+  if (program)
+    program++;
+  else
+    program = arguments[0];
+
+  /*
+   *  Redirect bison's output to m4's stdin.
+   */
+  if (from_out_fd < 0)
+    error (EXIT_FAILURE, 0, _("opening of tmpfile failed"));
+  if (dup2 (from_out_fd, STDIN_FILENO) < 0)
+  {
+    remove_tmp_file (from_out_fd, tmp_file_name[0]);
+    error (EXIT_FAILURE, 0, _("redirecting m4's stdin from tmpfile failed"));
+  }
+  close (from_out_fd);
+
+  /*
+   *  All m4's output will be gathered in this temp. file
+   *  and will be redirected to bison's stdin later.
+   */
+  if (to_in_fd < 0)
+  {
+    remove_tmp_file (STDIN_FILENO, tmp_file_name[0]);
+    error (EXIT_FAILURE, 0, _("opening of tmpfile failed"));
+  }
+  if (dup2 (to_in_fd, STDOUT_FILENO) < 0)
+  {
+    remove_tmp_file (STDIN_FILENO, tmp_file_name[0]);
+    remove_tmp_file (to_in_fd, tmp_file_name[1]);
+    error (EXIT_FAILURE, 0, _("redirecting m4's stdout to tmpfile failed"));
+  }
+  close (to_in_fd);
+
+  /*
+   *  Run m4.
+   */
+  child_interrupted = 0;
+  errno = 0;
+  previous_handler = signal (SIGINT, signal_catcher);
+  status = spawnvp (P_WAIT, program, arguments);
+  signal (SIGINT, previous_handler);
+  if (child_interrupted)
+  {
+    remove_tmp_file (STDIN_FILENO, tmp_file_name[0]);
+    remove_tmp_file (STDOUT_FILENO, tmp_file_name[1]);
+    error (EXIT_FAILURE, 0, _("subsidiary program `%s' interrupted"), program);
+  }
+  if (status)
+  {
+    remove_tmp_file (STDIN_FILENO, tmp_file_name[0]);
+    remove_tmp_file (STDOUT_FILENO, tmp_file_name[1]);
+    error (EXIT_FAILURE, 0, _(errno == ENOENT
+                              ? "subsidiary program `%s' not found"
+                              : status < 1
+                              ? "subsidiary program `%s' failed"
+                              : "subsidiary program `%s' failed (status=%i, 
errno=%i)"), program, status, errno);
+  }
+
+
+  /*
+   *  Redirect m4's output to bison's stdin.
+   */
+  if (dup2 (old_stdout, STDOUT_FILENO) < 0)
+    error (EXIT_FAILURE, 0, "restore of bison's stdout failed");
+  close (old_stdout);
+  to_in_fd = open (tmp_file_name[1], O_RDONLY, S_IRUSR);  /* pipe from m4 to 
bison. */
+  if (to_in_fd < 0)
+  {
+    remove_tmp_file (STDIN_FILENO, tmp_file_name[0]);
+    error (EXIT_FAILURE, 0, _("opening of tmpfile failed"));
+  }
+  if (dup2 (to_in_fd, STDIN_FILENO) < 0)
+  {
+    remove_tmp_file (STDIN_FILENO, tmp_file_name[0]);
+    remove_tmp_file (to_in_fd, tmp_file_name[1]);
+    error (EXIT_FAILURE, -1, "dup2");
+    error (EXIT_FAILURE, 0, _("redirecting bison's stdin from tmpfile 
failed"));
+  }
+  close (to_in_fd);
+
+
+  fd[1] = STDIN_FILENO;
+}
+
+
+/* Free resources, unlink temporary files and restore stdin and stdout.  */
+
+void
+reap_subpipe (pid_t pid, char const *program)
+{
+  int argc;
+
+  for (argc = 0; arguments[argc]; argc++)
+    free (arguments[argc]);
+  free (arguments);
+
+  if (unlink (tmp_file_name[0]))
+    error (EXIT_FAILURE, 0, _("removing of `%s' failed"), tmp_file_name[0]);
+  if (unlink (tmp_file_name[1]))
+    error (EXIT_FAILURE, 0, _("removing of `%s' failed"), tmp_file_name[1]);
+
+  if (dup2 (old_stdin, STDIN_FILENO) < 0)
+    error (EXIT_FAILURE, 0, "restore of bison's stdin failed");
+  close (old_stdin);
+}
+# else /* !__DJGPP__ */
+#  error "vfork, fork or an emulation is required."
+# endif /* !__DJGPP__ */
+#endif /* !HAVE_WORKING_VFORK and !HAVE_WORKING_FORK */
diff -apruNU5 bison-1.875d.orig/lib/subpipe.h bison-1.875d/lib/subpipe.h
--- bison-1.875d.orig/lib/subpipe.h     2004-04-28 06:30:04.000000000 +0000
+++ bison-1.875d/lib/subpipe.h  2004-12-07 14:58:34.000000000 +0000
@@ -26,5 +26,8 @@
 #endif
 
 void init_subpipe (void);
 pid_t create_subpipe (char const * const *, int[2]);
 void reap_subpipe (pid_t, char const *);
+#if !HAVE_WORKING_VFORK && !HAVE_WORKING_FORK
+void run_m4 (int[2]);
+#endif
diff -apruNU5 bison-1.875d.orig/src/output.c bison-1.875d/src/output.c
--- bison-1.875d.orig/src/output.c      2004-03-31 00:37:20.000000000 +0000
+++ bison-1.875d/src/output.c   2004-12-07 14:58:34.000000000 +0000
@@ -576,10 +576,15 @@ output_skeleton (void)
   fputs ("m4_divert_push(0)dnl\n", out);
   xfclose (out);
 
   /* Read and process m4's output.  */
   timevar_push (TV_M4);
+#if !HAVE_WORKING_VFORK && !HAVE_WORKING_FORK
+  /* On non posix systems that lack vfork and fork
+     m4 must be explicitly spawned to process bison output. */
+  run_m4 (filter_fd);
+#endif
   in = fdopen (filter_fd[1], "r");
   if (! in)
     error (EXIT_FAILURE, get_errno (), "fdopen");
   scan_skel (in);
   xfclose (in);
diff -apruNU5 bison-1.875d.orig/src/system.h bison-1.875d/src/system.h
--- bison-1.875d.orig/src/system.h      2004-04-28 20:00:56.000000000 +0000
+++ bison-1.875d/src/system.h   2004-12-07 14:58:34.000000000 +0000
@@ -178,12 +178,19 @@ do {                                                      
        \
 # define TAB_EXT       "_tab"
 # define OUTPUT_EXT    ".output"
 #else /* ! VMS */
 # ifdef MSDOS
    /* MS DOS. */
-#  define TAB_EXT      "_tab"
-#  define OUTPUT_EXT   ".out"
+#  ifdef __DJGPP__
+    /* DJGPP. */
+#   include <unistd.h>
+#   define TAB_EXT     ((pathconf(NULL, _PC_NAME_MAX) > 12) ? ".tab" : "_tab")
+#   define OUTPUT_EXT  ((pathconf(NULL, _PC_NAME_MAX) > 12) ? ".output" : 
".out")
+#  else /* ! __DJGPP__ */
+#   define TAB_EXT     "_tab"
+#   define OUTPUT_EXT  ".out"
+#  endif /* ! __DJGPP__ */
 # else /* ! MSDOS */
   /* Standard. */
 #  define TAB_EXT      ".tab"
 #  define OUTPUT_EXT   ".output"
 # endif /* ! MSDOS */





reply via email to

[Prev in Thread] Current Thread [Next in Thread]