Skip to content

Commit 179321a

Browse files
committed
Merge pull request godotengine#91201 from bruvzg/con_type
[OS] Add functions to determine standard I/O device type.
2 parents f1d3130 + 76164c2 commit 179321a

File tree

11 files changed

+377
-22
lines changed

11 files changed

+377
-22
lines changed

core/core_bind.compat.inc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,16 @@ void Semaphore::_bind_compatibility_methods() {
4444

4545
// OS
4646

47+
String OS::_read_string_from_stdin_bind_compat_91201() {
48+
return read_string_from_stdin(1024);
49+
}
50+
4751
Dictionary OS::_execute_with_pipe_bind_compat_94434(const String &p_path, const Vector<String> &p_arguments) {
4852
return execute_with_pipe(p_path, p_arguments, true);
4953
}
5054

5155
void OS::_bind_compatibility_methods() {
56+
ClassDB::bind_compatibility_method(D_METHOD("read_string_from_stdin"), &OS::_read_string_from_stdin_bind_compat_91201);
5257
ClassDB::bind_compatibility_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::_execute_with_pipe_bind_compat_94434);
5358
}
5459

core/core_bind.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,24 @@ Error OS::shell_show_in_file_manager(const String &p_path, bool p_open_folder) {
308308
return ::OS::get_singleton()->shell_show_in_file_manager(p_path, p_open_folder);
309309
}
310310

311-
String OS::read_string_from_stdin() {
312-
return ::OS::get_singleton()->get_stdin_string();
311+
String OS::read_string_from_stdin(int64_t p_buffer_size) {
312+
return ::OS::get_singleton()->get_stdin_string(p_buffer_size);
313+
}
314+
315+
PackedByteArray OS::read_buffer_from_stdin(int64_t p_buffer_size) {
316+
return ::OS::get_singleton()->get_stdin_buffer(p_buffer_size);
317+
}
318+
319+
OS::StdHandleType OS::get_stdin_type() const {
320+
return (OS::StdHandleType)::OS::get_singleton()->get_stdin_type();
321+
}
322+
323+
OS::StdHandleType OS::get_stdout_type() const {
324+
return (OS::StdHandleType)::OS::get_singleton()->get_stdout_type();
325+
}
326+
327+
OS::StdHandleType OS::get_stderr_type() const {
328+
return (OS::StdHandleType)::OS::get_singleton()->get_stderr_type();
313329
}
314330

315331
int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) {
@@ -633,7 +649,13 @@ void OS::_bind_methods() {
633649
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));
634650
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));
635651
ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path);
636-
ClassDB::bind_method(D_METHOD("read_string_from_stdin"), &OS::read_string_from_stdin);
652+
653+
ClassDB::bind_method(D_METHOD("read_string_from_stdin", "buffer_size"), &OS::read_string_from_stdin);
654+
ClassDB::bind_method(D_METHOD("read_buffer_from_stdin", "buffer_size"), &OS::read_buffer_from_stdin);
655+
ClassDB::bind_method(D_METHOD("get_stdin_type"), &OS::get_stdin_type);
656+
ClassDB::bind_method(D_METHOD("get_stdout_type"), &OS::get_stdout_type);
657+
ClassDB::bind_method(D_METHOD("get_stderr_type"), &OS::get_stderr_type);
658+
637659
ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL_ARRAY, DEFVAL(false), DEFVAL(false));
638660
ClassDB::bind_method(D_METHOD("execute_with_pipe", "path", "arguments", "blocking"), &OS::execute_with_pipe, DEFVAL(true));
639661
ClassDB::bind_method(D_METHOD("create_process", "path", "arguments", "open_console"), &OS::create_process, DEFVAL(false));
@@ -725,6 +747,12 @@ void OS::_bind_methods() {
725747
BIND_ENUM_CONSTANT(SYSTEM_DIR_MUSIC);
726748
BIND_ENUM_CONSTANT(SYSTEM_DIR_PICTURES);
727749
BIND_ENUM_CONSTANT(SYSTEM_DIR_RINGTONES);
750+
751+
BIND_ENUM_CONSTANT(STD_HANDLE_INVALID);
752+
BIND_ENUM_CONSTANT(STD_HANDLE_CONSOLE);
753+
BIND_ENUM_CONSTANT(STD_HANDLE_FILE);
754+
BIND_ENUM_CONSTANT(STD_HANDLE_PIPE);
755+
BIND_ENUM_CONSTANT(STD_HANDLE_UNKNOWN);
728756
}
729757

