feat: modules moved and engine moved to submodule
This commit is contained in:
parent
dfb5e645cd
commit
c33d2130cc
5136 changed files with 225275 additions and 64485 deletions
|
|
@ -43,6 +43,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#ifdef HAVE_MNTENT
|
||||
|
|
@ -256,7 +257,7 @@ static void _get_drives(List<String> *list) {
|
|||
// Parse only file:// links
|
||||
if (strncmp(string, "file://", 7) == 0) {
|
||||
// Strip any unwanted edges on the strings and push_back if it's not a duplicate.
|
||||
String fpath = String::utf8(string + 7).strip_edges().split_spaces()[0].uri_decode();
|
||||
String fpath = String::utf8(string + 7).strip_edges().split_spaces()[0].uri_file_decode();
|
||||
if (!list->find(fpath)) {
|
||||
list->push_back(fpath);
|
||||
}
|
||||
|
|
@ -342,7 +343,7 @@ Error DirAccessUnix::change_dir(String p_dir) {
|
|||
String prev_dir;
|
||||
char real_current_dir_name[2048];
|
||||
ERR_FAIL_NULL_V(getcwd(real_current_dir_name, 2048), ERR_BUG);
|
||||
if (prev_dir.parse_utf8(real_current_dir_name) != OK) {
|
||||
if (prev_dir.append_utf8(real_current_dir_name) != OK) {
|
||||
prev_dir = real_current_dir_name; //no utf8, maybe latin?
|
||||
}
|
||||
|
||||
|
|
@ -365,7 +366,7 @@ Error DirAccessUnix::change_dir(String p_dir) {
|
|||
if (!base.is_empty() && !try_dir.begins_with(base)) {
|
||||
ERR_FAIL_NULL_V(getcwd(real_current_dir_name, 2048), ERR_BUG);
|
||||
String new_dir;
|
||||
new_dir.parse_utf8(real_current_dir_name);
|
||||
new_dir.append_utf8(real_current_dir_name);
|
||||
|
||||
if (!new_dir.begins_with(base)) {
|
||||
try_dir = current_dir; //revert
|
||||
|
|
@ -383,7 +384,7 @@ String DirAccessUnix::get_current_dir(bool p_include_drive) const {
|
|||
if (!base.is_empty()) {
|
||||
String bd = current_dir.replace_first(base, "");
|
||||
if (bd.begins_with("/")) {
|
||||
return _get_root_string() + bd.substr(1, bd.length());
|
||||
return _get_root_string() + bd.substr(1);
|
||||
} else {
|
||||
return _get_root_string() + bd;
|
||||
}
|
||||
|
|
@ -486,7 +487,7 @@ String DirAccessUnix::read_link(String p_file) {
|
|||
ssize_t len = readlink(p_file.utf8().get_data(), buf, sizeof(buf));
|
||||
String link;
|
||||
if (len > 0) {
|
||||
link.parse_utf8(buf, len);
|
||||
link.append_utf8(buf, len);
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
|
@ -544,6 +545,24 @@ bool DirAccessUnix::is_case_sensitive(const String &p_path) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DirAccessUnix::is_equivalent(const String &p_path_a, const String &p_path_b) const {
|
||||
String f1 = fix_path(p_path_a);
|
||||
struct stat st1 = {};
|
||||
int err = stat(f1.utf8().get_data(), &st1);
|
||||
if (err) {
|
||||
return DirAccess::is_equivalent(p_path_a, p_path_b);
|
||||
}
|
||||
|
||||
String f2 = fix_path(p_path_b);
|
||||
struct stat st2 = {};
|
||||
err = stat(f2.utf8().get_data(), &st2);
|
||||
if (err) {
|
||||
return DirAccess::is_equivalent(p_path_a, p_path_b);
|
||||
}
|
||||
|
||||
return (st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino);
|
||||
}
|
||||
|
||||
DirAccessUnix::DirAccessUnix() {
|
||||
dir_stream = nullptr;
|
||||
_cisdir = false;
|
||||
|
|
@ -553,7 +572,8 @@ DirAccessUnix::DirAccessUnix() {
|
|||
// set current directory to an absolute path of the current directory
|
||||
char real_current_dir_name[2048];
|
||||
ERR_FAIL_NULL(getcwd(real_current_dir_name, 2048));
|
||||
if (current_dir.parse_utf8(real_current_dir_name) != OK) {
|
||||
current_dir.clear();
|
||||
if (current_dir.append_utf8(real_current_dir_name) != OK) {
|
||||
current_dir = real_current_dir_name;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DIR_ACCESS_UNIX_H
|
||||
#define DIR_ACCESS_UNIX_H
|
||||
#pragma once
|
||||
|
||||
#if defined(UNIX_ENABLED)
|
||||
|
||||
|
|
@ -41,6 +40,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
class DirAccessUnix : public DirAccess {
|
||||
GDSOFTCLASS(DirAccessUnix, DirAccess);
|
||||
DIR *dir_stream = nullptr;
|
||||
|
||||
bool _cisdir = false;
|
||||
|
|
@ -86,6 +86,7 @@ public:
|
|||
virtual Error create_link(String p_source, String p_target) override;
|
||||
|
||||
virtual bool is_case_sensitive(const String &p_path) const override;
|
||||
virtual bool is_equivalent(const String &p_path_a, const String &p_path_b) const override;
|
||||
|
||||
virtual uint64_t get_space_left() override;
|
||||
|
||||
|
|
@ -96,5 +97,3 @@ public:
|
|||
};
|
||||
|
||||
#endif // UNIX_ENABLED
|
||||
|
||||
#endif // DIR_ACCESS_UNIX_H
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ String FileAccessUnix::get_real_path() const {
|
|||
}
|
||||
|
||||
String result;
|
||||
Error parse_ok = result.parse_utf8(resolved_path);
|
||||
Error parse_ok = result.append_utf8(resolved_path);
|
||||
::free(resolved_path);
|
||||
|
||||
if (parse_ok != OK) {
|
||||
|
|
@ -336,16 +336,19 @@ bool FileAccessUnix::file_exists(const String &p_path) {
|
|||
|
||||
uint64_t FileAccessUnix::_get_modified_time(const String &p_file) {
|
||||
String file = fix_path(p_file);
|
||||
struct stat status = {};
|
||||
int err = stat(file.utf8().get_data(), &status);
|
||||
struct stat st = {};
|
||||
int err = stat(file.utf8().get_data(), &st);
|
||||
|
||||
if (!err) {
|
||||
uint64_t modified_time = status.st_mtime;
|
||||
uint64_t modified_time = 0;
|
||||
if ((st.st_mode & S_IFMT) == S_IFLNK || (st.st_mode & S_IFMT) == S_IFREG || (st.st_mode & S_IFDIR) == S_IFDIR) {
|
||||
modified_time = st.st_mtime;
|
||||
}
|
||||
#ifdef ANDROID_ENABLED
|
||||
// Workaround for GH-101007
|
||||
//FIXME: After saving, all timestamps (st_mtime, st_ctime, st_atime) are set to the same value.
|
||||
// After exporting or after some time, only 'modified_time' resets to a past timestamp.
|
||||
uint64_t created_time = status.st_ctime;
|
||||
uint64_t created_time = st.st_ctime;
|
||||
if (modified_time < created_time) {
|
||||
modified_time = created_time;
|
||||
}
|
||||
|
|
@ -356,6 +359,32 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) {
|
|||
}
|
||||
}
|
||||
|
||||
uint64_t FileAccessUnix::_get_access_time(const String &p_file) {
|
||||
String file = fix_path(p_file);
|
||||
struct stat st = {};
|
||||
int err = stat(file.utf8().get_data(), &st);
|
||||
|
||||
if (!err) {
|
||||
if ((st.st_mode & S_IFMT) == S_IFLNK || (st.st_mode & S_IFMT) == S_IFREG || (st.st_mode & S_IFDIR) == S_IFDIR) {
|
||||
return st.st_atime;
|
||||
}
|
||||
}
|
||||
ERR_FAIL_V_MSG(0, "Failed to get access time for: " + p_file + "");
|
||||
}
|
||||
|
||||
int64_t FileAccessUnix::_get_size(const String &p_file) {
|
||||
String file = fix_path(p_file);
|
||||
struct stat st = {};
|
||||
int err = stat(file.utf8().get_data(), &st);
|
||||
|
||||
if (!err) {
|
||||
if ((st.st_mode & S_IFMT) == S_IFLNK || (st.st_mode & S_IFMT) == S_IFREG) {
|
||||
return st.st_size;
|
||||
}
|
||||
}
|
||||
ERR_FAIL_V_MSG(-1, "Failed to get size for: " + p_file + "");
|
||||
}
|
||||
|
||||
BitField<FileAccess::UnixPermissionFlags> FileAccessUnix::_get_unix_permissions(const String &p_file) {
|
||||
String file = fix_path(p_file);
|
||||
struct stat status = {};
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef FILE_ACCESS_UNIX_H
|
||||
#define FILE_ACCESS_UNIX_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/os/memory.h"
|
||||
|
|
@ -39,6 +38,7 @@
|
|||
#if defined(UNIX_ENABLED)
|
||||
|
||||
class FileAccessUnix : public FileAccess {
|
||||
GDSOFTCLASS(FileAccessUnix, FileAccess);
|
||||
FILE *f = nullptr;
|
||||
int flags = 0;
|
||||
void check_errors(bool p_write = false) const;
|
||||
|
|
@ -81,6 +81,8 @@ public:
|
|||
virtual bool file_exists(const String &p_path) override; ///< return true if a file exists
|
||||
|
||||
virtual uint64_t _get_modified_time(const String &p_file) override;
|
||||
virtual uint64_t _get_access_time(const String &p_file) override;
|
||||
virtual int64_t _get_size(const String &p_file) override;
|
||||
virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override;
|
||||
virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override;
|
||||
|
||||
|
|
@ -96,5 +98,3 @@ public:
|
|||
};
|
||||
|
||||
#endif // UNIX_ENABLED
|
||||
|
||||
#endif // FILE_ACCESS_UNIX_H
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ Error FileAccessUnixPipe::open_internal(const String &p_path, int p_mode_flags)
|
|||
path_src = p_path;
|
||||
ERR_FAIL_COND_V_MSG(fd[0] >= 0 || fd[1] >= 0, ERR_ALREADY_IN_USE, "Pipe is already in use.");
|
||||
|
||||
path = String("/tmp/") + p_path.replace("pipe://", "").replace("/", "_");
|
||||
path = String("/tmp/") + p_path.replace("pipe://", "").replace_char('/', '_');
|
||||
const CharString path_utf8 = path.utf8();
|
||||
|
||||
struct stat st = {};
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef FILE_ACCESS_UNIX_PIPE_H
|
||||
#define FILE_ACCESS_UNIX_PIPE_H
|
||||
#pragma once
|
||||
|
||||
#include "core/io/file_access.h"
|
||||
#include "core/os/memory.h"
|
||||
|
|
@ -39,6 +38,7 @@
|
|||
#if defined(UNIX_ENABLED)
|
||||
|
||||
class FileAccessUnixPipe : public FileAccess {
|
||||
GDSOFTCLASS(FileAccessUnixPipe, FileAccess);
|
||||
bool unlink_on_close = false;
|
||||
|
||||
int fd[2] = { -1, -1 };
|
||||
|
|
@ -76,6 +76,8 @@ public:
|
|||
virtual bool file_exists(const String &p_path) override { return false; }
|
||||
|
||||
virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
|
||||
virtual uint64_t _get_access_time(const String &p_file) override { return 0; }
|
||||
virtual int64_t _get_size(const String &p_file) override { return -1; }
|
||||
virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; }
|
||||
virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return ERR_UNAVAILABLE; }
|
||||
|
||||
|
|
@ -91,5 +93,3 @@ public:
|
|||
};
|
||||
|
||||
#endif // UNIX_ENABLED
|
||||
|
||||
#endif // FILE_ACCESS_UNIX_PIPE_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef IP_UNIX_H
|
||||
#define IP_UNIX_H
|
||||
#pragma once
|
||||
|
||||
#if defined(UNIX_ENABLED) && !defined(UNIX_SOCKET_UNAVAILABLE)
|
||||
|
||||
|
|
@ -50,5 +49,3 @@ public:
|
|||
};
|
||||
|
||||
#endif // UNIX_ENABLED
|
||||
|
||||
#endif // IP_UNIX_H
|
||||
|
|
|
|||
|
|
@ -135,10 +135,7 @@ NetSocketUnix::~NetSocketUnix() {
|
|||
|
||||
// Silence a warning reported in GH-27594.
|
||||
// EAGAIN and EWOULDBLOCK have the same value on most platforms, but it's not guaranteed.
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wlogical-op")
|
||||
|
||||
NetSocketUnix::NetError NetSocketUnix::_get_socket_error() const {
|
||||
if (errno == EISCONN) {
|
||||
|
|
@ -163,9 +160,7 @@ NetSocketUnix::NetError NetSocketUnix::_get_socket_error() const {
|
|||
return ERR_NET_OTHER;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
GODOT_GCC_WARNING_POP
|
||||
|
||||
bool NetSocketUnix::_can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const {
|
||||
if (p_for_bind && !(p_ip.is_valid() || p_ip.is_wildcard())) {
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef NET_SOCKET_UNIX_H
|
||||
#define NET_SOCKET_UNIX_H
|
||||
#pragma once
|
||||
|
||||
#if defined(UNIX_ENABLED) && !defined(UNIX_SOCKET_UNAVAILABLE)
|
||||
|
||||
|
|
@ -98,5 +97,3 @@ public:
|
|||
};
|
||||
|
||||
#endif // UNIX_ENABLED && !UNIX_SOCKET_UNAVAILABLE
|
||||
|
||||
#endif // NET_SOCKET_UNIX_H
|
||||
|
|
|
|||
|
|
@ -580,6 +580,126 @@ Dictionary OS_Unix::get_memory_info() const {
|
|||
return meminfo;
|
||||
}
|
||||
|
||||
#ifndef __GLIBC__
|
||||
void OS_Unix::_load_iconv() {
|
||||
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
||||
String iconv_lib_aliases[] = { "/usr/lib/libiconv.2.dylib" };
|
||||
String iconv_func_aliases[] = { "iconv" };
|
||||
String charset_lib_aliases[] = { "/usr/lib/libcharset.1.dylib" };
|
||||
#else
|
||||
String iconv_lib_aliases[] = { "", "libiconv.2.so", "libiconv.so" };
|
||||
String iconv_func_aliases[] = { "libiconv", "iconv", "bsd_iconv", "rpl_iconv" };
|
||||
String charset_lib_aliases[] = { "", "libcharset.1.so", "libcharset.so" };
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < sizeof(iconv_lib_aliases) / sizeof(iconv_lib_aliases[0]); i++) {
|
||||
void *iconv_lib = iconv_lib_aliases[i].is_empty() ? RTLD_NEXT : dlopen(iconv_lib_aliases[i].utf8().get_data(), RTLD_NOW);
|
||||
if (iconv_lib) {
|
||||
for (size_t j = 0; j < sizeof(iconv_func_aliases) / sizeof(iconv_func_aliases[0]); j++) {
|
||||
gd_iconv_open = (PIConvOpen)dlsym(iconv_lib, (iconv_func_aliases[j] + "_open").utf8().get_data());
|
||||
gd_iconv = (PIConv)dlsym(iconv_lib, (iconv_func_aliases[j]).utf8().get_data());
|
||||
gd_iconv_close = (PIConvClose)dlsym(iconv_lib, (iconv_func_aliases[j] + "_close").utf8().get_data());
|
||||
if (gd_iconv_open && gd_iconv && gd_iconv_close) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (gd_iconv_open && gd_iconv && gd_iconv_close) {
|
||||
break;
|
||||
}
|
||||
if (!iconv_lib_aliases[i].is_empty()) {
|
||||
dlclose(iconv_lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(charset_lib_aliases) / sizeof(charset_lib_aliases[0]); i++) {
|
||||
void *cs_lib = charset_lib_aliases[i].is_empty() ? RTLD_NEXT : dlopen(charset_lib_aliases[i].utf8().get_data(), RTLD_NOW);
|
||||
if (cs_lib) {
|
||||
gd_locale_charset = (PIConvLocaleCharset)dlsym(cs_lib, "locale_charset");
|
||||
if (gd_locale_charset) {
|
||||
break;
|
||||
}
|
||||
if (!charset_lib_aliases[i].is_empty()) {
|
||||
dlclose(cs_lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
_iconv_ok = gd_iconv_open && gd_iconv && gd_iconv_close && gd_locale_charset;
|
||||
}
|
||||
#endif
|
||||
|
||||
String OS_Unix::multibyte_to_string(const String &p_encoding, const PackedByteArray &p_array) const {
|
||||
ERR_FAIL_COND_V_MSG(!_iconv_ok, String(), "Conversion failed: Unable to load libiconv");
|
||||
|
||||
LocalVector<char> chars;
|
||||
#ifdef __GLIBC__
|
||||
gd_iconv_t ctx = gd_iconv_open("UTF-8", p_encoding.is_empty() ? nl_langinfo(CODESET) : p_encoding.utf8().get_data());
|
||||
#else
|
||||
gd_iconv_t ctx = gd_iconv_open("UTF-8", p_encoding.is_empty() ? gd_locale_charset() : p_encoding.utf8().get_data());
|
||||
#endif
|
||||
ERR_FAIL_COND_V_MSG(ctx == (gd_iconv_t)(-1), String(), "Conversion failed: Unknown encoding");
|
||||
|
||||
char *in_ptr = (char *)p_array.ptr();
|
||||
size_t in_size = p_array.size();
|
||||
|
||||
chars.resize(in_size);
|
||||
char *out_ptr = (char *)chars.ptr();
|
||||
size_t out_size = chars.size();
|
||||
|
||||
while (gd_iconv(ctx, &in_ptr, &in_size, &out_ptr, &out_size) == (size_t)-1) {
|
||||
if (errno != E2BIG) {
|
||||
gd_iconv_close(ctx);
|
||||
ERR_FAIL_V_MSG(String(), vformat("Conversion failed: %d - %s", errno, strerror(errno)));
|
||||
}
|
||||
int64_t rate = (chars.size()) / (p_array.size() - in_size);
|
||||
size_t oldpos = chars.size() - out_size;
|
||||
chars.resize(chars.size() + in_size * rate);
|
||||
out_ptr = (char *)chars.ptr() + oldpos;
|
||||
out_size = chars.size() - oldpos;
|
||||
}
|
||||
chars.resize(chars.size() - out_size);
|
||||
gd_iconv_close(ctx);
|
||||
|
||||
return String::utf8((const char *)chars.ptr(), chars.size());
|
||||
}
|
||||
|
||||
PackedByteArray OS_Unix::string_to_multibyte(const String &p_encoding, const String &p_string) const {
|
||||
ERR_FAIL_COND_V_MSG(!_iconv_ok, PackedByteArray(), "Conversion failed: Unable to load libiconv");
|
||||
|
||||
CharString charstr = p_string.utf8();
|
||||
|
||||
PackedByteArray ret;
|
||||
#ifdef __GLIBC__
|
||||
gd_iconv_t ctx = gd_iconv_open(p_encoding.is_empty() ? nl_langinfo(CODESET) : p_encoding.utf8().get_data(), "UTF-8");
|
||||
#else
|
||||
gd_iconv_t ctx = gd_iconv_open(p_encoding.is_empty() ? gd_locale_charset() : p_encoding.utf8().get_data(), "UTF-8");
|
||||
#endif
|
||||
ERR_FAIL_COND_V_MSG(ctx == (gd_iconv_t)(-1), PackedByteArray(), "Conversion failed: Unknown encoding");
|
||||
|
||||
char *in_ptr = (char *)charstr.ptr();
|
||||
size_t in_size = charstr.size();
|
||||
|
||||
ret.resize(in_size);
|
||||
char *out_ptr = (char *)ret.ptrw();
|
||||
size_t out_size = ret.size();
|
||||
|
||||
while (gd_iconv(ctx, &in_ptr, &in_size, &out_ptr, &out_size) == (size_t)-1) {
|
||||
if (errno != E2BIG) {
|
||||
gd_iconv_close(ctx);
|
||||
ERR_FAIL_V_MSG(PackedByteArray(), vformat("Conversion failed: %d - %s", errno, strerror(errno)));
|
||||
}
|
||||
int64_t rate = (ret.size()) / (charstr.size() - in_size);
|
||||
size_t oldpos = ret.size() - out_size;
|
||||
ret.resize(ret.size() + in_size * rate);
|
||||
out_ptr = (char *)ret.ptrw() + oldpos;
|
||||
out_size = ret.size() - oldpos;
|
||||
}
|
||||
ret.resize(ret.size() - out_size);
|
||||
gd_iconv_close(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Dictionary OS_Unix::execute_with_pipe(const String &p_path, const List<String> &p_arguments, bool p_blocking) {
|
||||
#define CLEAN_PIPES \
|
||||
if (pipe_in[0] >= 0) { \
|
||||
|
|
@ -685,6 +805,57 @@ Dictionary OS_Unix::execute_with_pipe(const String &p_path, const List<String> &
|
|||
#endif
|
||||
}
|
||||
|
||||
int OS_Unix::_wait_for_pid_completion(const pid_t p_pid, int *r_status, int p_options) {
|
||||
while (true) {
|
||||
if (waitpid(p_pid, r_status, p_options) != -1) {
|
||||
// Thread exited normally.
|
||||
return 0;
|
||||
}
|
||||
const int error = errno;
|
||||
if (error == EINTR) {
|
||||
// We're in a debugger, should call waitpid again.
|
||||
// See https://stackoverflow.com/a/45472920/730797.
|
||||
continue;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
bool OS_Unix::_check_pid_is_running(const pid_t p_pid, int *r_status) const {
|
||||
const ProcessInfo *pi = process_map->getptr(p_pid);
|
||||
|
||||
if (pi && !pi->is_running) {
|
||||
// Can return cached value.
|
||||
if (r_status) {
|
||||
*r_status = pi->exit_code;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
const int result = _wait_for_pid_completion(p_pid, &status, WNOHANG);
|
||||
if (result == 0) {
|
||||
// Thread is still running.
|
||||
return true;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(result == -1, false, vformat("Thread %d exited with errno: %d", (int)p_pid, errno));
|
||||
// Thread exited normally.
|
||||
|
||||
status = WIFEXITED(status) ? WEXITSTATUS(status) : status;
|
||||
|
||||
if (pi) {
|
||||
pi->is_running = false;
|
||||
pi->exit_code = status;
|
||||
}
|
||||
|
||||
if (r_status) {
|
||||
*r_status = status;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// Don't compile this code at all to avoid undefined references.
|
||||
|
|
@ -710,7 +881,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, St
|
|||
p_pipe_mutex->lock();
|
||||
}
|
||||
String pipe_out;
|
||||
if (pipe_out.parse_utf8(buf) == OK) {
|
||||
if (pipe_out.append_utf8(buf) == OK) {
|
||||
(*r_pipe) += pipe_out;
|
||||
} else {
|
||||
(*r_pipe) += String(buf); // If not valid UTF-8 try decode as Latin-1
|
||||
|
|
@ -750,12 +921,12 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, St
|
|||
raise(SIGKILL);
|
||||
}
|
||||
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
int status = 0;
|
||||
const int result = _wait_for_pid_completion(pid, &status, 0);
|
||||
if (r_exitcode) {
|
||||
*r_exitcode = WIFEXITED(status) ? WEXITSTATUS(status) : status;
|
||||
}
|
||||
return OK;
|
||||
return result ? FAILED : OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -809,7 +980,7 @@ Error OS_Unix::kill(const ProcessID &p_pid) {
|
|||
if (!ret) {
|
||||
//avoid zombie process
|
||||
int st;
|
||||
::waitpid(p_pid, &st, 0);
|
||||
_wait_for_pid_completion(p_pid, &st, 0);
|
||||
}
|
||||
return ret ? ERR_INVALID_PARAMETER : OK;
|
||||
}
|
||||
|
|
@ -820,42 +991,19 @@ int OS_Unix::get_process_id() const {
|
|||
|
||||
bool OS_Unix::is_process_running(const ProcessID &p_pid) const {
|
||||
MutexLock lock(process_map_mutex);
|
||||
const ProcessInfo *pi = process_map->getptr(p_pid);
|
||||
|
||||
if (pi && !pi->is_running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
if (waitpid(p_pid, &status, WNOHANG) != 0) {
|
||||
if (pi) {
|
||||
pi->is_running = false;
|
||||
pi->exit_code = status;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return _check_pid_is_running(p_pid, nullptr);
|
||||
}
|
||||
|
||||
int OS_Unix::get_process_exit_code(const ProcessID &p_pid) const {
|
||||
MutexLock lock(process_map_mutex);
|
||||
const ProcessInfo *pi = process_map->getptr(p_pid);
|
||||
|
||||
if (pi && !pi->is_running) {
|
||||
return pi->exit_code;
|
||||
int exit_code = 0;
|
||||
if (_check_pid_is_running(p_pid, &exit_code)) {
|
||||
// Thread is still running
|
||||
return -1;
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
if (waitpid(p_pid, &status, WNOHANG) != 0) {
|
||||
status = WIFEXITED(status) ? WEXITSTATUS(status) : status;
|
||||
if (pi) {
|
||||
pi->is_running = false;
|
||||
pi->exit_code = status;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
return -1;
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
String OS_Unix::get_locale() const {
|
||||
|
|
@ -942,7 +1090,7 @@ String OS_Unix::get_environment(const String &p_var) const {
|
|||
return "";
|
||||
}
|
||||
String s;
|
||||
if (s.parse_utf8(val) == OK) {
|
||||
if (s.append_utf8(val) == OK) {
|
||||
return s;
|
||||
}
|
||||
return String(val); // Not valid UTF-8, so return as-is
|
||||
|
|
@ -971,7 +1119,7 @@ String OS_Unix::get_executable_path() const {
|
|||
ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf));
|
||||
String b;
|
||||
if (len > 0) {
|
||||
b.parse_utf8(buf, len);
|
||||
b.append_utf8(buf, len);
|
||||
}
|
||||
if (b.is_empty()) {
|
||||
WARN_PRINT("Couldn't get executable path from /proc/self/exe, using argv[0]");
|
||||
|
|
@ -1007,9 +1155,8 @@ String OS_Unix::get_executable_path() const {
|
|||
WARN_PRINT("Couldn't get executable path from sysctl");
|
||||
return OS::get_executable_path();
|
||||
}
|
||||
String b;
|
||||
b.parse_utf8(buf);
|
||||
return b;
|
||||
|
||||
return String::utf8(buf);
|
||||
#elif defined(__APPLE__)
|
||||
char temp_path[1];
|
||||
uint32_t buff_size = 1;
|
||||
|
|
@ -1082,6 +1229,10 @@ void UnixTerminalLogger::log_error(const char *p_function, const char *p_file, i
|
|||
UnixTerminalLogger::~UnixTerminalLogger() {}
|
||||
|
||||
OS_Unix::OS_Unix() {
|
||||
#ifndef __GLIBC__
|
||||
_load_iconv();
|
||||
#endif
|
||||
|
||||
Vector<Logger *> loggers;
|
||||
loggers.push_back(memnew(UnixTerminalLogger));
|
||||
_set_logger(memnew(CompositeLogger(loggers)));
|
||||
|
|
|
|||
|
|
@ -28,14 +28,28 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef OS_UNIX_H
|
||||
#define OS_UNIX_H
|
||||
#pragma once
|
||||
|
||||
#ifdef UNIX_ENABLED
|
||||
|
||||
#include "core/os/os.h"
|
||||
#include "drivers/unix/ip_unix.h"
|
||||
|
||||
#ifdef __GLIBC__
|
||||
#include <iconv.h>
|
||||
#include <langinfo.h>
|
||||
#define gd_iconv_t iconv_t
|
||||
#define gd_iconv_open iconv_open
|
||||
#define gd_iconv iconv
|
||||
#define gd_iconv_close iconv_close
|
||||
#else
|
||||
typedef void *gd_iconv_t;
|
||||
typedef gd_iconv_t (*PIConvOpen)(const char *, const char *);
|
||||
typedef size_t (*PIConv)(gd_iconv_t, char **, size_t *, char **, size_t *);
|
||||
typedef int (*PIConvClose)(gd_iconv_t);
|
||||
typedef const char *(*PIConvLocaleCharset)(void);
|
||||
#endif
|
||||
|
||||
class OS_Unix : public OS {
|
||||
struct ProcessInfo {
|
||||
mutable bool is_running = true;
|
||||
|
|
@ -44,6 +58,22 @@ class OS_Unix : public OS {
|
|||
HashMap<ProcessID, ProcessInfo> *process_map = nullptr;
|
||||
Mutex process_map_mutex;
|
||||
|
||||
#ifdef __GLIBC__
|
||||
bool _iconv_ok = true;
|
||||
#else
|
||||
bool _iconv_ok = false;
|
||||
|
||||
PIConvOpen gd_iconv_open = nullptr;
|
||||
PIConv gd_iconv = nullptr;
|
||||
PIConvClose gd_iconv_close = nullptr;
|
||||
PIConvLocaleCharset gd_locale_charset = nullptr;
|
||||
|
||||
void _load_iconv();
|
||||
#endif
|
||||
|
||||
static int _wait_for_pid_completion(const pid_t p_pid, int *r_status, int p_options);
|
||||
bool _check_pid_is_running(const pid_t p_pid, int *r_status) const;
|
||||
|
||||
protected:
|
||||
// UNIX only handles the core functions.
|
||||
// inheriting platforms under unix (eg. X11) should handle the rest
|
||||
|
|
@ -88,6 +118,9 @@ public:
|
|||
|
||||
virtual Dictionary get_memory_info() const override;
|
||||
|
||||
virtual String multibyte_to_string(const String &p_encoding, const PackedByteArray &p_array) const override;
|
||||
virtual PackedByteArray string_to_multibyte(const String &p_encoding, const String &p_string) const override;
|
||||
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override;
|
||||
virtual Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments, bool p_blocking = true) override;
|
||||
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
|
||||
|
|
@ -116,5 +149,3 @@ public:
|
|||
};
|
||||
|
||||
#endif // UNIX_ENABLED
|
||||
|
||||
#endif // OS_UNIX_H
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef SYSLOG_LOGGER_H
|
||||
#define SYSLOG_LOGGER_H
|
||||
#pragma once
|
||||
|
||||
#ifdef UNIX_ENABLED
|
||||
|
||||
|
|
@ -44,5 +43,3 @@ public:
|
|||
};
|
||||
|
||||
#endif // UNIX_ENABLED
|
||||
|
||||
#endif // SYSLOG_LOGGER_H
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@
|
|||
#include "core/os/thread.h"
|
||||
#include "core/string/ustring.h"
|
||||
|
||||
#if defined(PLATFORM_THREAD_OVERRIDE) && defined(__APPLE__)
|
||||
void init_thread_posix() {
|
||||
}
|
||||
#else
|
||||
|
||||
#ifdef PTHREAD_BSD_SET_NAME
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
|
@ -73,4 +78,6 @@ void init_thread_posix() {
|
|||
Thread::_set_platform_functions({ .set_name = set_name });
|
||||
}
|
||||
|
||||
#endif // PLATFORM_THREAD_OVERRIDE && __APPLE__
|
||||
|
||||
#endif // UNIX_ENABLED
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef THREAD_POSIX_H
|
||||
#define THREAD_POSIX_H
|
||||
#pragma once
|
||||
|
||||
void init_thread_posix();
|
||||
|
||||
#endif // THREAD_POSIX_H
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue