/* Create a bi-directional pipe to a test child, and validate that the child program returns the expected output. PROG is the program to run in the child process. STDERR_CLOSED is true if we have already closed fd 2. */ static void test_pipe (const char *prog, bool stderr_closed) { int fd[2]; char *argv[3]; pid_t pid; char buffer[2] = { 'a', 't' }; /* Set up child. */ argv[0] = (char *) prog; argv[1] = (char *) (stderr_closed ? "1" : "0"); argv[2] = NULL; pid = create_pipe_bidi (prog, prog, argv, false, true, true, fd); ASSERT (0 <= pid); ASSERT (STDERR_FILENO < fd[0]); ASSERT (STDERR_FILENO < fd[1]); /* Push child's input. */ ASSERT (write (fd[1], buffer, 1) == 1); ASSERT (close (fd[1]) == 0); /* Get child's output. */ ASSERT (read (fd[0], buffer, 2) == 1); /* Wait for child. */ ASSERT (wait_subprocess (pid, prog, true, false, true, true, NULL) == 0); ASSERT (close (fd[0]) == 0); /* Check the result. */ ASSERT (buffer[0] == 'b'); ASSERT (buffer[1] == 't'); }
struct pipe_filter_gi * pipe_filter_gi_create (const char *progname, const char *prog_path, const char **prog_argv, bool null_stderr, bool exit_on_error, prepare_read_fn prepare_read, done_read_fn done_read, void *private_data) { struct pipe_filter_gi *filter; filter = (struct pipe_filter_gi *) xmalloc (sizeof (struct pipe_filter_gi)); /* Open a bidirectional pipe to a subprocess. */ filter->child = create_pipe_bidi (progname, prog_path, (char **) prog_argv, null_stderr, true, exit_on_error, filter->fd); filter->progname = progname; filter->null_stderr = null_stderr; filter->exit_on_error = exit_on_error; filter->prepare_read = prepare_read; filter->done_read = done_read; filter->private_data = private_data; filter->exited = false; filter->exitstatus = 0; filter->writer_terminated = false; filter->writer_errno = 0; filter->reader_terminated = false; filter->reader_errno = 0; if (filter->child == -1) { /* Child process could not be created. Arrange for filter_retcode (filter) to be the current errno. */ filter->writer_errno = errno; filter->writer_terminated = true; filter->exited = true; } else if (filter_init (filter) < 0) filter_terminate (filter); return filter; }
static void output_skeleton (void) { int filter_fd[2]; pid_t pid; /* Compute the names of the package data dir and skeleton files. */ char const *m4 = (m4 = getenv ("M4")) ? m4 : M4; char const *datadir = pkgdatadir (); char *m4sugar = xconcatenated_filename (datadir, "m4sugar/m4sugar.m4", NULL); char *m4bison = xconcatenated_filename (datadir, "bison.m4", NULL); char *skel = (IS_PATH_WITH_DIR (skeleton) ? xstrdup (skeleton) : xconcatenated_filename (datadir, skeleton, NULL)); /* Test whether m4sugar.m4 is readable, to check for proper installation. A faulty installation can cause deadlock, so a cheap sanity check is worthwhile. */ xfclose (xfopen (m4sugar, "r")); /* Create an m4 subprocess connected to us via two pipes. */ if (trace_flag & trace_tools) fprintf (stderr, "running: %s %s - %s %s\n", m4, m4sugar, m4bison, skel); /* Some future version of GNU M4 (most likely 1.6) may treat the -dV in a position-dependent manner. Keep it as the first argument so that all files are traced. See the thread starting at <http://lists.gnu.org/archive/html/bug-bison/2008-07/msg00000.html> for details. */ { char const *argv[10]; int i = 0; argv[i++] = m4; /* When POSIXLY_CORRECT is set, GNU M4 1.6 and later disable GNU extensions, which Bison's skeletons depend on. With older M4, it has no effect. M4 1.4.12 added a -g/--gnu command-line option to make it explicit that a program wants GNU M4 extensions even when POSIXLY_CORRECT is set. See the thread starting at <http://lists.gnu.org/archive/html/bug-bison/2008-07/msg00000.html> for details. */ if (*M4_GNU_OPTION) argv[i++] = M4_GNU_OPTION; argv[i++] = "-I"; argv[i++] = datadir; if (trace_flag & trace_m4) argv[i++] = "-dV"; argv[i++] = m4sugar; argv[i++] = "-"; argv[i++] = m4bison; argv[i++] = skel; argv[i++] = NULL; aver (i <= ARRAY_CARDINALITY (argv)); /* The ugly cast is because gnulib gets the const-ness wrong. */ pid = create_pipe_bidi ("m4", m4, (char **)(void*)argv, false, true, true, filter_fd); } free (m4sugar); free (m4bison); free (skel); if (trace_flag & trace_muscles) muscles_output (stderr); { FILE *out = xfdopen (filter_fd[1], "w"); muscles_output (out); xfclose (out); } /* Read and process m4's output. */ timevar_push (TV_M4); { FILE *in = xfdopen (filter_fd[0], "r"); scan_skel (in); /* scan_skel should have read all of M4's output. Otherwise, when we close the pipe, we risk letting M4 report a broken-pipe to the Bison user. */ aver (feof (in)); xfclose (in); } wait_subprocess (pid, "m4", false, false, true, true, NULL); timevar_pop (TV_M4); }