730758
////// Geometry2D //////

core/core_bind.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class OS : public Object {
134134
#ifndef DISABLE_DEPRECATED
135135
Dictionary _execute_with_pipe_bind_compat_94434(const String &p_path, const Vector<String> &p_arguments);
136136

137+
String _read_string_from_stdin_bind_compat_91201();
137138
static void _bind_compatibility_methods();
138139
#endif
139140

@@ -148,6 +149,14 @@ class OS : public Object {
148149
PackedByteArray get_entropy(int p_bytes);
149150
String get_system_ca_certificates();
150151

152+
enum StdHandleType {
153+
STD_HANDLE_INVALID,
154+
STD_HANDLE_CONSOLE,
155+
STD_HANDLE_FILE,
156+
STD_HANDLE_PIPE,
157+
STD_HANDLE_UNKNOWN,
158+
};
159+
151160
virtual PackedStringArray get_connected_midi_inputs();
152161
virtual void open_midi_inputs();
153162
virtual void close_midi_inputs();
@@ -168,7 +177,13 @@ class OS : public Object {
168177
String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
169178
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;
170179
String get_executable_path() const;
171-
String read_string_from_stdin();
180+
181+
String read_string_from_stdin(int64_t p_buffer_size = 1024);
182+
PackedByteArray read_buffer_from_stdin(int64_t p_buffer_size = 1024);
183+
StdHandleType get_stdin_type() const;
184+
StdHandleType get_stdout_type() const;
185+
StdHandleType get_stderr_type() const;
186+
172187
int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = ClassDB::default_array_arg, bool p_read_stderr = false, bool p_open_console = false);
173188
Dictionary execute_with_pipe(const String &p_path, const Vector<String> &p_arguments, bool p_blocking = true);
174189
int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false);
@@ -644,6 +659,7 @@ VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags);
644659

645660
VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver);
646661
VARIANT_ENUM_CAST(core_bind::OS::SystemDir);
662+
VARIANT_ENUM_CAST(core_bind::OS::StdHandleType);
647663

648664
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation);
649665
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);

