From fcf3d552040e98e8ece2f511b46872b8bae41e23 Mon Sep 17 00:00:00 2001 From: chris-a-talbot Date: Tue, 18 Nov 2025 21:52:49 -0500 Subject: [PATCH 1/2] Add readLine() function: from terminal, pauses execution and reads user input into a string which can be manipulated within the simulation, then continues --- eidos/eidos_functions.cpp | 1 + eidos/eidos_functions.h | 1 + eidos/eidos_functions_files.cpp | 46 +++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/eidos/eidos_functions.cpp b/eidos/eidos_functions.cpp index 42d8085c..b0c1740c 100644 --- a/eidos/eidos_functions.cpp +++ b/eidos/eidos_functions.cpp @@ -369,6 +369,7 @@ const std::vector &EidosInterpreter::BuiltInFunction signatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature("fileExists", Eidos_ExecuteFunction_fileExists, kEidosValueMaskLogical | kEidosValueMaskSingleton))->AddString_S(gEidosStr_filePath)); signatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature("flushFile", Eidos_ExecuteFunction_flushFile, kEidosValueMaskLogical | kEidosValueMaskSingleton))->AddString_S(gEidosStr_filePath)); signatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature("readFile", Eidos_ExecuteFunction_readFile, kEidosValueMaskString))->AddString_S(gEidosStr_filePath)); + signatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature("readLine", Eidos_ExecuteFunction_readLine, kEidosValueMaskString | kEidosValueMaskSingleton))); signatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature("setwd", Eidos_ExecuteFunction_setwd, kEidosValueMaskString | kEidosValueMaskSingleton))->AddString_S("path")); signatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature("tempdir", Eidos_ExecuteFunction_tempdir, kEidosValueMaskString | kEidosValueMaskSingleton))); signatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature("writeFile", Eidos_ExecuteFunction_writeFile, kEidosValueMaskLogical | kEidosValueMaskSingleton))->AddString_S(gEidosStr_filePath)->AddString("contents")->AddLogical_OS("append", gStaticEidosValue_LogicalF)->AddLogical_OS("compress", gStaticEidosValue_LogicalF)); diff --git a/eidos/eidos_functions.h b/eidos/eidos_functions.h index 3a5c0096..f57f1c64 100644 --- a/eidos/eidos_functions.h +++ b/eidos/eidos_functions.h @@ -250,6 +250,7 @@ EidosValue_SP Eidos_ExecuteFunction_filesAtPath(const std::vector EidosValue_SP Eidos_ExecuteFunction_flushFile(const std::vector &p_arguments, EidosInterpreter &p_interpreter); EidosValue_SP Eidos_ExecuteFunction_getwd(const std::vector &p_arguments, EidosInterpreter &p_interpreter); EidosValue_SP Eidos_ExecuteFunction_readFile(const std::vector &p_arguments, EidosInterpreter &p_interpreter); +EidosValue_SP Eidos_ExecuteFunction_readLine(const std::vector &p_arguments, EidosInterpreter &p_interpreter); EidosValue_SP Eidos_ExecuteFunction_setwd(const std::vector &p_arguments, EidosInterpreter &p_interpreter); EidosValue_SP Eidos_ExecuteFunction_tempdir(const std::vector &p_arguments, EidosInterpreter &p_interpreter); EidosValue_SP Eidos_ExecuteFunction_writeFile(const std::vector &p_arguments, EidosInterpreter &p_interpreter); diff --git a/eidos/eidos_functions_files.cpp b/eidos/eidos_functions_files.cpp index 46ae41ca..c88267fe 100644 --- a/eidos/eidos_functions_files.cpp +++ b/eidos/eidos_functions_files.cpp @@ -27,7 +27,9 @@ #include #include #include +#include #include +#include #include "../eidos_zlib/zlib.h" @@ -220,6 +222,50 @@ EidosValue_SP Eidos_ExecuteFunction_readFile(const std::vector &p return result_SP; } +// (string$)readLine(void) +EidosValue_SP Eidos_ExecuteFunction_readLine(const std::vector &p_arguments, EidosInterpreter &p_interpreter) +{ +#pragma unused (p_arguments) + + EidosValue_SP result_SP(nullptr); + + // Check if running in SLiMgui + // Also check if stdin is a TTY to catch redirected input + EidosSymbolTable &symbols = p_interpreter.SymbolTable(); + EidosGlobalStringID slimgui_id = EidosStringRegistry::GlobalStringIDForString("slimgui"); + bool in_slimgui = symbols.ContainsSymbol(slimgui_id); + bool stdin_is_tty = isatty(fileno(stdin)); + + if (in_slimgui || !stdin_is_tty) + { + // Emit a warning and return empty string to avoid blocking the GUI + if (!gEidosSuppressWarnings) + p_interpreter.ErrorOutputStream() << "#WARNING (Eidos_ExecuteFunction_readLine): function readLine() is not available when stdin is not connected to an interactive terminal (e.g., when running in SLiMgui or with redirected input). Returning empty string." << std::endl; + + result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String("")); + return result_SP; + } + + // Read a single line from stdin (command-line mode with interactive terminal) + std::string line; + + if (std::getline(std::cin, line)) + { + // Control for CRLF vs. LF line endings + if (!line.empty() && line[line.size() - 1] == '\r') + line.pop_back(); + + result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(line)); + } + else + { + // EOF or error reading from stdin; return empty string + result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String("")); + } + + return result_SP; +} + // (string$)setwd(string$ path) EidosValue_SP Eidos_ExecuteFunction_setwd(const std::vector &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter) { From eb09ff1a4b1f7421693ed65cf6e64b75469b94cc Mon Sep 17 00:00:00 2001 From: chris-a-talbot Date: Wed, 19 Nov 2025 10:42:09 -0500 Subject: [PATCH 2/2] Fix GUI detection and add issue comments --- eidos/eidos_functions_files.cpp | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/eidos/eidos_functions_files.cpp b/eidos/eidos_functions_files.cpp index c88267fe..f8747877 100644 --- a/eidos/eidos_functions_files.cpp +++ b/eidos/eidos_functions_files.cpp @@ -227,24 +227,14 @@ EidosValue_SP Eidos_ExecuteFunction_readLine(const std::vector &p { #pragma unused (p_arguments) - EidosValue_SP result_SP(nullptr); - - // Check if running in SLiMgui - // Also check if stdin is a TTY to catch redirected input - EidosSymbolTable &symbols = p_interpreter.SymbolTable(); - EidosGlobalStringID slimgui_id = EidosStringRegistry::GlobalStringIDForString("slimgui"); - bool in_slimgui = symbols.ContainsSymbol(slimgui_id); - bool stdin_is_tty = isatty(fileno(stdin)); +#ifdef EIDOS_GUI + EIDOS_TERMINATION << "ERROR (Eidos_ExecuteFunction_readLine): function readLine() is not available in GUI environments (SLiMgui, SLiMguiLegacy, or EidosScribe)." << EidosTerminate(nullptr); +#endif + + // This function was implemented by Chris Talbot 11/19/25 for use in reinforcement learning environments. + // Associated with issue #576. - if (in_slimgui || !stdin_is_tty) - { - // Emit a warning and return empty string to avoid blocking the GUI - if (!gEidosSuppressWarnings) - p_interpreter.ErrorOutputStream() << "#WARNING (Eidos_ExecuteFunction_readLine): function readLine() is not available when stdin is not connected to an interactive terminal (e.g., when running in SLiMgui or with redirected input). Returning empty string." << std::endl; - - result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String("")); - return result_SP; - } + EidosValue_SP result_SP(nullptr); // Read a single line from stdin (command-line mode with interactive terminal) std::string line;