2016-01-28 14:52:40 +01:00
|
|
|
/** @file
|
|
|
|
|
*
|
|
|
|
|
* @par History
|
|
|
|
|
*/
|
2015-01-19 18:18:21 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "console.h"
|
|
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
|
2018-01-01 21:49:30 +01:00
|
|
|
#include "../bscript/eprog.h"
|
2015-01-19 18:18:21 +01:00
|
|
|
#include "../bscript/impstr.h"
|
|
|
|
|
#include "../clib/cfgelem.h"
|
|
|
|
|
#include "../clib/cfgfile.h"
|
|
|
|
|
#include "../clib/fileutil.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../clib/kbhit.h"
|
2015-01-19 18:18:21 +01:00
|
|
|
#include "../clib/logfacility.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "../clib/refptr.h"
|
|
|
|
|
#include "../clib/stlutil.h"
|
2015-01-19 18:18:21 +01:00
|
|
|
#include "../plib/systemstate.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "globals/state.h"
|
|
|
|
|
#include "globals/uvars.h"
|
2015-01-19 18:18:21 +01:00
|
|
|
#include "polsem.h"
|
2018-01-29 21:55:48 +01:00
|
|
|
#include "polsig.h"
|
2015-01-19 18:18:21 +01:00
|
|
|
#include "scrdef.h"
|
|
|
|
|
#include "scrsched.h"
|
|
|
|
|
#include "scrstore.h"
|
2024-01-10 18:29:10 +01:00
|
|
|
#include <fmt/format.h>
|
2015-01-19 18:18:21 +01:00
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
2016-02-19 19:26:35 +01:00
|
|
|
#include <conio.h>
|
2015-01-19 18:18:21 +01:00
|
|
|
#endif
|
|
|
|
|
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <exception>
|
2015-01-19 18:18:21 +01:00
|
|
|
#include <stdexcept>
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <string>
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2026-01-17 10:30:21 +01:00
|
|
|
|
|
|
|
|
namespace Pol::Core
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
bool ConsoleCommand::console_locked = true;
|
|
|
|
|
char ConsoleCommand::unlock_char;
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
ConsoleCommand::ConsoleCommand( Clib::ConfigElem& elem, const std::string& cmd )
|
|
|
|
|
{
|
|
|
|
|
ISTRINGSTREAM is( cmd );
|
|
|
|
|
std::string charspec;
|
|
|
|
|
if ( !( is >> charspec >> script ) )
|
|
|
|
|
{
|
|
|
|
|
elem.throw_error( "Ill-formed console command desc: " + cmd );
|
|
|
|
|
}
|
|
|
|
|
if ( charspec[0] == '^' && charspec.size() == 2 )
|
|
|
|
|
{
|
|
|
|
|
ch = static_cast<char>( toupper( charspec[1] ) ) - 'A' + 1;
|
|
|
|
|
}
|
|
|
|
|
else if ( charspec.size() == 1 )
|
|
|
|
|
{
|
|
|
|
|
ch = charspec[0];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
elem.throw_error( "Ill-formed console command char: " + charspec );
|
|
|
|
|
}
|
|
|
|
|
getline( is, description );
|
2026-01-16 13:22:43 +01:00
|
|
|
while ( !description.empty() && isspace( description[0] ) )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
description.erase( 0, 1 );
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( script == "[unlock]" || script == "[lock/unlock]" )
|
|
|
|
|
ConsoleCommand::unlock_char = ch;
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
size_t ConsoleCommand::estimateSize() const
|
|
|
|
|
{
|
|
|
|
|
return sizeof( char ) + script.capacity() + description.capacity();
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
std::string getcmdstr( char ch )
|
|
|
|
|
{
|
|
|
|
|
if ( iscntrl( ch ) )
|
|
|
|
|
{
|
|
|
|
|
char s[3];
|
|
|
|
|
s[0] = '^';
|
|
|
|
|
s[1] = ch + 'A' - 1;
|
|
|
|
|
s[2] = '\0';
|
|
|
|
|
return s;
|
|
|
|
|
}
|
2026-01-18 09:35:52 +01:00
|
|
|
|
|
|
|
|
char s[2];
|
|
|
|
|
s[0] = ch;
|
|
|
|
|
s[1] = '\0';
|
|
|
|
|
return s;
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
ConsoleCommand* ConsoleCommand::find_console_command( char ch )
|
|
|
|
|
{
|
2026-01-31 09:14:02 +01:00
|
|
|
for ( auto& cmd : gamestate.console_commands )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
if ( cmd.ch == ch )
|
|
|
|
|
return &cmd;
|
|
|
|
|
}
|
2018-07-31 14:30:29 +02:00
|
|
|
return nullptr;
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void ConsoleCommand::load_console_commands()
|
|
|
|
|
{
|
|
|
|
|
if ( !Clib::FileExists( "config/console.cfg" ) )
|
|
|
|
|
return;
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
Clib::ConfigFile cf( "config/console.cfg", "Commands" );
|
|
|
|
|
Clib::ConfigElem elem;
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
gamestate.console_commands.clear();
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
while ( cf.read( elem ) )
|
|
|
|
|
{
|
|
|
|
|
std::string tmp;
|
|
|
|
|
while ( elem.remove_prop( "CMD", &tmp ) )
|
|
|
|
|
{
|
|
|
|
|
ConsoleCommand cmd( elem, tmp );
|
|
|
|
|
gamestate.console_commands.push_back( cmd );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
void ConsoleCommand::exec_console_cmd( char ch )
|
|
|
|
|
{
|
2015-01-19 18:18:21 +01:00
|
|
|
#ifdef WIN32
|
2016-02-19 19:26:35 +01:00
|
|
|
// cope with function keys.
|
|
|
|
|
if ( ch == 0 || static_cast<unsigned char>( ch ) == 0xE0 )
|
|
|
|
|
{
|
|
|
|
|
getch();
|
|
|
|
|
ch = '?';
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
#endif
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( ch == '?' )
|
|
|
|
|
{
|
2024-01-10 18:29:10 +01:00
|
|
|
std::string tmp = "Commands: \n";
|
2026-01-31 09:14:02 +01:00
|
|
|
for ( auto& cmd : gamestate.console_commands )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
std::string sc = getcmdstr( cmd.ch );
|
2024-01-10 18:29:10 +01:00
|
|
|
tmp += fmt::format( "{}{}: {}\n", sc.size() == 1 ? " " : " ", sc, cmd.description );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
2024-01-10 18:29:10 +01:00
|
|
|
tmp += " ?: Help (This list)";
|
|
|
|
|
INFO_PRINTLN( tmp );
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
|
|
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
ConsoleCommand* cmd = find_console_command( ch );
|
|
|
|
|
if ( !cmd )
|
|
|
|
|
{
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Unknown console command: '{}'", getcmdstr( ch ) );
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ( cmd->script == "[lock]" )
|
|
|
|
|
{
|
|
|
|
|
ConsoleCommand::console_locked = true;
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Console is now locked." );
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ( cmd->script == "[unlock]" )
|
|
|
|
|
{
|
|
|
|
|
ConsoleCommand::console_locked = true;
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Console is now unlocked." );
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ( cmd->script == "[lock/unlock]" )
|
|
|
|
|
{
|
|
|
|
|
ConsoleCommand::console_locked = !ConsoleCommand::console_locked;
|
|
|
|
|
if ( ConsoleCommand::console_locked )
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Console is now locked." );
|
2016-02-19 19:26:35 +01:00
|
|
|
else
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Console is now unlocked." );
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ( cmd->script == "[threadstatus]" )
|
|
|
|
|
{
|
|
|
|
|
stateManager.polsig.report_status_signalled = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ( cmd->script == "[crash]" )
|
|
|
|
|
{
|
2025-06-23 20:13:01 +02:00
|
|
|
std::abort();
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( ConsoleCommand::console_locked )
|
|
|
|
|
{
|
2024-01-10 18:29:10 +01:00
|
|
|
INFO_PRINTLN( "Console is locked. Press '{}' to unlock.", ConsoleCommand::unlock_char );
|
2016-02-19 19:26:35 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
|
2016-02-19 19:26:35 +01:00
|
|
|
std::string filename = "scripts/console/" + cmd->script;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
PolLock lck;
|
|
|
|
|
ScriptDef sd;
|
|
|
|
|
sd.quickconfig( filename + ".ecl" );
|
|
|
|
|
ref_ptr<Bscript::EScriptProgram> prog =
|
|
|
|
|
find_script2( sd, true, Plib::systemstate.config.cache_interactive_scripts );
|
2018-07-31 14:30:29 +02:00
|
|
|
if ( prog.get() != nullptr )
|
2016-02-19 19:26:35 +01:00
|
|
|
start_script( prog, new Bscript::String( getcmdstr( ch ) ) );
|
|
|
|
|
}
|
|
|
|
|
catch ( const char* msg )
|
|
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
ERROR_PRINTLN( "Command aborted due to: {}", msg );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
catch ( std::string& str )
|
|
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
ERROR_PRINTLN( "Command aborted due to: {}", str );
|
2026-01-16 13:22:43 +01:00
|
|
|
} // egcs has some trouble realizing 'exception' should catch
|
2016-02-19 19:26:35 +01:00
|
|
|
catch ( std::runtime_error& re ) // runtime_errors, so...
|
|
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
ERROR_PRINTLN( "Command aborted due to: {}", re.what() );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
catch ( std::exception& ex )
|
|
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
ERROR_PRINTLN( "Command aborted due to: {}", ex.what() );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
catch ( int xn )
|
|
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
ERROR_PRINTLN( "Command aborted due to: {}", xn );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-02-21 10:23:50 +01:00
|
|
|
#ifdef _WIN32
|
2016-02-19 19:26:35 +01:00
|
|
|
void ConsoleCommand::check_console_commands()
|
|
|
|
|
{
|
|
|
|
|
if ( kbhit() )
|
|
|
|
|
{
|
|
|
|
|
exec_console_cmd( static_cast<char>( getch() ) );
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-19 18:18:21 +01:00
|
|
|
#else
|
2016-02-19 19:26:35 +01:00
|
|
|
void ConsoleCommand::check_console_commands( Clib::KeyboardHook* kb )
|
|
|
|
|
{
|
|
|
|
|
if ( kb->kbhit() )
|
|
|
|
|
{
|
|
|
|
|
exec_console_cmd( kb->getch() );
|
2015-01-19 18:18:21 +01:00
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
#endif
|
2026-01-17 10:30:21 +01:00
|
|
|
} // namespace Pol::Core
|