Skip to content

Commit

Permalink
[OS] Add functions to determine standard I/O device type.
Browse files Browse the repository at this point in the history
  • Loading branch information
bruvzg committed May 15, 2024
1 parent 1d47561 commit b8926b9
Show file tree
Hide file tree
Showing 11 changed files with 417 additions and 18 deletions.
45 changes: 45 additions & 0 deletions core/core_bind.compat.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**************************************************************************/
/* core_bind.compat.inc */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/

#ifndef DISABLE_DEPRECATED

namespace core_bind {

String OS::read_string_from_stdin_bind_compat_91201() {
return read_string_from_stdin(1024);
}

void OS::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("read_string_from_stdin"), &OS::read_string_from_stdin_bind_compat_91201);
}

} //namespace core_bind

#endif
34 changes: 31 additions & 3 deletions core/core_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
/**************************************************************************/

#include "core_bind.h"
#include "core_bind.compat.inc"

#include "core/config/project_settings.h"
#include "core/crypto/crypto_core.h"
Expand Down Expand Up @@ -275,8 +276,23 @@ Error OS::shell_show_in_file_manager(const String &p_path, bool p_open_folder) {
return ::OS::get_singleton()->shell_show_in_file_manager(p_path, p_open_folder);
}

String OS::read_string_from_stdin() {
return ::OS::get_singleton()->get_stdin_string();
String OS::read_string_from_stdin(int64_t p_buffer_size) {
return ::OS::get_singleton()->get_stdin_string(p_buffer_size);
}

PackedByteArray OS::read_buffer_from_stdin(int64_t p_buffer_size) {
return ::OS::get_singleton()->get_stdin_buffer(p_buffer_size);
}

OS::StdHandleType OS::get_stdin_type() const {
return (OS::StdHandleType)::OS::get_singleton()->get_stdin_type();
}

OS::StdHandleType OS::get_stdout_type() const {
return (OS::StdHandleType)::OS::get_singleton()->get_stdout_type();
}
OS::StdHandleType OS::get_stderr_type() const {
return (OS::StdHandleType)::OS::get_singleton()->get_stderr_type();
}

int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) {
Expand Down Expand Up @@ -595,7 +611,13 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_system_font_path", "font_name", "weight", "stretch", "italic"), &OS::get_system_font_path, DEFVAL(400), DEFVAL(100), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_system_font_path_for_text", "font_name", "text", "locale", "script", "weight", "stretch", "italic"), &OS::get_system_font_path_for_text, DEFVAL(String()), DEFVAL(String()), DEFVAL(400), DEFVAL(100), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path);
ClassDB::bind_method(D_METHOD("read_string_from_stdin"), &OS::read_string_from_stdin);

ClassDB::bind_method(D_METHOD("read_string_from_stdin", "buffer_size"), &OS::read_string_from_stdin);
ClassDB::bind_method(D_METHOD("read_buffer_from_stdin", "buffer_size"), &OS::read_buffer_from_stdin);
ClassDB::bind_method(D_METHOD("get_stdin_type"), &OS::get_stdin_type);
ClassDB::bind_method(D_METHOD("get_stdout_type"), &OS::get_stdout_type);
ClassDB::bind_method(D_METHOD("get_stderr_type"), &OS::get_stderr_type);

ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL(Array()), DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::execute_with_pipe);
ClassDB::bind_method(D_METHOD("create_process", "path", "arguments", "open_console"), &OS::create_process, DEFVAL(false));
Expand Down Expand Up @@ -686,6 +708,12 @@ void OS::_bind_methods() {
BIND_ENUM_CONSTANT(SYSTEM_DIR_MUSIC);
BIND_ENUM_CONSTANT(SYSTEM_DIR_PICTURES);
BIND_ENUM_CONSTANT(SYSTEM_DIR_RINGTONES);

BIND_ENUM_CONSTANT(STD_HANDLE_INVALID);
BIND_ENUM_CONSTANT(STD_HANDLE_CONSOLE);
BIND_ENUM_CONSTANT(STD_HANDLE_FILE);
BIND_ENUM_CONSTANT(STD_HANDLE_PIPE);
BIND_ENUM_CONSTANT(STD_HANDLE_UNKNOWN);
}

