From 55302629cd9d6e64de43b37bba4b1b8bc0ff18c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20H=C3=B8rl=C3=BCck=20Berg?= <36937807+henrikhorluck@users.noreply.github.com> Date: Fri, 18 Aug 2023 07:12:50 +0200 Subject: [PATCH] Add various FFI-interop-functions - `libc::setlinebuf` is not available through Rust's libc it appears. - autocxx fails to generate bindings using `*mut FILE`, instead go through `void*` - rust_main needs `parse_util_detect_errors_in_ast`, which is _partially_ ported, instead add FFI interop for C++. - We need to set the filename if we are sourcing a file --- src/common.cpp | 1 + src/common.h | 1 + src/flog.cpp | 15 +++++++++++++++ src/flog.h | 2 ++ src/parse_util.cpp | 5 +++++ src/parse_util.h | 3 +++ src/parser.cpp | 12 ++++++++++++ src/parser.h | 5 ++++- src/reader.cpp | 4 ++++ src/reader.h | 1 + 10 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/common.cpp b/src/common.cpp index 1a1b1913b..6607dbba0 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -81,6 +81,7 @@ static relaxed_atomic_t obfuscation_read_char; wchar_t get_obfuscation_read_char() { return obfuscation_read_char; } bool g_profiling_active = false; +void set_profiling_active(bool val) { g_profiling_active = val; } const wchar_t *program_name; diff --git a/src/common.h b/src/common.h index 8db5a9115..b1fb270b9 100644 --- a/src/common.h +++ b/src/common.h @@ -188,6 +188,7 @@ wchar_t get_obfuscation_read_char(); /// Profiling flag. True if commands should be profiled. extern bool g_profiling_active; +void set_profiling_active(bool val); /// Name of the current program. Should be set at startup. Used by the debug function. extern const wchar_t *program_name; diff --git a/src/flog.cpp b/src/flog.cpp index b6f0ee61d..ea0bca843 100644 --- a/src/flog.cpp +++ b/src/flog.cpp @@ -172,6 +172,21 @@ void activate_flog_categories_by_pattern(wcstring wc) { } } +// autocxx fails with FILE* +void set_flog_output_file_ffi(void* fp) { + auto f = static_cast(fp); + set_flog_output_file(f); +} + +// Rust libc does not contain setlinebuf +void flog_setlinebuf_ffi(void *f) { + auto fp = static_cast(f); + if (fp == nullptr) { + return; + } + setlinebuf(fp); +} + void set_flog_output_file(FILE *f) { assert(f && "Null file"); g_logger.acquire()->set_file(f); diff --git a/src/flog.h b/src/flog.h index 594a8279f..72821c0da 100644 --- a/src/flog.h +++ b/src/flog.h @@ -185,6 +185,8 @@ extern owning_lock g_logger; /// Set the active flog categories according to the given wildcard \p wc. void activate_flog_categories_by_pattern(wcstring wc); +void set_flog_output_file_ffi(void *fp); +void flog_setlinebuf_ffi(void *f); /// Set the file that flog should output to. /// flog does not close this file. void set_flog_output_file(FILE *f); diff --git a/src/parse_util.cpp b/src/parse_util.cpp index 3cf17dfe2..8b32728cf 100644 --- a/src/parse_util.cpp +++ b/src/parse_util.cpp @@ -1068,6 +1068,11 @@ static bool detect_errors_in_block_redirection_list( return false; } +parser_test_error_bits_t parse_util_detect_errors_ffi(const ast::ast_t* ast, const wcstring &buff_src, + parse_error_list_t *out_errors) { + return parse_util_detect_errors(*ast, buff_src, out_errors); +} + parser_test_error_bits_t parse_util_detect_errors(const ast::ast_t &ast, const wcstring &buff_src, parse_error_list_t *out_errors) { using namespace ast; diff --git a/src/parse_util.h b/src/parse_util.h index 27ff06a86..9d231b23d 100644 --- a/src/parse_util.h +++ b/src/parse_util.h @@ -126,6 +126,9 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, parse_error_list_t *out_errors = nullptr, bool allow_incomplete = false); +parser_test_error_bits_t parse_util_detect_errors_ffi(const ast::ast_t *ast, + const wcstring &buff_src, + parse_error_list_t *out_errors); /// Like parse_util_detect_errors but accepts an already-parsed ast. /// The top of the ast is assumed to be a job list. parser_test_error_bits_t parse_util_detect_errors(const ast::ast_t &ast, const wcstring &buff_src, diff --git a/src/parser.cpp b/src/parser.cpp index e5c49f67b..7701f68aa 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -417,6 +417,10 @@ filename_ref_t parser_t::current_filename() const { return libdata().current_filename; } +void parser_t::set_filename_ffi(wcstring filename) { + libdata().current_filename = std::make_shared(filename); +} + // FFI glue wcstring parser_t::current_filename_ffi() const { auto filename = current_filename(); @@ -586,6 +590,10 @@ eval_res_t parser_t::eval_with(const wcstring &cmd, const io_chain_t &io, eval_res_t parser_t::eval_string_ffi1(const wcstring &cmd) { return eval(cmd, io_chain_t()); } +eval_res_t parser_t::eval_parsed_source_ffi1(const parsed_source_ref_t* ps, enum block_type_t block_type) { + return eval_parsed_source(*ps, io_chain_t(), {}, block_type); +} + eval_res_t parser_t::eval_parsed_source(const parsed_source_ref_t &ps, const io_chain_t &io, const job_group_ref_t &job_group, enum block_type_t block_type) { @@ -690,6 +698,10 @@ template eval_res_t parser_t::eval_node(const parsed_source_ref_t &, const ast:: template eval_res_t parser_t::eval_node(const parsed_source_ref_t &, const ast::job_list_t &, const io_chain_t &, const job_group_ref_t &, block_type_t); +void parser_t::get_backtrace_ffi(const wcstring &src, const parse_error_list_t* errors, + wcstring &output) const { + return get_backtrace(src, *errors, output); +}; void parser_t::get_backtrace(const wcstring &src, const parse_error_list_t &errors, wcstring &output) const { if (!errors.empty()) { diff --git a/src/parser.h b/src/parser.h index 5c5cdc411..1d0dcadb4 100644 --- a/src/parser.h +++ b/src/parser.h @@ -349,7 +349,7 @@ class parser_t : public std::enable_shared_from_this { eval_res_t eval_parsed_source(const parsed_source_ref_t &ps, const io_chain_t &io, const job_group_ref_t &job_group = {}, block_type_t block_type = block_type_t::top); - + eval_res_t eval_parsed_source_ffi1(const parsed_source_ref_t* ps, block_type_t block_type); /// Evaluates a node. /// The node type must be ast_t::statement_t or ast::job_list_t. template @@ -466,6 +466,8 @@ class parser_t : public std::enable_shared_from_this { /// Output profiling data to the given filename. void emit_profiling(const char *path) const; + void get_backtrace_ffi(const wcstring &src, const parse_error_list_t* errors, + wcstring &output) const; void get_backtrace(const wcstring &src, const parse_error_list_t &errors, wcstring &output) const; @@ -474,6 +476,7 @@ class parser_t : public std::enable_shared_from_this { /// than the one currently read. filename_ref_t current_filename() const; wcstring current_filename_ffi() const; + void set_filename_ffi(wcstring filename); /// Return if we are interactive, which means we are executing a command that the user typed in /// (and not, say, a prompt). diff --git a/src/reader.cpp b/src/reader.cpp index a25a644b1..982d8b1c1 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -4842,6 +4842,10 @@ static int read_ni(parser_t &parser, int fd, const io_chain_t &io) { } } +int reader_read_ffi(parser_t &parser, int fd) { + return reader_read(parser, fd, {}); +} + int reader_read(parser_t &parser, int fd, const io_chain_t &io) { int res; diff --git a/src/reader.h b/src/reader.h index 56801d579..6e9ba9fbd 100644 --- a/src/reader.h +++ b/src/reader.h @@ -139,6 +139,7 @@ class editable_line_t { uint32_t edit_group_id_ = -1; }; +int reader_read_ffi(parser_t &parser, int fd); /// Read commands from \c fd until encountering EOF. /// The fd is not closed. int reader_read(parser_t &parser, int fd, const io_chain_t &io);