Compare commits
5 Commits
a4e797f619
...
f6320d64cd
| Author | SHA1 | Date | |
|---|---|---|---|
| f6320d64cd | |||
| 87ff913186 | |||
| 52c53fa57f | |||
| 8237fae60f | |||
| 10cfb05287 |
@@ -623,6 +623,10 @@ static const fx_value *iterator_get_value(const fx_iterator *obj)
|
||||
struct table_item *table = it->_h_p->t_items;
|
||||
size_t capacity = primes[it->_h_p->t_max_index];
|
||||
|
||||
if (it->i >= capacity) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (table[it->i].i_item) {
|
||||
return &it->item_value;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef FX_DIAGNOSTICS_PROCESS_H_
|
||||
#define FX_DIAGNOSTICS_PROCESS_H_
|
||||
|
||||
#include <fx/collections/hashtable.h>
|
||||
#include <fx/macros.h>
|
||||
#include <fx/stream.h>
|
||||
|
||||
@@ -18,16 +19,20 @@ typedef struct fx_process_start_info {
|
||||
const char *proc_file_name;
|
||||
const char **proc_args;
|
||||
size_t proc_args_count;
|
||||
const fx_hashtable *proc_environment;
|
||||
} fx_process_start_info;
|
||||
|
||||
FX_API fx_type_id fx_process_get_type(void);
|
||||
|
||||
FX_API fx_process *fx_process_create(const fx_process_start_info *info);
|
||||
|
||||
FX_API fx_process *fx_process_get_self(void);
|
||||
|
||||
FX_API fx_status fx_process_start(fx_process *proc);
|
||||
FX_API fx_status fx_process_wait(fx_process *proc, int *out_result);
|
||||
FX_API fx_status fx_process_kill(fx_process *proc);
|
||||
|
||||
FX_API const fx_hashtable *fx_process_get_environment(const fx_process *proc);
|
||||
FX_API fx_stream *fx_process_get_stdin(fx_process *proc);
|
||||
FX_API fx_stream *fx_process_get_stdout(fx_process *proc);
|
||||
FX_API fx_stream *fx_process_get_stderr(fx_process *proc);
|
||||
|
||||
@@ -84,7 +84,6 @@ static fx_status process_start(struct fx_process_p *proc)
|
||||
if (proc->proc_redirect_stdout) {
|
||||
fx_iostream_unref(out_r);
|
||||
fd = fx_iostream_steal_os_handle(out_w);
|
||||
fprintf(stderr, "dup2(%d, %d)\n", fd, 1);
|
||||
dup2(fd, 1);
|
||||
close(fd);
|
||||
}
|
||||
@@ -92,17 +91,28 @@ static fx_status process_start(struct fx_process_p *proc)
|
||||
if (proc->proc_redirect_stderr) {
|
||||
fx_iostream_unref(err_r);
|
||||
fd = fx_iostream_steal_os_handle(err_w);
|
||||
fprintf(stderr, "dup2(%d, %d)\n", fd, 2);
|
||||
dup2(fd, 2);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
const char *args[] = {
|
||||
"cowsay",
|
||||
NULL,
|
||||
};
|
||||
printf("exec '%s'\n", fx_string_get_cstr(proc->proc_exec_path));
|
||||
execv(fx_string_get_cstr(proc->proc_exec_path), (char *const *)args);
|
||||
const char **argv = NULL;
|
||||
size_t argc = 0;
|
||||
|
||||
if (proc->proc_args) {
|
||||
argc = fx_array_get_size(proc->proc_args);
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
argv = calloc(argc + 1, sizeof(char *));
|
||||
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
const fx_value *arg_value
|
||||
= fx_array_get_ref(proc->proc_args, i);
|
||||
fx_value_get_cstr(arg_value, &argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
execv(fx_string_get_cstr(proc->proc_exec_path), (char *const *)argv);
|
||||
exit(127);
|
||||
|
||||
cleanup:
|
||||
|
||||
@@ -0,0 +1,493 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <fx/collections/array.h>
|
||||
#include <fx/diagnostics/process.h>
|
||||
#include <fx/global.h>
|
||||
#include <fx/io/pipe.h>
|
||||
#include <fx/io/stream.h>
|
||||
#include <fx/iterator.h>
|
||||
#include <fx/macros.h>
|
||||
#include <fx/string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static fx_process *self = NULL;
|
||||
|
||||
extern const char **environ;
|
||||
|
||||
FX_API fx_type_id fx_process_iterator_get_type();
|
||||
|
||||
FX_DECLARE_TYPE(fx_process_iterator);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_process_iterator)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_process_iterator)
|
||||
|
||||
struct fx_process_p {
|
||||
fx_string *proc_exec_path;
|
||||
fx_array *proc_args;
|
||||
bool proc_redirect_stdin, proc_redirect_stdout, proc_redirect_stderr;
|
||||
fx_stream *proc_stdin, *proc_stdout, *proc_stderr;
|
||||
pid_t proc_id;
|
||||
fx_hashtable *proc_environment;
|
||||
};
|
||||
|
||||
struct fx_process_iterator_p {
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static fx_status process_start(struct fx_process_p *proc)
|
||||
{
|
||||
fx_iostream *in_r = NULL, *in_w = NULL;
|
||||
fx_iostream *out_r = NULL, *out_w = NULL;
|
||||
fx_iostream *err_r = NULL, *err_w = NULL;
|
||||
fx_status status = FX_SUCCESS;
|
||||
|
||||
if (proc->proc_redirect_stdin) {
|
||||
status = fx_pipe_create(&in_r, &in_w);
|
||||
if (!FX_OK(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stdout) {
|
||||
status = fx_pipe_create(&out_r, &out_w);
|
||||
if (!FX_OK(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stderr) {
|
||||
status = fx_pipe_create(&err_r, &err_w);
|
||||
if (!FX_OK(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
status = FX_ERR_INVALID_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
proc->proc_id = pid;
|
||||
proc->proc_stdin = fx_iostream_ref(in_w);
|
||||
proc->proc_stdout = fx_iostream_ref(out_r);
|
||||
proc->proc_stderr = fx_iostream_ref(err_r);
|
||||
status = FX_SUCCESS;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int fd = -1;
|
||||
if (proc->proc_redirect_stdin) {
|
||||
fx_iostream_unref(in_w);
|
||||
fd = fx_iostream_steal_os_handle(in_r);
|
||||
int err = dup2(fd, 0);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stdout) {
|
||||
fx_iostream_unref(out_r);
|
||||
fd = fx_iostream_steal_os_handle(out_w);
|
||||
dup2(fd, 1);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (proc->proc_redirect_stderr) {
|
||||
fx_iostream_unref(err_r);
|
||||
fd = fx_iostream_steal_os_handle(err_w);
|
||||
dup2(fd, 2);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
const char **argv = NULL;
|
||||
const char **envp = NULL;
|
||||
const char *default_argv[] = {
|
||||
fx_string_get_cstr(proc->proc_exec_path),
|
||||
NULL,
|
||||
};
|
||||
|
||||
size_t argc = 0;
|
||||
size_t envc = 0;
|
||||
|
||||
if (proc->proc_args) {
|
||||
argc = fx_array_get_size(proc->proc_args);
|
||||
}
|
||||
|
||||
if (proc->proc_environment) {
|
||||
envc = fx_hashtable_get_count(proc->proc_environment);
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
argv = calloc(argc + 1, sizeof(char *));
|
||||
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
const fx_value *arg_value
|
||||
= fx_array_get_ref(proc->proc_args, i);
|
||||
fx_value_get_cstr(arg_value, &argv[i]);
|
||||
}
|
||||
} else {
|
||||
argv = default_argv;
|
||||
}
|
||||
|
||||
if (envc) {
|
||||
envp = calloc(envc + 1, sizeof(char *));
|
||||
size_t i = 0;
|
||||
fx_stringstream *tmp = fx_stringstream_create();
|
||||
const fx_iterator *it
|
||||
= fx_iterator_begin(proc->proc_environment);
|
||||
fx_foreach(v, it)
|
||||
{
|
||||
fx_hashtable_item *item = NULL;
|
||||
fx_value_get_object(v, &item);
|
||||
const fx_value *name_v
|
||||
= fx_hashtable_item_get_key(item);
|
||||
const fx_value *value_v
|
||||
= fx_hashtable_item_get_value(item);
|
||||
|
||||
fx_value_to_string(name_v, tmp, NULL);
|
||||
fx_stream_write_char(tmp, '=');
|
||||
fx_value_to_string(value_v, tmp, NULL);
|
||||
envp[i++] = fx_stringstream_steal(tmp);
|
||||
}
|
||||
|
||||
fx_iterator_unref(it);
|
||||
fx_string_unref(tmp);
|
||||
}
|
||||
|
||||
fprintf(stderr, "argc=%zu, argv=%p\n", argc, argv);
|
||||
fprintf(stderr, "envc=%zu, envp=%p\n", envc, envp);
|
||||
execve(fx_string_get_cstr(proc->proc_exec_path),
|
||||
(char *const *)argv,
|
||||
(char *const *)envp);
|
||||
exit(127);
|
||||
|
||||
cleanup:
|
||||
fx_iostream_unref(in_r);
|
||||
fx_iostream_unref(in_w);
|
||||
fx_iostream_unref(out_r);
|
||||
fx_iostream_unref(out_w);
|
||||
fx_iostream_unref(err_r);
|
||||
fx_iostream_unref(err_w);
|
||||
return status;
|
||||
}
|
||||
|
||||
static fx_status process_wait(struct fx_process_p *proc, int *out_result)
|
||||
{
|
||||
if (proc->proc_id == 0) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
|
||||
do {
|
||||
int err = waitpid(proc->proc_id, &status, WUNTRACED);
|
||||
if (err != 0) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
} while (!WIFEXITED(status));
|
||||
|
||||
proc->proc_id = 0;
|
||||
*out_result = WEXITSTATUS(status);
|
||||
return FX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static fx_status process_kill(struct fx_process_p *proc)
|
||||
{
|
||||
if (proc->proc_id == 0) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
int err = kill(proc->proc_id, SIGTERM);
|
||||
if (err != 0) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static const fx_hashtable *process_get_environment(
|
||||
const struct fx_process_p *proc)
|
||||
{
|
||||
return proc->proc_environment;
|
||||
}
|
||||
|
||||
static fx_stream *process_get_stdin(struct fx_process_p *proc)
|
||||
{
|
||||
return proc->proc_stdin;
|
||||
}
|
||||
|
||||
static fx_stream *process_get_stdout(struct fx_process_p *proc)
|
||||
{
|
||||
return proc->proc_stdout;
|
||||
}
|
||||
|
||||
static fx_stream *process_get_stderr(struct fx_process_p *proc)
|
||||
{
|
||||
return proc->proc_stderr;
|
||||
}
|
||||
|
||||
static void process_close_stdin(struct fx_process_p *proc)
|
||||
{
|
||||
fx_iostream_unref(proc->proc_stdin);
|
||||
proc->proc_stdin = NULL;
|
||||
}
|
||||
|
||||
static void process_close_stdout(struct fx_process_p *proc)
|
||||
{
|
||||
fx_iostream_unref(proc->proc_stdout);
|
||||
proc->proc_stdout = NULL;
|
||||
}
|
||||
|
||||
static void process_close_stderr(struct fx_process_p *proc)
|
||||
{
|
||||
fx_iostream_unref(proc->proc_stderr);
|
||||
proc->proc_stderr = NULL;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_process *fx_process_create(const fx_process_start_info *info)
|
||||
{
|
||||
fx_process *out = fx_object_create(FX_DIAGNOSTICS_TYPE_PROCESS);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_process_p *proc
|
||||
= fx_object_get_private(out, FX_DIAGNOSTICS_TYPE_PROCESS);
|
||||
|
||||
proc->proc_exec_path = fx_string_create_from_cstr(info->proc_file_name);
|
||||
if (!proc->proc_exec_path) {
|
||||
fx_process_unref(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (info->proc_args_count > 0) {
|
||||
proc->proc_args = fx_array_create();
|
||||
if (!proc->proc_args) {
|
||||
fx_process_unref(out);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < info->proc_args_count; i++) {
|
||||
fx_string *arg = fx_string_create_from_cstr(info->proc_args[i]);
|
||||
if (!arg) {
|
||||
fx_process_unref(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_array_push_back(proc->proc_args, FX_VALUE_OBJECT(arg));
|
||||
fx_string_unref(arg);
|
||||
}
|
||||
|
||||
proc->proc_environment
|
||||
= fx_hashtable_ref((fx_hashtable *)info->proc_environment);
|
||||
proc->proc_redirect_stdin = info->proc_redirect_stdin;
|
||||
proc->proc_redirect_stdout = info->proc_redirect_stdout;
|
||||
proc->proc_redirect_stderr = info->proc_redirect_stderr;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
fx_process *fx_process_get_self(void)
|
||||
{
|
||||
if (self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
self = fx_object_create(FX_DIAGNOSTICS_TYPE_PROCESS);
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_process_p *proc
|
||||
= fx_object_get_private(self, FX_DIAGNOSTICS_TYPE_PROCESS);
|
||||
|
||||
proc->proc_id = getpid();
|
||||
fx_hashtable *env = fx_hashtable_create();
|
||||
|
||||
for (size_t i = 0; environ[i]; i++) {
|
||||
char *envstr = fx_strdup(environ[i]);
|
||||
|
||||
const char *name = envstr;
|
||||
char *sep = strchr(name, '=');
|
||||
const char *value = NULL;
|
||||
if (sep) {
|
||||
*sep = '\0';
|
||||
value = sep + 1;
|
||||
}
|
||||
|
||||
fx_string *name_str = fx_string_create_from_cstr(name);
|
||||
fx_string *value_str = fx_string_create();
|
||||
if (value) {
|
||||
fx_string_append_cstr(value_str, value);
|
||||
}
|
||||
|
||||
fx_hashtable_put(
|
||||
env,
|
||||
&FX_VALUE_OBJECT(name_str),
|
||||
&FX_VALUE_OBJECT(value_str));
|
||||
|
||||
fx_string_unref(name_str);
|
||||
fx_string_unref(value_str);
|
||||
free(envstr);
|
||||
}
|
||||
|
||||
proc->proc_environment = env;
|
||||
|
||||
fx_register_global(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
fx_status fx_process_start(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_start,
|
||||
proc);
|
||||
}
|
||||
|
||||
fx_status fx_process_wait(fx_process *proc, int *out_result)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_wait,
|
||||
proc,
|
||||
out_result);
|
||||
}
|
||||
|
||||
fx_status fx_process_kill(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_kill,
|
||||
proc);
|
||||
}
|
||||
|
||||
const fx_hashtable *fx_process_get_environment(const fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_get_environment,
|
||||
proc);
|
||||
}
|
||||
|
||||
fx_stream *fx_process_get_stdin(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_get_stdin,
|
||||
proc);
|
||||
}
|
||||
|
||||
fx_stream *fx_process_get_stdout(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_get_stdout,
|
||||
proc);
|
||||
}
|
||||
|
||||
fx_stream *fx_process_get_stderr(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_get_stderr,
|
||||
proc);
|
||||
}
|
||||
|
||||
void fx_process_close_stdin(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_V0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_close_stdin,
|
||||
proc);
|
||||
}
|
||||
|
||||
void fx_process_close_stdout(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_V0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_close_stdout,
|
||||
proc);
|
||||
}
|
||||
|
||||
void fx_process_close_stderr(fx_process *proc)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_V0(
|
||||
FX_DIAGNOSTICS_TYPE_PROCESS,
|
||||
process_close_stderr,
|
||||
proc);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void process_init(fx_object *obj, void *priv)
|
||||
{
|
||||
}
|
||||
|
||||
static void process_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_process_p *proc = priv;
|
||||
fx_array_unref(proc->proc_args);
|
||||
fx_iostream_unref(proc->proc_stdin);
|
||||
fx_iostream_unref(proc->proc_stdout);
|
||||
fx_iostream_unref(proc->proc_stderr);
|
||||
fx_string_unref(proc->proc_exec_path);
|
||||
fx_hashtable_unref(proc->proc_environment);
|
||||
}
|
||||
|
||||
/*** ITERATOR DEFINITION
|
||||
* ******************************************************/
|
||||
|
||||
static enum fx_status process_iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
static const fx_value *process_iterator_get_value(const fx_iterator *obj)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION
|
||||
* *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_process)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_END(fx_process)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_process)
|
||||
FX_TYPE_ID(0x7334594f, 0xa1c3, 0x4715, 0xab69, 0x68a709e1b64b);
|
||||
FX_TYPE_NAME("fx.diagnostics.process");
|
||||
FX_TYPE_CLASS(fx_process_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_process_p);
|
||||
FX_TYPE_INSTANCE_INIT(process_init);
|
||||
FX_TYPE_INSTANCE_FINI(process_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_process)
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_process_iterator)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = process_iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = process_iterator_get_value;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_END(fx_process_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_process_iterator)
|
||||
FX_TYPE_ID(0x67eb13b6, 0x25d1, 0x424a, 0xb136, 0x871a07829089);
|
||||
FX_TYPE_NAME("fx.diagnostics.process.iterator");
|
||||
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
|
||||
FX_TYPE_CLASS(fx_process_iterator_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_process_iterator_p);
|
||||
FX_TYPE_DEFINITION_END(fx_process_iterator)
|
||||
@@ -9,11 +9,21 @@ int main(int argc, const char **argv)
|
||||
const char *exec = argv[1];
|
||||
const char *msg = argv[2];
|
||||
|
||||
const char *args[] = {
|
||||
"hello",
|
||||
"world",
|
||||
};
|
||||
|
||||
fx_process *self = fx_process_get_self();
|
||||
const fx_hashtable *env = fx_process_get_environment(self);
|
||||
|
||||
fx_process_start_info info = {
|
||||
.proc_args = NULL,
|
||||
.proc_args_count = 0,
|
||||
.proc_args = args,
|
||||
.proc_args_count = sizeof args / sizeof args[0],
|
||||
.proc_redirect_stdout = true,
|
||||
.proc_redirect_stdin = true,
|
||||
.proc_file_name = exec,
|
||||
.proc_environment = env,
|
||||
};
|
||||
|
||||
fx_process *process = fx_process_create(&info);
|
||||
@@ -30,11 +40,20 @@ int main(int argc, const char **argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 1
|
||||
printf("process stdin: %s\n", msg);
|
||||
|
||||
fx_stream *in = fx_process_get_stdin(process);
|
||||
fx_stream_write_cstr(in, "Hello, world!\n", NULL);
|
||||
fx_stream_write_cstr(in, msg, NULL);
|
||||
fx_stream_write_char(in, '\n');
|
||||
fx_process_close_stdin(process);
|
||||
#endif
|
||||
|
||||
fx_stream *out = fx_process_get_stdout(process);
|
||||
printf("process stdout:\n");
|
||||
printf("---------------------\n");
|
||||
|
||||
while (FX_OK(fx_stream_read_line_s(out, fx_stdout))) { }
|
||||
|
||||
printf("---------------------\n");
|
||||
|
||||
int result;
|
||||
fx_process_wait(process, &result);
|
||||
|
||||
@@ -12,7 +12,6 @@ fx_status fx_pipe_create(fx_iostream **reader, fx_iostream **writer)
|
||||
return fx_status_from_errno(errno, FX_ERR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
fprintf(stderr, "created pipe %d->%d\n", fds[1], fds[0]);
|
||||
fx_iostream *r = fx_iostream_create(FX_STREAM_READ, fds[0], true);
|
||||
fx_iostream *w = fx_iostream_create(FX_STREAM_WRITE, fds[1], true);
|
||||
|
||||
|
||||
@@ -81,7 +81,6 @@ static void iostream_fini(fx_object *obj, void *priv)
|
||||
|
||||
if (stream->s_fd_close_on_release) {
|
||||
close(stream->s_fd);
|
||||
fprintf(stderr, "closed fd %d\n", stream->s_fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fx/io/stream.h>
|
||||
#include <unistd.h>
|
||||
|
||||
fx_status fx_pipe_create(fx_iostream **reader, fx_iostream **writer)
|
||||
{
|
||||
int fds[2];
|
||||
int err = pipe(fds);
|
||||
if (err != 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
fx_iostream *r = fx_iostream_create(FX_STREAM_READ, fds[0], true);
|
||||
fx_iostream *w = fx_iostream_create(FX_STREAM_WRITE, fds[1], true);
|
||||
|
||||
if (!r || !w) {
|
||||
fx_iostream_unref(r);
|
||||
fx_iostream_unref(w);
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
*reader = r;
|
||||
*writer = w;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
#include "posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fx/io/stream.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_iostream_p {
|
||||
int s_fd;
|
||||
bool s_fd_close_on_release;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static uptr iostream_get_os_handle(const struct fx_iostream_p *stream)
|
||||
{
|
||||
return stream->s_fd;
|
||||
}
|
||||
|
||||
static uptr iostream_steal_os_handle(struct fx_iostream_p *stream)
|
||||
{
|
||||
uptr out = stream->s_fd;
|
||||
stream->s_fd = -1;
|
||||
stream->s_fd_close_on_release = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_iostream *fx_iostream_create(
|
||||
fx_stream_mode mode,
|
||||
uptr os_handle,
|
||||
bool close_handle_on_release)
|
||||
{
|
||||
fx_iostream *s = fx_object_create(FX_IO_TYPE_STREAM);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM);
|
||||
struct fx_iostream_p *p = fx_object_get_private(s, FX_IO_TYPE_STREAM);
|
||||
|
||||
cfg->s_mode = mode | Z__FX_STREAM_STATIC;
|
||||
p->s_fd = (int)os_handle;
|
||||
p->s_fd_close_on_release = close_handle_on_release;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
uptr fx_iostream_get_os_handle(const fx_iostream *stream)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_IO_TYPE_STREAM,
|
||||
iostream_get_os_handle,
|
||||
stream);
|
||||
}
|
||||
|
||||
uptr fx_iostream_steal_os_handle(fx_iostream *stream)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_IO_TYPE_STREAM,
|
||||
iostream_steal_os_handle,
|
||||
stream);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void iostream_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_iostream_p *stream = priv;
|
||||
}
|
||||
|
||||
static void iostream_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_iostream_p *stream = priv;
|
||||
|
||||
if (stream->s_fd_close_on_release) {
|
||||
close(stream->s_fd);
|
||||
}
|
||||
}
|
||||
|
||||
static enum fx_status stream_read(
|
||||
fx_stream *stream,
|
||||
void *buf,
|
||||
size_t count,
|
||||
size_t *nr_read)
|
||||
{
|
||||
struct fx_iostream_p *s
|
||||
= fx_object_get_private(stream, FX_IO_TYPE_STREAM);
|
||||
|
||||
long r = read(s->s_fd, buf, count);
|
||||
if (r < 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*nr_read = r;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status stream_write(
|
||||
fx_stream *stream,
|
||||
const void *buf,
|
||||
size_t count,
|
||||
size_t *nr_written)
|
||||
{
|
||||
struct fx_iostream_p *s
|
||||
= fx_object_get_private(stream, FX_IO_TYPE_STREAM);
|
||||
|
||||
long w = write(s->s_fd, buf, count);
|
||||
if (w < 0) {
|
||||
return fx_status_from_errno(errno, FX_ERR_IO_FAILURE);
|
||||
}
|
||||
|
||||
*nr_written = w;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_BEGIN(fx_iostream)
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
|
||||
FX_INTERFACE_ENTRY(s_close) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_seek) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_tell) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_getc) = NULL;
|
||||
FX_INTERFACE_ENTRY(s_read) = stream_read;
|
||||
FX_INTERFACE_ENTRY(s_write) = stream_write;
|
||||
FX_INTERFACE_ENTRY(s_reserve) = NULL;
|
||||
FX_TYPE_VTABLE_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
|
||||
FX_TYPE_CLASS_END(fx_iostream)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_iostream)
|
||||
FX_TYPE_ID(0xc0b1c3c9, 0xa9c6, 0x4910, 0x8786, 0x574b0696e7aa);
|
||||
FX_TYPE_NAME("fx.io.stream");
|
||||
FX_TYPE_EXTENDS(FX_TYPE_STREAM);
|
||||
FX_TYPE_CLASS(fx_iostream_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_iostream_p);
|
||||
FX_TYPE_INSTANCE_INIT(iostream_init);
|
||||
FX_TYPE_INSTANCE_FINI(iostream_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_iostream)
|
||||
+3
-3
@@ -1574,10 +1574,9 @@ static fx_status get_length(
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static void iterator_fini(fx_iterator *obj)
|
||||
static void iterator_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_string_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_STRING_ITERATOR);
|
||||
struct fx_string_iterator_p *it = priv;
|
||||
if (it->_tmp) {
|
||||
fx_string_unref(it->_tmp);
|
||||
}
|
||||
@@ -1840,4 +1839,5 @@ FX_TYPE_DEFINITION_BEGIN(fx_string_iterator)
|
||||
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
|
||||
FX_TYPE_CLASS(fx_string_iterator_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_string_iterator_p);
|
||||
FX_TYPE_INSTANCE_FINI(iterator_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_string_iterator)
|
||||
|
||||
+13
-18
@@ -167,9 +167,8 @@ fx_stringstream *fx_stringstream_create_with_buffer(char *buf, size_t max)
|
||||
}
|
||||
|
||||
fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM);
|
||||
struct fx_stringstream_p *p = fx_object_get_private(
|
||||
s,
|
||||
FX_TYPE_STRINGSTREAM);
|
||||
struct fx_stringstream_p *p
|
||||
= fx_object_get_private(s, FX_TYPE_STRINGSTREAM);
|
||||
|
||||
cfg->s_mode = FX_STREAM_READ | FX_STREAM_WRITE | Z__FX_STREAM_STATIC;
|
||||
|
||||
@@ -189,9 +188,8 @@ fx_stringstream *fx_stringstream_create(void)
|
||||
}
|
||||
|
||||
fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM);
|
||||
struct fx_stringstream_p *p = fx_object_get_private(
|
||||
s,
|
||||
FX_TYPE_STRINGSTREAM);
|
||||
struct fx_stringstream_p *p
|
||||
= fx_object_get_private(s, FX_TYPE_STRINGSTREAM);
|
||||
|
||||
cfg->s_mode = FX_STREAM_READ | FX_STREAM_WRITE | Z__FX_STREAM_STATIC;
|
||||
|
||||
@@ -268,41 +266,38 @@ static void stringstream_fini(fx_object *obj, void *priv)
|
||||
}
|
||||
}
|
||||
|
||||
enum fx_status stream_getc(fx_stream *stream, fx_wchar *c)
|
||||
static enum fx_status stream_getc(fx_stream *stream, fx_wchar *c)
|
||||
{
|
||||
struct fx_stringstream_p *s = fx_object_get_private(
|
||||
stream,
|
||||
FX_TYPE_STRINGSTREAM);
|
||||
struct fx_stringstream_p *s
|
||||
= fx_object_get_private(stream, FX_TYPE_STRINGSTREAM);
|
||||
|
||||
enum fx_status status = __getc(s, c);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
enum fx_status stream_read(
|
||||
static enum fx_status stream_read(
|
||||
fx_stream *stream,
|
||||
void *buf,
|
||||
size_t count,
|
||||
size_t *nr_read)
|
||||
{
|
||||
struct fx_stringstream_p *s = fx_object_get_private(
|
||||
stream,
|
||||
FX_TYPE_STRINGSTREAM);
|
||||
struct fx_stringstream_p *s
|
||||
= fx_object_get_private(stream, FX_TYPE_STRINGSTREAM);
|
||||
|
||||
enum fx_status status = __gets(s, buf, count, nr_read);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
enum fx_status stream_write(
|
||||
static enum fx_status stream_write(
|
||||
fx_stream *stream,
|
||||
const void *buf,
|
||||
size_t count,
|
||||
size_t *nr_written)
|
||||
{
|
||||
struct fx_stringstream_p *s = fx_object_get_private(
|
||||
stream,
|
||||
FX_TYPE_STRINGSTREAM);
|
||||
struct fx_stringstream_p *s
|
||||
= fx_object_get_private(stream, FX_TYPE_STRINGSTREAM);
|
||||
|
||||
enum fx_status status = __puts(s, (const char *)buf, count, nr_written);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user