From: Ingo Ruhnke Date: Sun, 17 Aug 2014 19:11:41 +0000 (+0200) Subject: Split of the line buffer from Console into ConsoleBuffer class X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=d041b64d9d853852bf66b5a194c5beaf7e6fe611;p=supertux.git Split of the line buffer from Console into ConsoleBuffer class This fixes an issue where the Console got destructed and it's graphics free'd after the VideoSystem was already gone, thus crash on game exit. --- diff --git a/src/scripting/functions.cpp b/src/scripting/functions.cpp index 216aeb693..893191bb2 100644 --- a/src/scripting/functions.cpp +++ b/src/scripting/functions.cpp @@ -44,7 +44,7 @@ namespace scripting { SQInteger display(HSQUIRRELVM vm) { - Console::output << squirrel2string(vm, -1) << std::endl; + ConsoleBuffer::output << squirrel2string(vm, -1) << std::endl; return 0; } diff --git a/src/scripting/squirrel_util.cpp b/src/scripting/squirrel_util.cpp index e2d13ba3b..9e80aedac 100644 --- a/src/scripting/squirrel_util.cpp +++ b/src/scripting/squirrel_util.cpp @@ -43,8 +43,8 @@ static void printfunc(HSQUIRRELVM, const char* str, ...) char buf[4096]; va_list arglist; va_start(arglist, str); - vsprintf(buf, str, arglist); - Console::output << (const char*) buf << std::flush; + vsnprintf(buf, sizeof(buf), str, arglist); + ConsoleBuffer::output << (const char*) buf << std::flush; va_end(arglist); } diff --git a/src/supertux/console.cpp b/src/supertux/console.cpp index 3a5f148d6..6b866b25d 100644 --- a/src/supertux/console.cpp +++ b/src/supertux/console.cpp @@ -28,10 +28,75 @@ /// speed (pixels/s) the console closes static const float FADE_SPEED = 1; -Console::Console() : +ConsoleBuffer::ConsoleBuffer() : + m_lines() +{ +} + +void +ConsoleBuffer::addLines(const std::string& s) +{ + std::istringstream iss(s); + std::string line; + while (std::getline(iss, line, '\n')) + { + addLine(line); + } +} + +void +ConsoleBuffer::addLine(const std::string& s_) +{ + std::string s = s_; + + // output line to stderr + std::cerr << s << std::endl; + + // wrap long lines + std::string overflow; + int line_count = 0; + do { + m_lines.push_front(Font::wrap_to_chars(s, 99, &overflow)); + line_count += 1; + s = overflow; + } while (s.length() > 0); + + // trim scrollback buffer + while (m_lines.size() >= 1000) + { + m_lines.pop_back(); + } + + if (Console::current()) + { + Console::current()->on_buffer_change(line_count); + } +} + +void +ConsoleBuffer::flush(ConsoleStreamBuffer& buffer) +{ + if (&buffer == &s_outputBuffer) + { + std::string s = s_outputBuffer.str(); + if ((s.length() > 0) && ((s[s.length()-1] == '\n') || (s[s.length()-1] == '\r'))) + { + while ((s[s.length()-1] == '\n') || (s[s.length()-1] == '\r')) + { + s.erase(s.length()-1); + } + addLines(s); + s_outputBuffer.str(std::string()); + } + } +} + +Console::Console(ConsoleBuffer& buffer) : + m_buffer(buffer), + m_inputBuffer(), + m_inputBufferPosition(0), m_history(), m_history_position(m_history.end()), - m_lines(), m_background(Surface::create("images/engine/console.png")), m_background2(Surface::create("images/engine/console2.png")), m_vm(NULL), @@ -55,16 +120,20 @@ Console::~Console() } void -Console::flush(ConsoleStreamBuffer* buffer) +Console::on_buffer_change(int line_count) { - if (buffer == &outputBuffer) { - std::string s = outputBuffer.str(); - if ((s.length() > 0) && ((s[s.length()-1] == '\n') || (s[s.length()-1] == '\r'))) { - while ((s[s.length()-1] == '\n') || (s[s.length()-1] == '\r')) s.erase(s.length()-1); - addLines(s); - outputBuffer.str(std::string()); + // increase console height if necessary + if (m_stayOpen > 0 && m_height < 64) + { + if(m_height < 4) + { + m_height = 4; } + m_height += m_font->get_height() * line_count; } + + // reset console to full opacity + m_alpha = 1.0; } void @@ -121,9 +190,9 @@ Console::execute_script(const std::string& command) throw SquirrelError(m_vm, "Problem while executing command"); if(sq_gettype(m_vm, -1) != OT_NULL) - addLines(squirrel2string(m_vm, -1)); + m_buffer.addLines(squirrel2string(m_vm, -1)); } catch(std::exception& e) { - addLines(e.what()); + m_buffer.addLines(e.what()); } SQInteger newtop = sq_gettop(m_vm); if(newtop < oldtop) { @@ -136,34 +205,34 @@ Console::execute_script(const std::string& command) void Console::input(char c) { - inputBuffer.insert(inputBufferPosition, 1, c); - inputBufferPosition++; + m_inputBuffer.insert(m_inputBufferPosition, 1, c); + m_inputBufferPosition++; } void Console::backspace() { - if ((inputBufferPosition > 0) && (inputBuffer.length() > 0)) { - inputBuffer.erase(inputBufferPosition-1, 1); - inputBufferPosition--; + if ((m_inputBufferPosition > 0) && (m_inputBuffer.length() > 0)) { + m_inputBuffer.erase(m_inputBufferPosition-1, 1); + m_inputBufferPosition--; } } void Console::eraseChar() { - if (inputBufferPosition < (int)inputBuffer.length()) { - inputBuffer.erase(inputBufferPosition, 1); + if (m_inputBufferPosition < (int)m_inputBuffer.length()) { + m_inputBuffer.erase(m_inputBufferPosition, 1); } } void Console::enter() { - addLines("> "+inputBuffer); - parse(inputBuffer); - inputBuffer = ""; - inputBufferPosition = 0; + m_buffer.addLines("> " + m_inputBuffer); + parse(m_inputBuffer); + m_inputBuffer = ""; + m_inputBufferPosition = 0; } void @@ -185,22 +254,22 @@ Console::show_history(int offset_) offset_++; } if (m_history_position == m_history.end()) { - inputBuffer = ""; - inputBufferPosition = 0; + m_inputBuffer = ""; + m_inputBufferPosition = 0; } else { - inputBuffer = *m_history_position; - inputBufferPosition = inputBuffer.length(); + m_inputBuffer = *m_history_position; + m_inputBufferPosition = m_inputBuffer.length(); } } void Console::move_cursor(int offset_) { - if (offset_ == -65535) inputBufferPosition = 0; - if (offset_ == +65535) inputBufferPosition = inputBuffer.length(); - inputBufferPosition+=offset_; - if (inputBufferPosition < 0) inputBufferPosition = 0; - if (inputBufferPosition > (int)inputBuffer.length()) inputBufferPosition = inputBuffer.length(); + if (offset_ == -65535) m_inputBufferPosition = 0; + if (offset_ == +65535) m_inputBufferPosition = m_inputBuffer.length(); + m_inputBufferPosition+=offset_; + if (m_inputBufferPosition < 0) m_inputBufferPosition = 0; + if (m_inputBufferPosition > (int)m_inputBuffer.length()) m_inputBufferPosition = m_inputBuffer.length(); } // Helper functions for Console::autocomplete @@ -271,15 +340,15 @@ sq_insert_commands(std::list& cmds, HSQUIRRELVM vm, std::string tab void Console::autocomplete() { - //int autocompleteFrom = inputBuffer.find_last_of(" ();+", inputBufferPosition); - int autocompleteFrom = inputBuffer.find_last_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_->.", inputBufferPosition); + //int autocompleteFrom = m_inputBuffer.find_last_of(" ();+", m_inputBufferPosition); + int autocompleteFrom = m_inputBuffer.find_last_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_->.", m_inputBufferPosition); if (autocompleteFrom != (int)std::string::npos) { autocompleteFrom += 1; } else { autocompleteFrom = 0; } - std::string prefix = inputBuffer.substr(autocompleteFrom, inputBufferPosition - autocompleteFrom); - addLines("> "+prefix); + std::string prefix = m_inputBuffer.substr(autocompleteFrom, m_inputBufferPosition - autocompleteFrom); + m_buffer.addLines("> " + prefix); std::list cmds; @@ -301,66 +370,35 @@ Console::autocomplete() sq_pop(m_vm, 1); // remove table // depending on number of hits, show matches or autocomplete - if (cmds.empty()) addLines("No known command starts with \""+prefix+"\""); - if (cmds.size() == 1) { + if (cmds.empty()) + { + m_buffer.addLines("No known command starts with \"" + prefix + "\""); + } + + if (cmds.size() == 1) + { // one match: just replace input buffer with full command std::string replaceWith = cmds.front(); - inputBuffer.replace(autocompleteFrom, prefix.length(), replaceWith); - inputBufferPosition += (replaceWith.length() - prefix.length()); + m_inputBuffer.replace(autocompleteFrom, prefix.length(), replaceWith); + m_inputBufferPosition += (replaceWith.length() - prefix.length()); } - if (cmds.size() > 1) { + + if (cmds.size() > 1) + { // multiple matches: show all matches and set input buffer to longest common prefix std::string commonPrefix = cmds.front(); while (cmds.begin() != cmds.end()) { std::string cmd = cmds.front(); cmds.pop_front(); - addLines(cmd); + m_buffer.addLines(cmd); for (int n = commonPrefix.length(); n >= 1; n--) { if (cmd.compare(0, n, commonPrefix) != 0) commonPrefix.resize(n-1); else break; } } std::string replaceWith = commonPrefix; - inputBuffer.replace(autocompleteFrom, prefix.length(), replaceWith); - inputBufferPosition += (replaceWith.length() - prefix.length()); - } -} - -void -Console::addLines(std::string s) -{ - std::istringstream iss(s); - std::string line; - while (std::getline(iss, line, '\n')) addLine(line); -} - -void -Console::addLine(std::string s) -{ - // output line to stderr - std::cerr << s << std::endl; - - // wrap long lines - std::string overflow; - unsigned int line_count = 0; - do { - m_lines.push_front(Font::wrap_to_chars(s, 99, &overflow)); - line_count++; - s = overflow; - } while (s.length() > 0); - - // trim scrollback buffer - while (m_lines.size() >= 1000) - m_lines.pop_back(); - - // increase console height if necessary - if ((m_stayOpen > 0) && (m_height < 64)) { - if(m_height < 4) - m_height = 4; - m_height += m_font->get_height() * line_count; + m_inputBuffer.replace(autocompleteFrom, prefix.length(), replaceWith); + m_inputBufferPosition += (replaceWith.length() - prefix.length()); } - - // reset console to full opacity - m_alpha = 1.0; } void @@ -395,9 +433,8 @@ Console::parse(std::string s) try { execute_script(s); } catch(std::exception& e) { - addLines(e.what()); + m_buffer.addLines(e.what()); } - } bool @@ -439,8 +476,8 @@ Console::hide() m_stayOpen = 0; // clear input buffer - inputBuffer = ""; - inputBufferPosition = 0; + m_inputBuffer = ""; + m_inputBufferPosition = 0; // SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL); } @@ -481,18 +518,18 @@ Console::draw(DrawingContext& context) context.push_transform(); context.set_alpha(m_alpha); - context.draw_surface(m_background2, - Vector(SCREEN_WIDTH/2 - m_background->get_width()/2 - m_background->get_width() + m_backgroundOffset, - m_height - m_background->get_height()), + context.draw_surface(m_background2, + Vector(SCREEN_WIDTH/2 - m_background->get_width()/2 - m_background->get_width() + m_backgroundOffset, + m_height - m_background->get_height()), layer); - context.draw_surface(m_background2, + context.draw_surface(m_background2, Vector(SCREEN_WIDTH/2 - m_background->get_width()/2 + m_backgroundOffset, - m_height - m_background->get_height()), + m_height - m_background->get_height()), layer); - for (int x = (SCREEN_WIDTH/2 - m_background->get_width()/2 + for (int x = (SCREEN_WIDTH/2 - m_background->get_width()/2 - (static_cast(ceilf((float)SCREEN_WIDTH / - (float)m_background->get_width()) - 1) * m_background->get_width())); - x < SCREEN_WIDTH; + (float)m_background->get_width()) - 1) * m_background->get_width())); + x < SCREEN_WIDTH; x += m_background->get_width()) { context.draw_surface(m_background, Vector(x, m_height - m_background->get_height()), layer); @@ -505,15 +542,16 @@ Console::draw(DrawingContext& context) if (m_focused) { lineNo++; float py = m_height-4-1 * m_font->get_height(); - context.draw_text(m_font, "> "+inputBuffer, Vector(4, py), ALIGN_LEFT, layer); + context.draw_text(m_font, "> "+m_inputBuffer, Vector(4, py), ALIGN_LEFT, layer); if (SDL_GetTicks() % 1000 < 750) { - int cursor_px = 2 + inputBufferPosition; + int cursor_px = 2 + m_inputBufferPosition; context.draw_text(m_font, "_", Vector(4 + (cursor_px * m_font->get_text_width("X")), py), ALIGN_LEFT, layer); } } int skipLines = -m_offset; - for (std::list::iterator i = m_lines.begin(); i != m_lines.end(); i++) { + for (std::list::iterator i = m_buffer.m_lines.begin(); i != m_buffer.m_lines.end(); i++) + { if (skipLines-- > 0) continue; lineNo++; float py = m_height - 4 - lineNo * m_font->get_height(); @@ -523,9 +561,7 @@ Console::draw(DrawingContext& context) context.pop_transform(); } -int Console::inputBufferPosition = 0; -std::string Console::inputBuffer; -ConsoleStreamBuffer Console::outputBuffer; -std::ostream Console::output(&Console::outputBuffer); +ConsoleStreamBuffer ConsoleBuffer::s_outputBuffer; +std::ostream ConsoleBuffer::output(&ConsoleBuffer::s_outputBuffer); /* EOF */ diff --git a/src/supertux/console.hpp b/src/supertux/console.hpp index 27f774d6d..d1c1da902 100644 --- a/src/supertux/console.hpp +++ b/src/supertux/console.hpp @@ -32,13 +32,35 @@ class ConsoleStreamBuffer; class ConsoleCommandReceiver; class DrawingContext; +class ConsoleBuffer : public Currenton +{ +public: + static std::ostream output; /**< stream of characters to output to the console. Do not forget to send std::endl or to flush the stream. */ + static ConsoleStreamBuffer s_outputBuffer; /**< stream buffer used by output stream */ + +public: + std::list m_lines; /**< backbuffer of lines sent to the console. New lines get added to front. */ + +public: + ConsoleBuffer(); + + void addLines(const std::string& s); /**< display a string of (potentially) multiple lines in the console */ + void addLine(const std::string& s); /**< display a line in the console */ + + void flush(ConsoleStreamBuffer& buffer); /**< act upon changes in a ConsoleStreamBuffer */ + +private: + ConsoleBuffer(const ConsoleBuffer&) = delete; + ConsoleBuffer& operator=(const ConsoleBuffer&) = delete; +}; + class Console : public Currenton { public: - Console(); + Console(ConsoleBuffer& buffer); ~Console(); - static std::ostream output; /**< stream of characters to output to the console. Do not forget to send std::endl or to flush the stream. */ + void on_buffer_change(int line_count); void input(char c); /**< add character to inputBuffer */ void backspace(); /**< delete character left of inputBufferPosition */ @@ -60,9 +82,13 @@ public: bool hasFocus(); /**< true if characters should be sent to the console instead of their normal target */ private: + ConsoleBuffer& m_buffer; + + std::string m_inputBuffer; /**< string used for keyboard input */ + int m_inputBufferPosition; /**< position in inputBuffer before which to append new characters */ + std::list m_history; /**< command history. New lines get added to back. */ std::list::iterator m_history_position; /**< item of command history that is currently displayed */ - std::list m_lines; /**< backbuffer of lines sent to the console. New lines get added to front. */ SurfacePtr m_background; /**< console background image */ SurfacePtr m_background2; /**< second, moving console background image */ @@ -79,12 +105,6 @@ private: float m_stayOpen; - static int inputBufferPosition; /**< position in inputBuffer before which to append new characters */ - static std::string inputBuffer; /**< string used for keyboard input */ - static ConsoleStreamBuffer outputBuffer; /**< stream buffer used by output stream */ - - void addLines(std::string s); /**< display a string of (potentially) multiple lines in the console */ - void addLine(std::string s); /**< display a line in the console */ void parse(std::string s); /**< react to a given command */ /** ready a virtual machine instance, creating a new thread and loading default .nut files if needed */ @@ -95,9 +115,6 @@ private: bool consoleCommand(std::string command, std::vector arguments); /**< process internal command; return false if command was unknown, true otherwise */ - friend class ConsoleStreamBuffer; - void flush(ConsoleStreamBuffer* buffer); /**< act upon changes in a ConsoleStreamBuffer */ - private: Console(const Console&); Console & operator=(const Console&); @@ -109,8 +126,8 @@ public: int sync() { int result = std::stringbuf::sync(); - if(Console::current()) - Console::current()->flush(this); + if(ConsoleBuffer::current()) + ConsoleBuffer::current()->flush(*this); return result; } }; diff --git a/src/supertux/main.cpp b/src/supertux/main.cpp index 9e82c3d6e..c91c18ed4 100644 --- a/src/supertux/main.cpp +++ b/src/supertux/main.cpp @@ -309,7 +309,7 @@ Main::run(int argc, char** argv) } init_sdl(); - //ConsoleBuffer console_buffer; + ConsoleBuffer console_buffer; timelog("controller"); InputManager input_manager; @@ -327,7 +327,7 @@ Main::run(int argc, char** argv) sound_manager.enable_sound(g_config->sound_enabled); sound_manager.enable_music(g_config->music_enabled); - Console console; + Console console(console_buffer); timelog("scripting"); scripting::init_squirrel(g_config->enable_script_debugger); diff --git a/src/util/log.cpp b/src/util/log.cpp index 0b30709ac..de4fb3df5 100644 --- a/src/util/log.cpp +++ b/src/util/log.cpp @@ -26,8 +26,8 @@ LogLevel g_log_level = LOG_WARNING; static std::ostream& get_logging_instance (void) { - if (Console::current()) - return (Console::output); + if (ConsoleBuffer::current()) + return (ConsoleBuffer::output); else return (std::cerr); }