diff --git a/builtin-functions/_functions.txt b/builtin-functions/_functions.txt index 9e6e139f39..ba2c5aeeef 100644 --- a/builtin-functions/_functions.txt +++ b/builtin-functions/_functions.txt @@ -1620,3 +1620,7 @@ class DateTimeImmutable implements DateTimeInterface { } function getenv(string $varname = '', bool $local_only = false): mixed; + +//2022-04-19 comm644 +function popen ($command ::: string, $mode ::: string) ::: mixed; +function pclose ($stream ::: mixed ) ::: bool; diff --git a/runtime/files.cpp b/runtime/files.cpp index 06a346f965..7fd6fe1a1b 100644 --- a/runtime/files.cpp +++ b/runtime/files.cpp @@ -412,6 +412,11 @@ Optional f$realpath(const string &path) { } static Optional full_realpath(const string &path) { // realpath resolving only dirname to work with unexisted files + + if (!strncmp(path.c_str(), "popen://", 8)) { + return path; + } + static char full_realpath_cache_storage[sizeof(array)]; static array *full_realpath_cache = reinterpret_cast *> (full_realpath_cache_storage); static long long full_realpath_last_query_num = -1; @@ -939,3 +944,4 @@ void free_files_lib() { dl::leave_critical_section(); } +#include "files_popen.cpp" diff --git a/runtime/files.h b/runtime/files.h index 0da8704f05..97646237c8 100644 --- a/runtime/files.h +++ b/runtime/files.h @@ -72,3 +72,5 @@ Optional file_file_get_contents(const string &name); void global_init_files_lib(); void free_files_lib(); + +#include "files_popen.h" \ No newline at end of file diff --git a/runtime/files_popen.cpp b/runtime/files_popen.cpp new file mode 100644 index 0000000000..1b23374f42 --- /dev/null +++ b/runtime/files_popen.cpp @@ -0,0 +1,90 @@ +#include "streams.h" +#include "files_popen.h" + +#include +#include "runtime/string_functions.h"//php_buf, TODO + +const string popen_wrapper_name("popen://", 8); + +//2022-04-19 av +Stream f$popen(const string &command, const string &mode) +{ + if (dl::query_num != opened_files_last_query_num) { + new(opened_files_storage) array(); + + opened_files_last_query_num = dl::query_num; + } + string fullname = popen_wrapper_name; + fullname.append( command ); + + printf("open: %s\n", fullname.c_str()); + dl::enter_critical_section();//NOT OK: opened_files + FILE *file = popen(command.c_str(), mode.c_str()); + if (file == nullptr) { + dl::leave_critical_section(); + return false; + } + + opened_files->set_value(fullname, file); + dl::leave_critical_section(); + + return fullname; +} + +bool f$pclose(const Stream &stream) { + + string filename = stream.to_string(); + if (dl::query_num == opened_files_last_query_num && opened_files->has_key(filename)) { + dl::enter_critical_section();//NOT OK: opened_files + int result = pclose(opened_files->get_value(filename)); + opened_files->unset(filename); + dl::leave_critical_section(); + return (result == 0); + } + return false; +} + +void global_init_popen_lib() { + static stream_functions file_stream_functions; + + file_stream_functions.name = string("popen", 5); + file_stream_functions.fopen = f$popen; + file_stream_functions.fwrite = file_fwrite; + file_stream_functions.fseek = nullptr;; + file_stream_functions.ftell = nullptr; + file_stream_functions.fread = file_fread; + file_stream_functions.fgetc = file_fgetc; + file_stream_functions.fgets = file_fgets; + file_stream_functions.fpassthru = file_fpassthru; + file_stream_functions.fflush = file_fflush; + file_stream_functions.feof = file_feof; + file_stream_functions.fclose = f$pclose; + + file_stream_functions.file_get_contents = file_file_get_contents; + file_stream_functions.file_put_contents = file_file_put_contents; + + file_stream_functions.stream_socket_client = nullptr; + file_stream_functions.context_set_option = nullptr; + file_stream_functions.stream_set_option = nullptr; + file_stream_functions.get_fd = nullptr; + + register_stream_functions(&file_stream_functions, false); +} + + +void free_popen_lib() { + dl::enter_critical_section();//OK + if (dl::query_num == opened_files_last_query_num) { + const array *const_opened_files = opened_files; + for (array::const_iterator p = const_opened_files->begin(); p != const_opened_files->end(); ++p) { + fclose(p.get_value()); + } + opened_files_last_query_num--; + } + + if (opened_fd != -1) { + close_safe(opened_fd); + } + opened_fd = -1; + dl::leave_critical_section(); +} diff --git a/runtime/files_popen.h b/runtime/files_popen.h new file mode 100644 index 0000000000..bc4f171c41 --- /dev/null +++ b/runtime/files_popen.h @@ -0,0 +1,13 @@ +#pragma once + +#include "runtime/kphp_core.h" + +using Stream =mixed; + +//2022-04-19 av (comm644) +Stream f$popen(const string &stream, const string &mode); +bool f$pclose(const Stream &stream); + +void global_init_popen_lib(); + +void free_popen_lib(); diff --git a/runtime/interface.cpp b/runtime/interface.cpp index 60707154dc..d17eceb185 100644 --- a/runtime/interface.cpp +++ b/runtime/interface.cpp @@ -2389,6 +2389,7 @@ void global_init_runtime_libs() { global_init_profiler(); global_init_instance_cache_lib(); global_init_files_lib(); + global_init_popen_lib(); global_init_interface_lib(); global_init_openssl_lib(); global_init_regexp_lib();