////// Geometry2D //////
Expand Down
22 changes: 21 additions & 1 deletion core/core_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,26 @@ class OS : public Object {
static void _bind_methods();
static OS *singleton;

#ifndef DISABLE_DEPRECATED
String read_string_from_stdin_bind_compat_91201();
static void _bind_compatibility_methods();
#endif

public:
enum RenderingDriver {
RENDERING_DRIVER_VULKAN,
RENDERING_DRIVER_OPENGL3,
RENDERING_DRIVER_D3D12,
};

enum StdHandleType {
STD_HANDLE_INVALID,
STD_HANDLE_CONSOLE,
STD_HANDLE_FILE,
STD_HANDLE_PIPE,
STD_HANDLE_UNKNOWN,
};

virtual PackedStringArray get_connected_midi_inputs();
virtual void open_midi_inputs();
virtual void close_midi_inputs();
Expand All @@ -154,7 +167,13 @@ class OS : public Object {
String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
String get_executable_path() const;
String read_string_from_stdin();

String read_string_from_stdin(int64_t p_buffer_size = 1024);
PackedByteArray read_buffer_from_stdin(int64_t p_buffer_size = 1024);
StdHandleType get_stdin_type() const;
StdHandleType get_stdout_type() const;
StdHandleType get_stderr_type() const;

int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false, bool p_open_console = false);
Dictionary execute_with_pipe(const String &p_path, const Vector<String> &p_arguments);
int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false);
Expand Down Expand Up @@ -592,6 +611,7 @@ VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags);

VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver);
VARIANT_ENUM_CAST(core_bind::OS::SystemDir);
VARIANT_ENUM_CAST(core_bind::OS::StdHandleType);

VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);
Expand Down
17 changes: 15 additions & 2 deletions core/os/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,15 @@ class OS {
enum RenderThreadMode {
RENDER_THREAD_UNSAFE,
RENDER_THREAD_SAFE,
RENDER_SEPARATE_THREAD
RENDER_SEPARATE_THREAD,
};

enum StdHandleType {
STD_HANDLE_INVALID,
STD_HANDLE_CONSOLE,
STD_HANDLE_FILE,
STD_HANDLE_PIPE,
STD_HANDLE_UNKNOWN,
};

protected:
Expand Down Expand Up @@ -143,7 +151,12 @@ class OS {
void print_rich(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
void printerr(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;

virtual String get_stdin_string() = 0;
virtual String get_stdin_string(int64_t p_buffer_size = 1024) = 0;
virtual PackedByteArray get_stdin_buffer(int64_t p_buffer_size = 1024) = 0;

virtual StdHandleType get_stdin_type() const { return STD_HANDLE_UNKNOWN; }
virtual StdHandleType get_stdout_type() const { return STD_HANDLE_UNKNOWN; }
virtual StdHandleType get_stderr_type() const { return STD_HANDLE_UNKNOWN; }

virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) = 0; // Should return cryptographically-safe random bytes.
virtual String get_system_ca_certificates() { return ""; } // Concatenated certificates in PEM format.
Expand Down
53 changes: 51 additions & 2 deletions doc/classes/OS.xml
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,24 @@
Returns the amount of static memory being used by the program in bytes. Only works in debug builds.
</description>
</method>
<method name="get_stderr_type" qualifiers="const">
<return type="int" enum="OS.StdHandleType" />
<description>
Returns type of the standard error device.
</description>
</method>
<method name="get_stdin_type" qualifiers="const">
<return type="int" enum="OS.StdHandleType" />
<description>
Returns type of the standard input device.
</description>
</method>
<method name="get_stdout_type" qualifiers="const">
<return type="int" enum="OS.StdHandleType" />
<description>
Returns type of the standard output device.
</description>
</method>
<method name="get_system_dir" qualifiers="const">
<return type="String" />
<param index="0" name="dir" type="int" enum="OS.SystemDir" />
Expand Down Expand Up @@ -666,12 +684,28 @@
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
</description>
</method>
<method name="read_buffer_from_stdin">
<return type="PackedByteArray" />
<param index="0" name="buffer_size" type="int" />
<description>
Reads a user input as raw data from the standard input. This operation can be [i]blocking[/i], which causes the window to freeze if [method read_string_from_stdin] is called on the main thread.
- If standard input is console, this method will block until the program receives a line break in standard input (usually by the user pressing [kbd]Enter[/kbd]).
- If standard input is pipe, this method will block until a specific amount of data is read or pipe is closed.
- If standard input is a file, this method will read a specific amount of data (or less if end-of-file is reached) and return immediately.
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
[b]Note:[/b] On exported Windows builds, run the console wrapper executable to access the terminal. If standard input is console, calling this method without console wrapped will freeze permanently. If standard input is pipe or file, it can be used without console wrapper. If you need a single executable with full console support, use a custom build compiled with the [code]windows_subsystem=console[/code] flag.
</description>
</method>
<method name="read_string_from_stdin">
<return type="String" />
<param index="0" name="buffer_size" type="int" />
<description>
Reads a user input string from the standard input (usually the terminal). This operation is [i]blocking[/i], which causes the window to freeze if [method read_string_from_stdin] is called on the main thread. The thread calling [method read_string_from_stdin] will block until the program receives a line break in standard input (usually by the user pressing [kbd]Enter[/kbd]).
Reads a user input as a UTF-8 encoded string from the standard input. This operation can be [i]blocking[/i], which causes the window to freeze if [method read_string_from_stdin] is called on the main thread.
- If standard input is console, this method will block until the program receives a line break in standard input (usually by the user pressing [kbd]Enter[/kbd]).
- If standard input is pipe, this method will block until a specific amount of data is read or pipe is closed.
- If standard input is a file, this method will read a specific amount of data (or less if end-of-file is reached) and return immediately.
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
[b]Note:[/b] On exported Windows builds, run the console wrapper executable to access the terminal. Otherwise, the standard input will not work correctly. If you need a single executable with console support, use a custom build compiled with the [code]windows_subsystem=console[/code] flag.
[b]Note:[/b] On exported Windows builds, run the console wrapper executable to access the terminal. If standard input is console, calling this method without console wrapped will freeze permanently. If standard input is pipe or file, it can be used without console wrapper. If you need a single executable with full console support, use a custom build compiled with the [code]windows_subsystem=console[/code] flag.
</description>
</method>
<method name="request_permission">
Expand Down Expand Up @@ -811,5 +845,20 @@
<constant name="SYSTEM_DIR_RINGTONES" value="7" enum="SystemDir">
Refers to the Ringtones directory path.
</constant>
<constant name="STD_HANDLE_INVALID" value="0" enum="StdHandleType">
Standard I/O device is invalid.
</constant>
<constant name="STD_HANDLE_CONSOLE" value="1" enum="StdHandleType">
Standard I/O device is a console.
</constant>
<constant name="STD_HANDLE_FILE" value="2" enum="StdHandleType">
Standard I/O device is a regular file.
</constant>
<constant name="STD_HANDLE_PIPE" value="3" enum="StdHandleType">
Standard I/O device is a FIFO/pipe.
</constant>
<constant name="STD_HANDLE_UNKNOWN" value="4" enum="StdHandleType">
Standard I/O device type is unknown.
</constant>
</constants>
</class>
85 changes: 82 additions & 3 deletions drivers/unix/os_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <time.h>
Expand Down Expand Up @@ -182,9 +183,87 @@ Vector<String> OS_Unix::get_video_adapter_driver_info() const {
return Vector<String>();
}

String OS_Unix::get_stdin_string() {
char buff[1024];
return String::utf8(fgets(buff, 1024, stdin));
String OS_Unix::get_stdin_string(int64_t p_buffer_size) {
Vector<uint8_t> data;
data.resize(p_buffer_size);
if (fgets((char *)data.ptrw(), data.size(), stdin)) {
return String::utf8((char *)data.ptr());
}
return String();
}

PackedByteArray OS_Unix::get_stdin_buffer(int64_t p_buffer_size) {
Vector<uint8_t> data;
data.resize(p_buffer_size);
size_t sz = fread((void *)data.ptrw(), 1, data.size(), stdin);
if (sz > 0) {
data.resize(sz);
return data;
}
return PackedByteArray();
}

OS_Unix::StdHandleType OS_Unix::get_stdin_type() const {
int h = fileno(stdin);
if (h == -1) {
return STD_HANDLE_INVALID;
}

if (isatty(h)) {
return STD_HANDLE_CONSOLE;
}
struct stat statbuf;
if (fstat(h, &statbuf) < 0) {
return STD_HANDLE_UNKNOWN;
}
if (S_ISFIFO(statbuf.st_mode)) {
return STD_HANDLE_PIPE;
} else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) {
return STD_HANDLE_FILE;
}
return STD_HANDLE_UNKNOWN;
}

OS_Unix::StdHandleType OS_Unix::get_stdout_type() const {
int h = fileno(stdout);
if (h == -1) {
return STD_HANDLE_INVALID;
}

if (isatty(h)) {
return STD_HANDLE_CONSOLE;
}
struct stat statbuf;
if (fstat(h, &statbuf) < 0) {
return STD_HANDLE_UNKNOWN;
}
if (S_ISFIFO(statbuf.st_mode)) {
return STD_HANDLE_PIPE;
} else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) {
return STD_HANDLE_FILE;
}
return STD_HANDLE_UNKNOWN;
}

OS_Unix::StdHandleType OS_Unix::get_stderr_type() const {
int h = fileno(stderr);
if (h == -1) {
return STD_HANDLE_INVALID;
}

if (isatty(h)) {
return STD_HANDLE_CONSOLE;
}
struct stat statbuf;
if (fstat(h, &statbuf) < 0) {
return STD_HANDLE_UNKNOWN;
}
if (S_ISFIFO(statbuf.st_mode)) {
return STD_HANDLE_PIPE;
} else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) {
return STD_HANDLE_FILE;
}
return STD_HANDLE_UNKNOWN;
}

Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) {
Expand Down
6 changes: 5 additions & 1 deletion drivers/unix/os_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ class OS_Unix : public OS {

virtual Vector<String> get_video_adapter_driver_info() const override;

virtual String get_stdin_string() override;
virtual String get_stdin_string(int64_t p_buffer_size = 1024) override;
virtual PackedByteArray get_stdin_buffer(int64_t p_buffer_size = 1024) override;
virtual StdHandleType get_stdin_type() const override;
virtual StdHandleType get_stdout_type() const override;
virtual StdHandleType get_stderr_type() const override;

virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override;

Expand Down
7 changes: 7 additions & 0 deletions misc/extension_api_validation/4.2-stable.expected
Original file line number Diff line number Diff line change
Expand Up @@ -357,3 +357,10 @@ Validate extension JSON: Error: Field 'classes/RenderingServer/methods/canvas_it
Validate extension JSON: Error: Field 'classes/RenderingServer/methods/canvas_item_add_rect/arguments': size changed value in new API, from 3 to 4.

Optional arguments added. Compatibility methods registered.


GH-91201
--------
Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/OS/methods/read_string_from_stdin': arguments

Added optional argument. Compatibility method registered.
Loading

0 comments on commit b8926b9

Please sign in to comment.