1.1 --- a/test_files/programs/test_popenv.c Sat Jun 01 01:27:34 2024 +0200
1.2 +++ b/test_files/programs/test_popenv.c Sat Jun 01 01:28:52 2024 +0200
1.3 @@ -19,11 +19,12 @@
1.4 * Boston, MA 02110-1301, USA
1.5 */
1.6
1.7 +#include <errno.h>
1.8 +#include <fcntl.h>
1.9 +#include <port.h>
1.10 +#include <process.h>
1.11 #include <stdio.h>
1.12 #include <sys/types.h>
1.13 -#include <errno.h>
1.14 -#include <port.h>
1.15 -#include <process.h>
1.16
1.17
1.18
1.19 @@ -33,15 +34,25 @@
1.20
1.21 /* Transfer data between streams. */
1.22
1.23 -static void transfer(FILE *input, FILE *output)
1.24 +static void transfer(FILE *input, FILE *output, char *buffer, int *start, size_t *remaining)
1.25 {
1.26 - char buffer[TO_TRANSFER];
1.27 - size_t nread;
1.28 + size_t nwritten;
1.29 +
1.30 + /* Transfer any previously read data before trying to read more. */
1.31 +
1.32 + while (*remaining || (*start = 0, *remaining = fread(buffer, sizeof(char), TO_TRANSFER, input)))
1.33 + {
1.34 + /* Write the data, stopping if no data can be written. */
1.35
1.36 - while ((nread = fread(buffer, sizeof(char), TO_TRANSFER, input)))
1.37 - {
1.38 - if (!fwrite(buffer, sizeof(char), nread, output))
1.39 - break;
1.40 + nwritten = fwrite(buffer + *start, sizeof(char), *remaining, output);
1.41 +
1.42 + if (!nwritten)
1.43 + return;
1.44 +
1.45 + /* Record the remaining amount. */
1.46 +
1.47 + *remaining -= nwritten;
1.48 + *start += nwritten;
1.49 }
1.50 }
1.51
1.52 @@ -57,6 +68,14 @@
1.53 event_source_t source;
1.54 event_values_t result;
1.55
1.56 + /* Transfer buffers and status. */
1.57 +
1.58 + char input_buffer[TO_TRANSFER];
1.59 + char output_buffer[TO_TRANSFER];
1.60 + char error_buffer[TO_TRANSFER];
1.61 + int input_start = 0, output_start = 0, error_start = 0;
1.62 + size_t input_remaining = 0, output_remaining = 0, error_remaining = 0;
1.63 +
1.64 if (argc < 2)
1.65 {
1.66 printf("Usage: test_popenv <program> <argument>...\n");
1.67 @@ -75,6 +94,12 @@
1.68
1.69 printf("Process: %d\n", pid);
1.70
1.71 + /* Prevent stdin from blocking to be able to read as much data as is
1.72 + available and to monitor events on it manually. */
1.73 +
1.74 + if (stdin != NULL)
1.75 + fcntl(fileno(stdin), F_SETFL, O_NONBLOCK | fcntl(fileno(stdin), F_GETFL));
1.76 +
1.77 /* Monitor the streams and the process. */
1.78
1.79 port = port_create();
1.80 @@ -82,7 +107,10 @@
1.81 port_subscribe(port, port_process_source(pid), PORT_PROCESS_ALL);
1.82
1.83 if (stdin != NULL)
1.84 + {
1.85 port_subscribe(port, port_file_source(fileno(stdin)), PORT_INPUT | PORT_CLOSE);
1.86 + port_subscribe(port, port_file_source(fileno(input)), PORT_OUTPUT | PORT_CLOSE);
1.87 + }
1.88
1.89 port_subscribe(port, port_file_source(fileno(output)), PORT_INPUT | PORT_CLOSE);
1.90
1.91 @@ -99,33 +127,54 @@
1.92 return 1;
1.93 }
1.94
1.95 - /* Handle input to this process. */
1.96 + /* Handle input to this process and its transfer to the created
1.97 + process. */
1.98 +
1.99 + if ((stdin != NULL) && (input != NULL))
1.100 + {
1.101 + /* Attempt to transfer input. */
1.102
1.103 - if ((stdin != NULL) && (source == port_file_source(fileno(stdin))))
1.104 - transfer(stdin, input);
1.105 + if ((source == port_file_source(fileno(stdin))) ||
1.106 + input_remaining || (source == port_file_source(fileno(input))))
1.107 + transfer(stdin, input, input_buffer, &input_start, &input_remaining);
1.108 +
1.109 + /* If no input remains and stdin has been closed, close the input
1.110 + pipe. */
1.111 +
1.112 + if (!input_remaining && port_source_event_flags(port_file_source(fileno(stdin))) & PORT_CLOSE)
1.113 + {
1.114 + fclose(input);
1.115 + input = NULL;
1.116 + }
1.117 + }
1.118
1.119 /* Handle output from the process. */
1.120
1.121 - else if (source == port_file_source(fileno(output)))
1.122 - transfer(output, stdout);
1.123 - else if ((error != NULL) && (source == port_file_source(fileno(error))))
1.124 - transfer(error, stderr);
1.125 + if (output_remaining || (source == port_file_source(fileno(output))))
1.126 + transfer(output, stdout, output_buffer, &output_start, &output_remaining);
1.127 +
1.128 + if ((error != NULL) && (error_remaining || (source == port_file_source(fileno(error)))))
1.129 + transfer(error, stderr, error_buffer, &error_start, &error_remaining);
1.130
1.131 /* Handle process termination. */
1.132
1.133 else if (source == port_process_source(pid))
1.134 {
1.135 - transfer(output, stdout);
1.136 + transfer(output, stdout, output_buffer, &output_start, &output_remaining);
1.137
1.138 if (error != NULL)
1.139 - transfer(error, stderr);
1.140 + transfer(error, stderr, error_buffer, &error_start, &error_remaining);
1.141
1.142 result = port_source_event_values(source);
1.143 break;
1.144 }
1.145 }
1.146
1.147 - fclose(input);
1.148 + /* Close any open pipes. */
1.149 +
1.150 + if (input != NULL)
1.151 + fclose(input);
1.152 +
1.153 fclose(output);
1.154
1.155 if (error != NULL)