aboutsummaryrefslogtreecommitdiff
path: root/examples/commands
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-03-24 15:16:56 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-03-24 15:16:56 -0400
commit454cb1ce1d8a35f712139e0ae5958370d6d56e81 (patch)
tree3d054d143299a84481dd2da580b4928c334e2779 /examples/commands
parent31af868b5d5825b3179ae8cdb85554f993e20344 (diff)
Change commands interface so it can either run or get result
Diffstat (limited to 'examples/commands')
-rw-r--r--examples/commands/commands.c57
-rw-r--r--examples/commands/commands.tm23
2 files changed, 48 insertions, 32 deletions
diff --git a/examples/commands/commands.c b/examples/commands/commands.c
index d7bdeee6..ec090a7b 100644
--- a/examples/commands/commands.c
+++ b/examples/commands/commands.c
@@ -16,7 +16,7 @@
#define READ_END 0
#define WRITE_END 1
int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
- Array_t input_bytes, Array_t *output_bytes, Array_t *error_bytes)
+ OptionalArray_t input_bytes, Array_t *output_bytes, Array_t *error_bytes)
{
pthread_testcancel();
@@ -36,18 +36,24 @@ int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK);
int child_inpipe[2], child_outpipe[2], child_errpipe[2];
- pipe(child_inpipe);
- pipe(child_outpipe);
- pipe(child_errpipe);
+ if (input_bytes.length >= 0) pipe(child_inpipe);
+ if (output_bytes) pipe(child_outpipe);
+ if (error_bytes) pipe(child_errpipe);
posix_spawn_file_actions_t actions;
posix_spawn_file_actions_init(&actions);
- posix_spawn_file_actions_adddup2(&actions, child_inpipe[READ_END], STDIN_FILENO);
- posix_spawn_file_actions_addclose(&actions, child_inpipe[WRITE_END]);
- posix_spawn_file_actions_adddup2(&actions, child_outpipe[WRITE_END], STDOUT_FILENO);
- posix_spawn_file_actions_addclose(&actions, child_outpipe[READ_END]);
- posix_spawn_file_actions_adddup2(&actions, child_errpipe[WRITE_END], STDERR_FILENO);
- posix_spawn_file_actions_addclose(&actions, child_errpipe[READ_END]);
+ if (input_bytes.length >= 0) {
+ posix_spawn_file_actions_adddup2(&actions, child_inpipe[READ_END], STDIN_FILENO);
+ posix_spawn_file_actions_addclose(&actions, child_inpipe[WRITE_END]);
+ }
+ if (output_bytes) {
+ posix_spawn_file_actions_adddup2(&actions, child_outpipe[WRITE_END], STDOUT_FILENO);
+ posix_spawn_file_actions_addclose(&actions, child_outpipe[READ_END]);
+ }
+ if (error_bytes) {
+ posix_spawn_file_actions_adddup2(&actions, child_errpipe[WRITE_END], STDERR_FILENO);
+ posix_spawn_file_actions_addclose(&actions, child_errpipe[READ_END]);
+ }
const char *exe_str = Text$as_c_string(exe);
@@ -85,15 +91,14 @@ int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
posix_spawnattr_destroy(&attr);
posix_spawn_file_actions_destroy(&actions);
- close(child_inpipe[READ_END]);
- close(child_outpipe[WRITE_END]);
- close(child_errpipe[WRITE_END]);
+ if (input_bytes.length >= 0) close(child_inpipe[READ_END]);
+ if (output_bytes) close(child_outpipe[WRITE_END]);
+ if (error_bytes) close(child_errpipe[WRITE_END]);
- struct pollfd pollfds[3] = {
- {.fd=child_inpipe[WRITE_END], .events=POLLOUT},
- {.fd=child_outpipe[WRITE_END], .events=POLLIN},
- {.fd=child_errpipe[WRITE_END], .events=POLLIN},
- };
+ struct pollfd pollfds[3] = {};
+ if (input_bytes.length >= 0) pollfds[0] = (struct pollfd){.fd=child_inpipe[WRITE_END], .events=POLLOUT};
+ if (output_bytes) pollfds[1] = (struct pollfd){.fd=child_outpipe[WRITE_END], .events=POLLIN};
+ if (error_bytes) pollfds[2] = (struct pollfd){.fd=child_errpipe[WRITE_END], .events=POLLIN};
if (input_bytes.length > 0 && input_bytes.stride != 1)
Array$compact(&input_bytes, sizeof(char));
@@ -102,10 +107,10 @@ int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
if (error_bytes)
*error_bytes = (Array_t){.atomic=1, .stride=1, .length=0};
- for (;;) {
+ while (input_bytes.length > 0 || output_bytes || error_bytes) {
(void)poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1); // Wait for data or readiness
bool did_something = false;
- if (pollfds[0].revents) {
+ if (input_bytes.length >= 0 && pollfds[0].revents) {
if (input_bytes.length > 0) {
ssize_t written = write(child_inpipe[WRITE_END], input_bytes.data, (size_t)input_bytes.length);
if (written > 0) {
@@ -123,13 +128,13 @@ int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
}
}
char buf[256];
- if (pollfds[1].revents) {
+ if (output_bytes && pollfds[1].revents) {
ssize_t n = read(child_outpipe[READ_END], buf, sizeof(buf));
did_something = did_something || (n > 0);
if (n <= 0) {
close(child_outpipe[READ_END]);
pollfds[1].events = 0;
- } else if (n > 0 && output_bytes) {
+ } else if (n > 0) {
if (output_bytes->free < n) {
output_bytes->data = GC_REALLOC(output_bytes->data, (size_t)(output_bytes->length + n));
output_bytes->free = 0;
@@ -138,13 +143,13 @@ int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
output_bytes->length += n;
}
}
- if (pollfds[2].revents) {
+ if (error_bytes && pollfds[2].revents) {
ssize_t n = read(child_errpipe[READ_END], buf, sizeof(buf));
did_something = did_something || (n > 0);
if (n <= 0) {
close(child_errpipe[READ_END]);
pollfds[2].events = 0;
- } else if (n > 0 && error_bytes) {
+ } else if (n > 0) {
if (error_bytes->free < n) {
error_bytes->data = GC_REALLOC(error_bytes->data, (size_t)(error_bytes->length + n));
error_bytes->free = 0;
@@ -166,6 +171,10 @@ int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
}
}
+ if (input_bytes.length >= 0) close(child_inpipe[WRITE_END]);
+ if (output_bytes) close(child_outpipe[READ_END]);
+ if (error_bytes) close(child_errpipe[READ_END]);
+
sigaction(SIGINT, &oldint, NULL);
sigaction(SIGQUIT, &oldquit, NULL);
sigprocmask(SIG_SETMASK, &old, NULL);
diff --git a/examples/commands/commands.tm b/examples/commands/commands.tm
index 7d2f4a6f..dd366f6f 100644
--- a/examples/commands/commands.tm
+++ b/examples/commands/commands.tm
@@ -3,7 +3,7 @@
use ./commands.c
use libunistring.so
-extern run_command:func(exe:Text, args:[Text], env:{Text,Text}, input:[Byte], output:&[Byte], error:&[Byte] -> Int32)
+extern run_command:func(exe:Text, args:[Text], env:{Text,Text}, input:[Byte]?, output:&[Byte]?, error:&[Byte]? -> Int32)
extern command_by_line:func(exe:Text, args:[Text], env:{Text,Text} -> func(->Text?)?)
enum ExitType(Exited(status:Int32), Signaled(signal:Int32), Failed)
@@ -43,7 +43,7 @@ struct Command(command:Text, args=[:Text], env={:Text,Text}):
func from_path(path:Path, args=[:Text], env={:Text,Text} -> Command):
return Command(Text(path), args, env)
- func run(command:Command, input="", input_bytes=[:Byte] -> ProgramResult):
+ func result(command:Command, input="", input_bytes=[:Byte] -> ProgramResult):
if input.length > 0:
(&input_bytes):insert_all(input:bytes())
@@ -59,11 +59,22 @@ struct Command(command:Text, args=[:Text], env={:Text,Text}):
return ProgramResult(stdout, stderr, ExitType.Failed)
+ func run(command:Command, -> ExitType):
+ status := run_command(command.command, command.args, command.env, none, none, none)
+
+ if inline C : Bool { WIFEXITED(_$status) }:
+ return ExitType.Exited(inline C : Int32 { WEXITSTATUS(_$status) })
+
+ if inline C : Bool { WIFSIGNALED(_$status) }:
+ return ExitType.Signaled(inline C : Int32 { WTERMSIG(_$status) })
+
+ return ExitType.Failed
+
func get_output(command:Command, input="", trim_newline=yes -> Text?):
- return command:run(input=input):output_text(trim_newline=trim_newline)
+ return command:result(input=input):output_text(trim_newline=trim_newline)
func get_output_bytes(command:Command, input="", input_bytes=[:Byte] -> [Byte]?):
- result := command:run(input=input, input_bytes=input_bytes)
+ result := command:result(input=input, input_bytes=input_bytes)
when result.exit_type is Exited(status):
if status == 0: return result.stdout
return none
@@ -71,7 +82,3 @@ struct Command(command:Text, args=[:Text], env={:Text,Text}):
func by_line(command:Command -> func(->Text?)?):
return command_by_line(command.command, command.args, command.env)
-
-func main(command:Text, args:[Text], input=""):
- cmd := Command(command, args)
- say(cmd:get_output(input=input)!)