int char_buffer::do_image(int argc, char *argv[]) { string s; alterDeviceTo(argc, argv, 1); argv += troff_arg; // skip all arguments up to troff/groff argc -= troff_arg; argv = addRegDef(argc, argv, "-rps4html=1"); argc++; s = "-dwww-image-template="; s += macroset_template; s += '\0'; argv = addRegDef(argc, argv, s.contents()); argc++; // override local settings and produce a page size letter postscript file argv = addRegDef(argc, argv, "-P-pletter"); argc++; #if defined(DEBUGGING) # define IMAGE_DEBUG_STREAM OUTPUT_STREAM(troffFileName) // slight security risk so only enabled if compiled with defined(DEBUGGING) if (debug) { int saved_stdout = save_and_redirect(STDOUT_FILENO, IMAGE_DEBUG_STREAM); emit_troff_output(DEVICE_FORMAT(IMAGE_OUTPUT_FILTER)); set_redirection(STDOUT_FILENO, saved_stdout); } #endif return run_output_filter(IMAGE_OUTPUT_FILTER, argc, argv); }
int char_buffer::do_html(int argc, char *argv[]) { string s; alterDeviceTo(argc, argv, 0); argv += troff_arg; // skip all arguments up to groff argc -= troff_arg; argv = addZ(argc, argv); argc++; s = "-dwww-image-template="; s += macroset_template; // do not combine these statements, // otherwise they will not work s += '\0'; // the trailing `\0' is ignored argv = addRegDef(argc, argv, s.contents()); argc++; #if defined(DEBUGGING) # define HTML_DEBUG_STREAM OUTPUT_STREAM(htmlFileName) // slight security risk so only enabled if compiled with defined(DEBUGGING) if (debug) { int saved_stdout = save_and_redirect(STDOUT_FILENO, HTML_DEBUG_STREAM); emit_troff_output(DEVICE_FORMAT(HTML_OUTPUT_FILTER)); set_redirection(STDOUT_FILENO, saved_stdout); } #endif return run_output_filter(HTML_OUTPUT_FILTER, argc, argv); }
int char_buffer::run_output_filter(int filter, int argc, char **argv) { int pipedes[2]; PID_T child_pid; int status; print_args(argc, argv); if (pipe(pipedes) < 0) sys_fatal("pipe"); #if MAY_FORK_CHILD_PROCESS // This is the UNIX process model. To invoke our post-processor, // we must `fork' the current process. if ((child_pid = fork()) < 0) sys_fatal("fork"); else if (child_pid == 0) { // This is the child process fork. We redirect its `stdin' stream // to read data emerging from our pipe. There is no point in saving, // since we won't be able to restore later! set_redirection(STDIN_FILENO, pipedes[0]); // The parent process will be writing this data, so we should release // the child's writeable handle on the pipe, since we have no use for it. if (close(pipedes[1]) < 0) sys_fatal("close"); // The IMAGE_OUTPUT_FILTER needs special output redirection... if (filter == IMAGE_OUTPUT_FILTER) { // with BOTH `stdout' AND `stderr' diverted to files. set_redirection(STDOUT_FILENO, PS_OUTPUT_STREAM); set_redirection(STDERR_FILENO, REGION_OUTPUT_STREAM); } // Now we are ready to launch the output filter. execvp(argv[0], argv); // If we get to here then the `exec...' request for the output filter // failed. Diagnose it and bail out. error("couldn't exec %1: %2", argv[0], strerror(errno), ((char *)0)); fflush(stderr); // just in case error() didn't exit(1); } else { // This is the parent process fork. We will be writing data to the // filter pipeline, and the child will be reading it. We have no further // use for our read handle on the pipe, and should close it. if (close(pipedes[0]) < 0) sys_fatal("close"); // Now we redirect the `stdout' stream to the inlet end of the pipe, // and push out the appropiately formatted data to the filter. pipedes[1] = save_and_redirect(STDOUT_FILENO, pipedes[1]); emit_troff_output(DEVICE_FORMAT(filter)); // After emitting all the data we close our connection to the inlet // end of the pipe so the child process will detect end of data. set_redirection(STDOUT_FILENO, pipedes[1]); // Finally, we must wait for the child process to complete. if (WAIT(&status, child_pid, _WAIT_CHILD) != child_pid) sys_fatal("wait"); } #elif MAY_SPAWN_ASYNCHRONOUS_CHILD // We do not have `fork', (or we prefer not to use it), // but asynchronous processes are allowed, passing data through pipes. // This should be ok for most Win32 systems and is preferred to `fork' // for starting child processes under Cygwin. // Before we start the post-processor we bind its inherited `stdin' // stream to the readable end of our pipe, saving our own `stdin' stream // in `pipedes[0]'. pipedes[0] = save_and_redirect(STDIN_FILENO, pipedes[0]); // for the Win32 model, // we need special provision for saving BOTH `stdout' and `stderr'. int saved_stdout = dup(STDOUT_FILENO); int saved_stderr = STDERR_FILENO; // The IMAGE_OUTPUT_FILTER needs special output redirection... if (filter == IMAGE_OUTPUT_FILTER) { // with BOTH `stdout' AND `stderr' diverted to files while saving a // duplicate handle for `stderr'. set_redirection(STDOUT_FILENO, PS_OUTPUT_STREAM); saved_stderr = save_and_redirect(STDERR_FILENO, REGION_OUTPUT_STREAM); } // We then use an asynchronous spawn request to start the post-processor. if ((child_pid = spawnvp(_P_NOWAIT, argv[0], argv)) < 0) { // Should the spawn request fail we issue a diagnostic and bail out. error("cannot spawn %1: %2", argv[0], strerror(errno), ((char *)0)); exit(1); } // Once the post-processor has been started we revert our `stdin' // to its original saved source, which also closes the readable handle // for the pipe. set_redirection(STDIN_FILENO, pipedes[0]); // if we redirected `stderr', for use by the image post-processor, // then we also need to reinstate its original assignment. if (filter == IMAGE_OUTPUT_FILTER) set_redirection(STDERR_FILENO, saved_stderr); // Now we redirect the `stdout' stream to the inlet end of the pipe, // and push out the appropiately formatted data to the filter. set_redirection(STDOUT_FILENO, pipedes[1]); emit_troff_output(DEVICE_FORMAT(filter)); // After emitting all the data we close our connection to the inlet // end of the pipe so the child process will detect end of data. set_redirection(STDOUT_FILENO, saved_stdout); // And finally, we must wait for the child process to complete. if (WAIT(&status, child_pid, _WAIT_CHILD) != child_pid) sys_fatal("wait"); #else /* can't do asynchronous pipes! */ // TODO: code to support an MS-DOS style process model // should go here #endif /* MAY_FORK_CHILD_PROCESS or MAY_SPAWN_ASYNCHRONOUS_CHILD */ return 0; }