core/os/os.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,15 @@ class OS {
9494
enum RenderThreadMode {
9595
RENDER_THREAD_UNSAFE,
9696
RENDER_THREAD_SAFE,
97-
RENDER_SEPARATE_THREAD
97+
RENDER_SEPARATE_THREAD,
98+
};
99+
100+
enum StdHandleType {
101+
STD_HANDLE_INVALID,
102+
STD_HANDLE_CONSOLE,
103+
STD_HANDLE_FILE,
104+
STD_HANDLE_PIPE,
105+
STD_HANDLE_UNKNOWN,
98106
};
99107

100108
protected:
@@ -146,7 +154,12 @@ class OS {
146154
void print_rich(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
147155
void printerr(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
148156

149-
virtual String get_stdin_string() = 0;
157+
virtual String get_stdin_string(int64_t p_buffer_size = 1024) = 0;
158+
virtual PackedByteArray get_stdin_buffer(int64_t p_buffer_size = 1024) = 0;
159+
160+
virtual StdHandleType get_stdin_type() const { return STD_HANDLE_UNKNOWN; }
161+
virtual StdHandleType get_stdout_type() const { return STD_HANDLE_UNKNOWN; }
162+
virtual StdHandleType get_stderr_type() const { return STD_HANDLE_UNKNOWN; }
150163

151164
virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) = 0; // Should return cryptographically-safe random bytes.
152165
virtual String get_system_ca_certificates() { return ""; } // Concatenated certificates in PEM format.

doc/classes/OS.xml

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<return type="void" />
2424
<description>
2525
Shuts down the system MIDI driver. Godot will no longer receive [InputEventMIDI]. See also [method open_midi_inputs] and [method get_connected_midi_inputs].
26-
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
26+
[b]Note:[/b] This method is implemented on Linux, macOS, and Windows.
2727
</description>
2828
</method>
2929
<method name="crash">
@@ -244,7 +244,7 @@
244244
<return type="PackedStringArray" />
245245
<description>
246246
Returns an array of connected MIDI device names, if they exist. Returns an empty array if the system MIDI driver has not previously been initialized with [method open_midi_inputs]. See also [method close_midi_inputs].
247-
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
247+
[b]Note:[/b] This method is implemented on Linux, macOS, and Windows.
248248
</description>
249249
</method>
250250
<method name="get_data_dir" qualifiers="const">
@@ -466,6 +466,24 @@
466466
Returns the amount of static memory being used by the program in bytes. Only works in debug builds.
467467
</description>
468468
</method>
469+
<method name="get_stderr_type" qualifiers="const">
470+
<return type="int" enum="OS.StdHandleType" />
471+
<description>
472+
Returns type of the standard error device.
473+
</description>
474+
</method>
475+
<method name="get_stdin_type" qualifiers="const">
476+
<return type="int" enum="OS.StdHandleType" />
477+
<description>
478+
Returns type of the standard input device.
479+
</description>
480+
</method>
481+
<method name="get_stdout_type" qualifiers="const">
482+
<return type="int" enum="OS.StdHandleType" />
483+
<description>
484+
Returns type of the standard output device.
485+
</description>
486+
</method>
469487
<method name="get_system_ca_certificates">
470488
<return type="String" />
471489
<description>
@@ -680,15 +698,31 @@
680698
<return type="void" />
681699
<description>
682700
Initializes the singleton for the system MIDI driver, allowing Godot to receive [InputEventMIDI]. See also [method get_connected_midi_inputs] and [method close_midi_inputs].
683-
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
701+
[b]Note:[/b] This method is implemented on Linux, macOS, and Windows.
702+
</description>
703+
</method>
704+
<method name="read_buffer_from_stdin">
705+
<return type="PackedByteArray" />
706+
<param index="0" name="buffer_size" type="int" />
707+
<description>
708+
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.
709+
- 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]).
710+
- If standard input is pipe, this method will block until a specific amount of data is read or pipe is closed.
711+
- 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.
712+
[b]Note:[/b] This method is implemented on Linux, macOS, and Windows.
713+
[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.
684714
</description>
685715
</method>
686716
<method name="read_string_from_stdin">
687717
<return type="String" />
718+
<param index="0" name="buffer_size" type="int" />
688719
<description>
689-
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]).
690-
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
691-
[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.
720+
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.
721+
- 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]).
722+
- If standard input is pipe, this method will block until a specific amount of data is read or pipe is closed.
723+
- 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.
724+
[b]Note:[/b] This method is implemented on Linux, macOS, and Windows.
725+
[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.
692726
</description>
693727
</method>
694728
<method name="request_permission">
@@ -831,5 +865,20 @@
831865
<constant name="SYSTEM_DIR_RINGTONES" value="7" enum="SystemDir">
832866
Refers to the Ringtones directory path.
833867
</constant>
868+
<constant name="STD_HANDLE_INVALID" value="0" enum="StdHandleType">
869+
Standard I/O device is invalid. No data can be received from or sent to these standard I/O devices.
870+
</constant>
871+
<constant name="STD_HANDLE_CONSOLE" value="1" enum="StdHandleType">
872+
Standard I/O device is a console. This typically occurs when Godot is run from a terminal with no redirection. This is also used for all standard I/O devices when running Godot from the editor, at least on desktop platforms.
873+
</constant>
874+
<constant name="STD_HANDLE_FILE" value="2" enum="StdHandleType">
875+
Standard I/O device is a regular file. This typically occurs with redirection from a terminal, e.g. [code]godot &gt; stdout.txt[/code], [code]godot &lt; stdin.txt[/code] or [code]godot &gt; stdout_stderr.txt 2&gt;&amp;1[/code].
876+
</constant>
877+
<constant name="STD_HANDLE_PIPE" value="3" enum="StdHandleType">
878+
Standard I/O device is a FIFO/pipe. This typically occurs with pipe usage from a terminal, e.g. [code]echo "Hello" | godot[/code].
879+
</constant>
880+
<constant name="STD_HANDLE_UNKNOWN" value="4" enum="StdHandleType">
881+
Standard I/O device type is unknown.
882+
</constant>
834883
</constants>
835884
</class>

drivers/unix/os_unix.cpp

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
#include <stdlib.h>
7878
#include <string.h>
7979
#include <sys/resource.h>
80+
#include <sys/stat.h>
8081
#include <sys/time.h>
8182
#include <sys/wait.h>
8283
#include <time.h>
@@ -182,9 +183,87 @@ Vector<String> OS_Unix::get_video_adapter_driver_info() const {
182183
return Vector<String>();
183184
}
184185

185-
String OS_Unix::get_stdin_string() {
186-
char buff[1024];
187-
return String::utf8(fgets(buff, 1024, stdin));
186+
String OS_Unix::get_stdin_string(int64_t p_buffer_size) {
187+
Vector<uint8_t> data;
188+
data.resize(p_buffer_size);
189+
if (fgets((char *)data.ptrw(), data.size(), stdin)) {
190+
return String::utf8((char *)data.ptr());
191+
}
192+
return String();
193+
}
194+
195+
PackedByteArray OS_Unix::get_stdin_buffer(int64_t p_buffer_size) {
196+
Vector<uint8_t> data;
197+
data.resize(p_buffer_size);
198+
size_t sz = fread((void *)data.ptrw(), 1, data.size(), stdin);
199+
if (sz > 0) {
200+
data.resize(sz);
201+
return data;
202+
}
203+
return PackedByteArray();
204+
}
205+
206+
OS_Unix::StdHandleType OS_Unix::get_stdin_type() const {
207+
int h = fileno(stdin);
208+
if (h == -1) {
209+
return STD_HANDLE_INVALID;
210+
}
211+
212+
if (isatty(h)) {
213+
return STD_HANDLE_CONSOLE;
214+
}
215+
struct stat statbuf;
216+
if (fstat(h, &statbuf) < 0) {
217+
return STD_HANDLE_UNKNOWN;
218+
}
219+
if (S_ISFIFO(statbuf.st_mode)) {
220+
return STD_HANDLE_PIPE;
221+
} else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) {
222+
return STD_HANDLE_FILE;
223+
}
224+
return STD_HANDLE_UNKNOWN;
225+
}
226+
227+
OS_Unix::StdHandleType OS_Unix::get_stdout_type() const {
228+
int h = fileno(stdout);
229+
if (h == -1) {
230+
return STD_HANDLE_INVALID;
231+
}
232+
233+
if (isatty(h)) {
234+
return STD_HANDLE_CONSOLE;
235+
}
236+
struct stat statbuf;
237+
if (fstat(h, &statbuf) < 0) {
238+
return STD_HANDLE_UNKNOWN;
239+
}
240+
if (S_ISFIFO(statbuf.st_mode)) {
241+
return STD_HANDLE_PIPE;
242+
} else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) {
243+
return STD_HANDLE_FILE;
244+
}
245+
return STD_HANDLE_UNKNOWN;
246+
}
247+
248+
OS_Unix::StdHandleType OS_Unix::get_stderr_type() const {
249+
int h = fileno(stderr);
250+
if (h == -1) {
251+
return STD_HANDLE_INVALID;
252+
}
253+
254+
if (isatty(h)) {
255+
return STD_HANDLE_CONSOLE;
256+
}
257+
struct stat statbuf;
258+
if (fstat(h, &statbuf) < 0) {
259+
return STD_HANDLE_UNKNOWN;
260+
}
261+
if (S_ISFIFO(statbuf.st_mode)) {
262+
return STD_HANDLE_PIPE;
263+
} else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) {
264+
return STD_HANDLE_FILE;
265+
}
266+
return STD_HANDLE_UNKNOWN;
188267
}
189268

190269
Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) {

drivers/unix/os_unix.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@ class OS_Unix : public OS {
5858

5959
virtual Vector<String> get_video_adapter_driver_info() const override;
6060

61-
virtual String get_stdin_string() override;
61+
virtual String get_stdin_string(int64_t p_buffer_size = 1024) override;
62+
virtual PackedByteArray get_stdin_buffer(int64_t p_buffer_size = 1024) override;
63+
virtual StdHandleType get_stdin_type() const override;
64+
virtual StdHandleType get_stdout_type() const override;
65+
virtual StdHandleType get_stderr_type() const override;
6266

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

misc/extension_api_validation/4.3-stable.expected

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,10 @@ GH-97257
108108
Validate extension JSON: Error: Field 'classes/EditorFeatureProfile/enums/Feature/values/FEATURE_MAX': value changed value in new API, from 8.0 to 9.
109109

110110
New entry to the `EditorFeatureProfile.Feature` enum added. Those need to go before `FEATURE_MAX`, which will always cause a compatibility break.
111+
112+
113+
GH-91201
114+
--------
115+
Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/OS/methods/read_string_from_stdin': arguments
116+
117+
Added optional argument. Compatibility method registered.

0 commit comments

Comments
 (0)