# HG changeset patch # User Paul Boddie # Date 1717198132 -7200 # Node ID 010a687b0eaa61722531a6fe6d876334772f7cef # Parent 9394ba7a6785f25437e6b761603b42aacf8aa061 Added support for relaying input to the created process. diff -r 9394ba7a6785 -r 010a687b0eaa test_files/programs/test_popenv.c --- a/test_files/programs/test_popenv.c Sat Jun 01 01:27:34 2024 +0200 +++ b/test_files/programs/test_popenv.c Sat Jun 01 01:28:52 2024 +0200 @@ -19,11 +19,12 @@ * Boston, MA 02110-1301, USA */ +#include +#include +#include +#include #include #include -#include -#include -#include @@ -33,15 +34,25 @@ /* Transfer data between streams. */ -static void transfer(FILE *input, FILE *output) +static void transfer(FILE *input, FILE *output, char *buffer, int *start, size_t *remaining) { - char buffer[TO_TRANSFER]; - size_t nread; + size_t nwritten; + + /* Transfer any previously read data before trying to read more. */ + + while (*remaining || (*start = 0, *remaining = fread(buffer, sizeof(char), TO_TRANSFER, input))) + { + /* Write the data, stopping if no data can be written. */ - while ((nread = fread(buffer, sizeof(char), TO_TRANSFER, input))) - { - if (!fwrite(buffer, sizeof(char), nread, output)) - break; + nwritten = fwrite(buffer + *start, sizeof(char), *remaining, output); + + if (!nwritten) + return; + + /* Record the remaining amount. */ + + *remaining -= nwritten; + *start += nwritten; } } @@ -57,6 +68,14 @@ event_source_t source; event_values_t result; + /* Transfer buffers and status. */ + + char input_buffer[TO_TRANSFER]; + char output_buffer[TO_TRANSFER]; + char error_buffer[TO_TRANSFER]; + int input_start = 0, output_start = 0, error_start = 0; + size_t input_remaining = 0, output_remaining = 0, error_remaining = 0; + if (argc < 2) { printf("Usage: test_popenv ...\n"); @@ -75,6 +94,12 @@ printf("Process: %d\n", pid); + /* Prevent stdin from blocking to be able to read as much data as is + available and to monitor events on it manually. */ + + if (stdin != NULL) + fcntl(fileno(stdin), F_SETFL, O_NONBLOCK | fcntl(fileno(stdin), F_GETFL)); + /* Monitor the streams and the process. */ port = port_create(); @@ -82,7 +107,10 @@ port_subscribe(port, port_process_source(pid), PORT_PROCESS_ALL); if (stdin != NULL) + { port_subscribe(port, port_file_source(fileno(stdin)), PORT_INPUT | PORT_CLOSE); + port_subscribe(port, port_file_source(fileno(input)), PORT_OUTPUT | PORT_CLOSE); + } port_subscribe(port, port_file_source(fileno(output)), PORT_INPUT | PORT_CLOSE); @@ -99,33 +127,54 @@ return 1; } - /* Handle input to this process. */ + /* Handle input to this process and its transfer to the created + process. */ + + if ((stdin != NULL) && (input != NULL)) + { + /* Attempt to transfer input. */ - if ((stdin != NULL) && (source == port_file_source(fileno(stdin)))) - transfer(stdin, input); + if ((source == port_file_source(fileno(stdin))) || + input_remaining || (source == port_file_source(fileno(input)))) + transfer(stdin, input, input_buffer, &input_start, &input_remaining); + + /* If no input remains and stdin has been closed, close the input + pipe. */ + + if (!input_remaining && port_source_event_flags(port_file_source(fileno(stdin))) & PORT_CLOSE) + { + fclose(input); + input = NULL; + } + } /* Handle output from the process. */ - else if (source == port_file_source(fileno(output))) - transfer(output, stdout); - else if ((error != NULL) && (source == port_file_source(fileno(error)))) - transfer(error, stderr); + if (output_remaining || (source == port_file_source(fileno(output)))) + transfer(output, stdout, output_buffer, &output_start, &output_remaining); + + if ((error != NULL) && (error_remaining || (source == port_file_source(fileno(error))))) + transfer(error, stderr, error_buffer, &error_start, &error_remaining); /* Handle process termination. */ else if (source == port_process_source(pid)) { - transfer(output, stdout); + transfer(output, stdout, output_buffer, &output_start, &output_remaining); if (error != NULL) - transfer(error, stderr); + transfer(error, stderr, error_buffer, &error_start, &error_remaining); result = port_source_event_values(source); break; } } - fclose(input); + /* Close any open pipes. */ + + if (input != NULL) + fclose(input); + fclose(output); if (error != NULL)