# HG changeset patch # User Teemu Piippo # Date 1431704182 -10800 # Node ID 4f7c2c9446374f2f16bad1da96f3e0ebbf12c1bd # Parent 0e947b487b18ab3c4af8212f4aa9d87d5c692503# Parent 9ab869656b9e6cc324b898810253f76db4d9b30c Merge tab-complete diff -r 9ab869656b9e -r 4f7c2c944637 .hgtags --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgtags Fri May 15 18:36:22 2015 +0300 @@ -0,0 +1,1 @@ +5e968dc8d552598f5bb5343bd5fa0c24088b6ee9 1.0 diff -r 9ab869656b9e -r 4f7c2c944637 CMakeLists.txt --- a/CMakeLists.txt Mon Dec 15 20:19:18 2014 +0200 +++ b/CMakeLists.txt Fri May 15 18:36:22 2015 +0300 @@ -2,6 +2,7 @@ project (zfc9000) set (SOURCE_FILES + sources/coloredline.cpp sources/format.cpp sources/interface.cpp sources/main.cpp diff -r 9ab869656b9e -r 4f7c2c944637 README.md --- a/README.md Mon Dec 15 20:19:18 2014 +0200 +++ b/README.md Fri May 15 18:36:22 2015 +0300 @@ -1,1 +1,21 @@ -Text-based RCON utility for Zandronum +zfc9000 +--------- + +zfc9000 is a text-based RCON utility for the Zandronum Doom source port. + +Features: + +* Fully textual, can be used over SSH for instance +* Supports in-game colorcodes +* Input history +* A subset of readline shortcuts +* a nicklist + +To use, either: + +* use the command line: ```zfc9000
``` +* use Ctrl-N within the application to create a new connection + +To compile, clone the sources off the mercurial repository and check out the version desired. Ensure you have the proper ncurses libraries installed, e.g. ```libncurses5-dev``` and ```libncursesw5-dev``` on Ubuntu. Compile using cmake. + +Binaries are provided but these may or may not work on your system. diff -r 9ab869656b9e -r 4f7c2c944637 sources/basics.h --- a/sources/basics.h Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/basics.h Fri May 15 18:36:22 2015 +0300 @@ -44,6 +44,11 @@ using std::min; using std::max; +template +using Function = std::function; + +// ------------------------------------------------------------------------------------------------- +// enum Color { BLACK, @@ -59,16 +64,35 @@ NUM_COLORS }; -template -using Function = std::function; +#define TEXTCOLOR_Escape "\x1C" +#define TEXTCOLOR_Black TEXTCOLOR_Escape "M" +#define TEXTCOLOR_Gray TEXTCOLOR_Escape "U" +#define TEXTCOLOR_Silver TEXTCOLOR_Escape "C" +#define TEXTCOLOR_White TEXTCOLOR_Escape "J" +#define TEXTCOLOR_Red TEXTCOLOR_Escape "R" +#define TEXTCOLOR_BrightRed TEXTCOLOR_Escape "G" +#define TEXTCOLOR_Green TEXTCOLOR_Escape "Q" +#define TEXTCOLOR_BrightGreen TEXTCOLOR_Escape "D" +#define TEXTCOLOR_Yellow TEXTCOLOR_Escape "K" +#define TEXTCOLOR_BrightYellow TEXTCOLOR_Escape "F" +#define TEXTCOLOR_Blue TEXTCOLOR_Escape "H" +#define TEXTCOLOR_BrightBlue TEXTCOLOR_Escape "N" +#define TEXTCOLOR_Magenta TEXTCOLOR_Escape "T" +#define TEXTCOLOR_BrightCyan TEXTCOLOR_Escape "V" +#define TEXTCOLOR_Reset TEXTCOLOR_Escape "-" +// ------------------------------------------------------------------------------------------------- +// FUNCTION print_to_console (String a) -> void; -FUNCTION request_exit() -> void; +// ------------------------------------------------------------------------------------------------- +// template inline FUNCTION clamp (T a, T b, T c) -> T { return (a < b) ? b : (a > c) ? c : a; } +// ------------------------------------------------------------------------------------------------- +// struct Exitception {}; diff -r 9ab869656b9e -r 4f7c2c944637 sources/coloredline.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sources/coloredline.cpp Fri May 15 18:36:22 2015 +0300 @@ -0,0 +1,156 @@ +/* + Copyright 2014 Teemu Piippo + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "coloredline.h" + +static const struct +{ + const char* name; + Color color; + bool bold; +} g_colorCodes['v' - 'a' + 1] = +{ + { "Brick", RED, true }, // a + { "Tan", YELLOW, true }, // b + { "Gray", WHITE, false }, // c + { "Green", GREEN, true }, // d + { "Brown", YELLOW, false }, // e + { "Gold", YELLOW, true }, // f + { "Red", RED, true }, // g + { "Blue", BLUE, false }, // h + { "Orange", YELLOW, false }, // i + { "White", WHITE, true }, // j + { "Yellow", YELLOW, true }, // k + { "Untranslated", DEFAULT, false }, // l + { "Black", BLACK, false }, // m + { "Blue", BLUE, true }, // n + { "Cream", YELLOW, true }, // o + { "Olive", GREEN, true }, // p + { "Dark Green", GREEN, false }, // q + { "Dark Red", RED, false }, // r + { "Dark Brown", YELLOW, false }, // s + { "Purple", MAGENTA, false }, // t + { "Dark Gray", BLACK, true }, // u + { "Cyan", CYAN, true }, // v +}; + +// ------------------------------------------------------------------------------------------------- +// +void ColoredLine::finalize() +{ + if (m_activeColor != DEFAULT) + set_color (m_activeColor, false); + + if (m_boldActive) + m_data << RLINE_OFF_BOLD; + + m_final = true; +} + +// ------------------------------------------------------------------------------------------------- +// +void ColoredLine::add_char (char ch) +{ + if (m_final) + return; // Don't touch finalized lines. + + if (ch == '\x1C' and m_colorCodeStage == 0) + { + m_colorCodeStage = 1; + return; + } + + if (m_colorCodeStage == 1) + { + if (m_activeColor != DEFAULT) + set_color (m_activeColor, false); + + if (m_boldActive) + m_data << RLINE_OFF_BOLD; + + // Chars may be in uppercase + if (ch >= 'A' and ch <= 'V') + ch += 'a' - 'A'; + + if (ch >= 'a' and ch <= 'v' and ch != 'l') + { + auto colorInfo = g_colorCodes[ch - 'a']; + m_activeColor = colorInfo.color; + m_boldActive = colorInfo.bold; + assert (m_activeColor < 8); + set_color (m_activeColor, true); + + if (m_boldActive) + m_data << RLINE_ON_BOLD; + } + + m_colorCodeStage = 0; + return; + } + + if (isprint (ch)) + { + m_string += ch; + m_data << int (ch); + ++m_length; + } +} + +// ------------------------------------------------------------------------------------------------- +// +void ColoredLine::set_color (Color a, bool on) +{ + switch (a) + { + case BLACK: m_data << (on ? RLINE_ON_BLACK : RLINE_OFF_BLACK); break; + case RED: m_data << (on ? RLINE_ON_RED : RLINE_OFF_RED); break; + case GREEN: m_data << (on ? RLINE_ON_GREEN : RLINE_OFF_GREEN); break; + case YELLOW: m_data << (on ? RLINE_ON_YELLOW : RLINE_OFF_YELLOW); break; + case BLUE: m_data << (on ? RLINE_ON_BLUE : RLINE_OFF_BLUE); break; + case MAGENTA: m_data << (on ? RLINE_ON_MAGENTA : RLINE_OFF_MAGENTA); break; + case CYAN: m_data << (on ? RLINE_ON_CYAN : RLINE_OFF_CYAN); break; + case WHITE: m_data << (on ? RLINE_ON_WHITE : RLINE_OFF_WHITE); break; + case NUM_COLORS: + case DEFAULT: assert (false); break; + } +} + +// ------------------------------------------------------------------------------------------------- +// How many rows does this line take up? +// +int ColoredLine::rows (int cols) const +{ + int rows = length() / cols; + + if (length() % cols != 0) + rows++; + + return max (rows, 1); +} diff -r 9ab869656b9e -r 4f7c2c944637 sources/coloredline.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sources/coloredline.h Fri May 15 18:36:22 2015 +0300 @@ -0,0 +1,81 @@ +/* + Copyright 2014 Teemu Piippo + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once +#include "main.h" + +// ------------------------------------------------------------------------------------------------- +// +enum +{ + RLINE_ON_BLACK = 256, + RLINE_ON_RED, + RLINE_ON_GREEN, + RLINE_ON_YELLOW, + RLINE_ON_BLUE, + RLINE_ON_MAGENTA, + RLINE_ON_CYAN, + RLINE_ON_WHITE, + RLINE_ON_BOLD, + RLINE_OFF_BLACK, + RLINE_OFF_RED, + RLINE_OFF_GREEN, + RLINE_OFF_YELLOW, + RLINE_OFF_BLUE, + RLINE_OFF_MAGENTA, + RLINE_OFF_CYAN, + RLINE_OFF_WHITE, + RLINE_OFF_BOLD, +}; + +// ------------------------------------------------------------------------------------------------- +// +class ColoredLine +{ +public: + ColoredLine() {} + + const Vector& data() const { return m_data; } + int length() const { return m_length; } + void add_char (char ch); + void finalize(); + int rows (int cols) const; + +private: + void set_color (Color a, bool on); + + Vector m_data; + int m_length = 0; + bool m_final = false; + Color m_activeColor = DEFAULT; + bool m_boldActive = false; + int m_colorCodeStage = 0; + String m_string; +}; diff -r 9ab869656b9e -r 4f7c2c944637 sources/colors.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sources/colors.h Fri May 15 18:36:22 2015 +0300 @@ -0,0 +1,1 @@ +#pragma once \ No newline at end of file diff -r 9ab869656b9e -r 4f7c2c944637 sources/format.cpp --- a/sources/format.cpp Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/format.cpp Fri May 15 18:36:22 2015 +0300 @@ -32,6 +32,7 @@ #include "format.h" // ------------------------------------------------------------------------------------------------- +// // Throws an error while formatting the string // static auto format_error (String fmtstr, const String errdescribe, int pos) -> void @@ -48,6 +49,7 @@ } // ------------------------------------------------------------------------------------------------- +// // Main formatter algorithm. // auto format_args (const String& fmtstr, const Vector& args) -> String diff -r 9ab869656b9e -r 4f7c2c944637 sources/format.h --- a/sources/format.h Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/format.h Fri May 15 18:36:22 2015 +0300 @@ -34,18 +34,19 @@ #include "geometry.h" #define FORMAT_OVERLOAD(...) \ - inline FUNCTION make_format_argument (__VA_ARGS__ a) -> String + inline String make_format_argument (__VA_ARGS__ a) -// // ------------------------------------------------------------------------------------------------- // - FORMAT_OVERLOAD (String) { return a; } FORMAT_OVERLOAD (char) { return String (a); } +FORMAT_OVERLOAD (short int) { return String::from_number (a); } FORMAT_OVERLOAD (int) { return String::from_number (a); } FORMAT_OVERLOAD (long int) { return String::from_number (a); } FORMAT_OVERLOAD (double) { return String::from_number (a); } -FORMAT_OVERLOAD (size_t) { return String::from_number (a); } +FORMAT_OVERLOAD (unsigned short int) { return String::from_number (a); } +FORMAT_OVERLOAD (unsigned int) { return String::from_number (a); } +FORMAT_OVERLOAD (unsigned long int) { return String::from_number (a); } FORMAT_OVERLOAD (const char*) { return a; } FORMAT_OVERLOAD (std::nullptr_t) { (void) a; return ""; } FORMAT_OVERLOAD (bool) { return a ? "true" : "false"; } @@ -96,8 +97,15 @@ return "???"; } -FORMAT_OVERLOAD (Position) { return String ("(") + a.x + ", " + a.y + ")"; } -FORMAT_OVERLOAD (Size) { return String ("(") + a.width + "x" + a.height + ")"; } +FORMAT_OVERLOAD (Position) +{ + return String ("(") + a.x + ", " + a.y + ")"; +} + +FORMAT_OVERLOAD (Size) +{ + return String ("(") + a.width + "x" + a.height + ")"; +} FORMAT_OVERLOAD (Rectangle) { @@ -107,15 +115,17 @@ } // ------------------------------------------------------------------------------------------------- +// // Formats the given string with the given args. // FUNCTION format_args (const String& fmtstr, const Vector& args) -> String; // ------------------------------------------------------------------------------------------------- +// // Expands the given arguments into a vector of strings. // -template FUNCTION -expand_format_arguments (Vector& data, const T& arg, const RestTypes& ... rest) -> void +template +void expand_format_arguments (Vector& data, const T& arg, const RestTypes& ... rest) { data.append (make_format_argument (arg)); expand_format_arguments (data, rest...); @@ -149,8 +159,8 @@ // argument did not expand into a number in the first place, 0 is used // and 0x0 is printed. // -template FUNCTION -format (const String& fmtstr, const argtypes&... raw_args) -> String +template +String format (const String& fmtstr, const argtypes&... raw_args) { Vector args; expand_format_arguments (args, raw_args...); @@ -158,26 +168,28 @@ } // ------------------------------------------------------------------------------------------------- +// // This is an overload of format() where no arguments are supplied. // It returns the formatter string as-is. // static String format (const String& fmtstr) __attribute__ ((unused)); -static String // FUNCTION -format (const String& fmtstr) // -> String +static String format (const String& fmtstr) // -> String { return fmtstr; } // ------------------------------------------------------------------------------------------------- +// // Prints the formatting result to the given file handle // -template FUNCTION -print_to (FILE* fp, const String& fmtstr, Args const& ...args) -> void +template +void print_to (FILE* fp, const String& fmtstr, Args const& ...args) { std::fprintf (fp, "%s", format (fmtstr, args...).chars()); } // ------------------------------------------------------------------------------------------------- +// // Appends the formatting result to the given filename, if opening it succeeds // template @@ -193,6 +205,7 @@ } // ------------------------------------------------------------------------------------------------- +// // Prints the formatting result to the console // template @@ -200,3 +213,23 @@ { print_to_console (format (fmtstr, args...)); } + +// ------------------------------------------------------------------------------------------------- +// +// Prints the formatting result as a warning to the console +// +template +void print_warning (const String& fmtstr, const argtypes&... args) +{ + print_to_console (TEXTCOLOR_BrightYellow "-!- " + format (fmtstr, args...) + TEXTCOLOR_Reset); +} + +// ------------------------------------------------------------------------------------------------- +// +// Prints the formatting result as a warning to the console +// +template +void print_error (const String& fmtstr, const argtypes&... args) +{ + print_to_console (TEXTCOLOR_BrightRed "!!! " + format (fmtstr, args...) + TEXTCOLOR_Reset); +} \ No newline at end of file diff -r 9ab869656b9e -r 4f7c2c944637 sources/geometry.h --- a/sources/geometry.h Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/geometry.h Fri May 15 18:36:22 2015 +0300 @@ -43,12 +43,41 @@ x (0), y (0) {} - inline METHOD operator< (const Position& other) const -> bool; - inline METHOD operator> (const Position& other) const -> bool; - inline METHOD operator== (const Position& other) const -> bool; - inline METHOD operator<= (const Position& other) const -> bool; - inline METHOD operator>= (const Position& other) const -> bool; - inline METHOD operator!= (const Position& other) const -> bool; + bool operator< (const Position& other) const + { + if (y != other.y) + return y < other.y; + + return x < other.x; + } + + bool operator> (const Position& other) const + { + if (y != other.y) + return y > other.y; + + return x > other.x; + } + + bool operator== (const Position& other) const + { + return y == other.y and x == other.x; + } + + bool operator!= (const Position& other) const + { + return not operator== (other); + } + + bool operator<= (const Position& other) const + { + return not operator> (other); + } + + bool operator>= (const Position& other) const + { + return not operator< (other); + } }; // ------------------------------------------------------------------------------------------------- @@ -84,57 +113,3 @@ Position(), Size() {} }; - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -Position::operator< (const Position& other) const -> bool -{ - if (y != other.y) - return y < other.y; - - return x < other.x; -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -Position::operator> (const Position& other) const -> bool -{ - if (y != other.y) - return y > other.y; - - return x > other.x; -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -Position::operator== (const Position& other) const -> bool -{ - return y == other.y and x == other.x; -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -Position::operator<= (const Position& other) const -> bool -{ - return not operator> (other); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -Position::operator>= (const Position& other) const -> bool -{ - return not operator< (other); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -Position::operator!= (const Position& other) const -> bool -{ - return not operator== (other); -} diff -r 9ab869656b9e -r 4f7c2c944637 sources/interface.cpp --- a/sources/interface.cpp Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/interface.cpp Fri May 15 18:36:22 2015 +0300 @@ -29,54 +29,11 @@ */ #include +#include #include "interface.h" #include "network/rconsession.h" #include "network/ipaddress.h" - -enum -{ - RLINE_ON_BLACK = 256, - RLINE_ON_RED, - RLINE_ON_GREEN, - RLINE_ON_YELLOW, - RLINE_ON_BLUE, - RLINE_ON_MAGENTA, - RLINE_ON_CYAN, - RLINE_ON_WHITE, - RLINE_ON_BOLD, - RLINE_OFF_BLACK, - RLINE_OFF_RED, - RLINE_OFF_GREEN, - RLINE_OFF_YELLOW, - RLINE_OFF_BLUE, - RLINE_OFF_MAGENTA, - RLINE_OFF_CYAN, - RLINE_OFF_WHITE, - RLINE_OFF_BOLD, -}; - -class RendererLine -{ -public: - RendererLine() {} - - METHOD data() const -> const Vector& { return m_data; } - METHOD length() const -> int { return m_length; } - METHOD add_char (char ch) -> void; - METHOD finalize() -> void; - METHOD rows (int cols) const -> int; - -private: - METHOD set_color (Color a, bool on) -> void; - - Vector m_data; - int m_length = 0; - bool m_final = false; - Color m_activeColor = DEFAULT; - bool m_boldActive = false; - int m_colorCodeStage = 0; - String m_string; -}; +#include "coloredline.h" static const int g_pageSize = 10; @@ -88,48 +45,25 @@ INPUTSTATE_CONFIRM_DISCONNECTION, }; -static StringList g_input; -static int g_inputCursor = 0; -static int g_cursor = 0; -static int g_pan = 0; -static bool g_needRefresh = false; -static bool g_needStatusBarRender = false; -static bool g_needInputRender = false; -static bool g_needOutputRender = false; -static struct { char ch; int x; } g_cursorChar; -static Vector g_output;; -static int g_outputScroll = 0; -static String g_title; -static InputState g_inputState = INPUTSTATE_NORMAL; -static Function g_disconnectConfirmFunction = nullptr; -static IPAddress g_address; -static String g_statusBarText; - -static const struct { Color color; bool bold; } g_colorCodes['v' - 'a' + 1] = -{ - { RED, true }, // a - brick - { YELLOW, true }, // b - tan - { WHITE, false }, // c - gray - { GREEN, true }, // d - light green - { YELLOW, false }, // e - brown - { YELLOW, true }, // f - gold yellow - { RED, true }, // g - bright red - { BLUE, false }, // h - dark blue - { YELLOW, false }, // i - orange - { WHITE, true }, // j - white - { YELLOW, true }, // k - fire yellow - { DEFAULT, false }, // l - untranslated - { BLACK, false }, // m - black - { BLUE, true }, // n - light blue - { YELLOW, true }, // o - cream - { GREEN, true }, // p - olive green - { GREEN, false }, // q - dark green - { RED, false }, // r - dark red - { YELLOW, false }, // s - dark brown - { MAGENTA, false }, // t - purple - { BLACK, true }, // u - dark gray - { CYAN, true }, // v - cyan -}; +static StringList InputHistory; +static int InputCursor = 0; +static int CursorPosition = 0; +static int InputPanning = 0; +static bool NeedRefresh = false; +static bool NeedStatusBarRender = false; +static bool NeedInputRender = false; +static bool NeedOutputRender = false; +static bool NeedNicklistRender = false; +static struct { char ch; int x; } CursorCharacter; +static Vector OutputLines; +static int OutputScroll = 0; +static String Title; +static InputState CurrentInputState = INPUTSTATE_NORMAL; +static Function DisconnectConfirmFunction = nullptr; +static IPAddress CurrentAddress; +static String StatusBarText; +static StringList PlayerNames; +static String PasteBuffer; // ------------------------------------------------------------------------------------------------- // @@ -144,7 +78,7 @@ static FUNCTION current_input() -> const String& { - return g_input[g_inputCursor]; + return InputHistory[InputCursor]; } // ------------------------------------------------------------------------------------------------- @@ -154,10 +88,10 @@ static FUNCTION detach_input() -> void { - if (g_inputCursor > 0) + if (InputCursor > 0) { - g_input[0] = current_input(); - g_inputCursor = 0; + InputHistory[0] = current_input(); + InputCursor = 0; } } @@ -168,7 +102,7 @@ mutable_current_input() -> String& { detach_input(); - return g_input[g_inputCursor]; + return InputHistory[InputCursor]; } // ------------------------------------------------------------------------------------------------- @@ -177,19 +111,19 @@ move_input_cursor (int delta) -> void { // No input history when inputting addresses or passwords - if (g_inputState != INPUTSTATE_NORMAL) + if (CurrentInputState != INPUTSTATE_NORMAL) { - g_inputCursor = 0; + InputCursor = 0; return; } - int oldcursor = g_inputCursor; - g_inputCursor = clamp (g_inputCursor + delta, 0, g_input.size() - 1); + int oldcursor = InputCursor; + InputCursor = clamp (InputCursor + delta, 0, InputHistory.size() - 1); - if (g_inputCursor != oldcursor) + if (InputCursor != oldcursor) { - g_cursor = current_input().length(); - g_needInputRender = true; + CursorPosition = current_input().length(); + NeedInputRender = true; } } @@ -200,7 +134,7 @@ { String prompt; - switch (g_inputState) + switch (CurrentInputState) { case INPUTSTATE_NORMAL: prompt = ">"; break; case INPUTSTATE_ADDRESS: prompt = "address:"; break; @@ -218,25 +152,25 @@ { // Clear the input row (unless going to or from confirm state) if (newstate != INPUTSTATE_CONFIRM_DISCONNECTION - and g_inputState != INPUTSTATE_CONFIRM_DISCONNECTION) + and CurrentInputState != INPUTSTATE_CONFIRM_DISCONNECTION) { - g_inputCursor = 0; + InputCursor = 0; mutable_current_input().clear(); } switch (newstate) { case INPUTSTATE_ADDRESS: - if (g_address.host != 0) - mutable_current_input() = g_address.to_string (IP_WITH_PORT); + if (CurrentAddress.host != 0) + mutable_current_input() = CurrentAddress.to_string (IP_WITH_PORT); break; default: break; } - g_inputState = newstate; - g_needInputRender = true; + CurrentInputState = newstate; + NeedInputRender = true; } // ------------------------------------------------------------------------------------------------- @@ -252,11 +186,11 @@ ::refresh(); ::timeout (0); ::use_default_colors(); - g_input.clear(); - g_input << ""; - g_output.clear(); - g_output << RendererLine(); - g_title = format (APPNAME " %1 (%2)", full_version_string(), changeset_date_string()); + InputHistory.clear(); + InputHistory << ""; + OutputLines.clear(); + OutputLines << ColoredLine(); + Title = format (APPNAME " %1 (%2)", full_version_string(), changeset_date_string()); for (int i = 0; i < NUM_COLORS; ++i) for (int j = 0; j < NUM_COLORS; ++j) @@ -268,7 +202,7 @@ render_full(); refresh(); - g_needRefresh = false; + NeedRefresh = false; } // ------------------------------------------------------------------------------------------------- @@ -276,19 +210,19 @@ static FUNCTION interface_render_titlebar() -> void { - if (g_title.length() <= COLS) + if (Title.length() <= COLS) { int pair = interface_color_pair (WHITE, BLUE); - int startx = (COLS - g_title.length()) / 2; - int endx = startx + g_title.length(); + int startx = (COLS - Title.length()) / 2; + int endx = startx + Title.length(); attron (pair); - mvprintw (0, startx, "%s", g_title.chars()); + mvprintw (0, startx, "%s", Title.chars()); mvhline (0, 0, ' ', startx); mvhline (0, endx, ' ', COLS - endx); attroff (pair); } - g_needRefresh = true; + NeedRefresh = true; } // ------------------------------------------------------------------------------------------------- @@ -296,7 +230,7 @@ FUNCTION Interface::set_title (const String& title) -> void { - g_title = title; + Title = title; interface_render_titlebar(); } @@ -307,7 +241,7 @@ { if (RCONSession::get_session()->is_active()) { - g_disconnectConfirmFunction = afterwards; + DisconnectConfirmFunction = afterwards; set_input_state (INPUTSTATE_CONFIRM_DISCONNECTION); } else @@ -317,16 +251,95 @@ // ------------------------------------------------------------------------------------------------- // static FUNCTION +interface_nicklist_width() -> int +{ + // Allocate at least 12 characters, at most 24 characters, for the nicklist. If we cannot + // afford that (o_O) then we probably shouldn't draw the nicklist at all I think. + int nicklistWidth = COLS / 4; + + if (nicklistWidth < 12) + return 0; + + return min (nicklistWidth, 24); +} + +// ------------------------------------------------------------------------------------------------- +// Renders the given colored line onto the screen. Will wrap if allowWrap is true. Returns the +// 'y' value for the next line. +// +static FUNCTION +interface_render_colorline (int y, int x0, int width, + const ColoredLine& line, bool allowWrap) -> int +{ + int x = x0; + + for (int byte : line.data()) + { + if (x == x0 + width) + { + if (not allowWrap) + return y; + + x = x0; + ++y; + } + + if (isprint (byte)) + { + mvaddch (y, x, char (byte)); + ++x; + } + else switch (byte) + { + case RLINE_ON_BLACK: + case RLINE_ON_RED: + case RLINE_ON_GREEN: + case RLINE_ON_YELLOW: + case RLINE_ON_BLUE: + case RLINE_ON_MAGENTA: + case RLINE_ON_CYAN: + case RLINE_ON_WHITE: + attron (interface_color_pair (Color (byte - RLINE_ON_BLACK), DEFAULT)); + break; + + case RLINE_OFF_BLACK: + case RLINE_OFF_RED: + case RLINE_OFF_GREEN: + case RLINE_OFF_YELLOW: + case RLINE_OFF_BLUE: + case RLINE_OFF_MAGENTA: + case RLINE_OFF_CYAN: + case RLINE_OFF_WHITE: + attroff (interface_color_pair (Color (byte - RLINE_OFF_BLACK), DEFAULT)); + break; + + case RLINE_ON_BOLD: + attron (A_BOLD); + break; + + case RLINE_OFF_BOLD: + attroff (A_BOLD); + break; + } + } + + return y + 1; +} + +// ------------------------------------------------------------------------------------------------- +// +static FUNCTION interface_render_output() -> void { - if (g_output.size() == 1) + if (OutputLines.size() == 1) return; - g_outputScroll = clamp (g_outputScroll, 0, g_output.size() - 1); + OutputScroll = clamp (OutputScroll, 0, OutputLines.size() - 1); int height = LINES - 3; + int width = COLS - interface_nicklist_width(); int printOffset = 0; - int end = g_output.size() - 1 - g_outputScroll; + int end = OutputLines.size() - 1 - OutputScroll; int start = end; int usedHeight = 0; int y = 1; @@ -335,7 +348,7 @@ // Where to start? while (start > 0) { - int rows = g_output[start - 1].rows (COLS); + int rows = OutputLines[start - 1].rows (width); if (usedHeight + rows > height) { @@ -351,9 +364,9 @@ // See if there's any more rows to use (end may be too small) if (not tightFit) { - while (end < g_output.size()) + while (end < OutputLines.size()) { - int rows = g_output[end].rows (COLS); + int rows = OutputLines[end].rows (width); if (usedHeight + rows > height) { @@ -369,7 +382,7 @@ if (start > 0) printOffset = height - usedHeight; - g_outputScroll = g_output.size() - 1 - end; + OutputScroll = OutputLines.size() - 1 - end; if (start < 0 or start == end or printOffset >= height) return; @@ -378,62 +391,53 @@ // Clear the display for (int i = y; i < y + height; ++i) - mvhline (i, 0, ' ', COLS); + mvhline (i, 0, ' ', width); // Print the lines y += printOffset; for (int i = start; i < end; ++i) + y = interface_render_colorline (y, 0, width, OutputLines[i], true); + + NeedOutputRender = false; + NeedRefresh = true; +} + +// ------------------------------------------------------------------------------------------------- +// +static FUNCTION +interface_render_nicklist() -> void +{ + int width = interface_nicklist_width(); + int height = LINES- 3; + int y = 1; + int x = COLS - width; + + if (width == 0) + return; + + for (int i = 0; i < height; ++i) { - int x = 0; + mvhline (y, x, ' ', width); - for (int byte : g_output[i].data()) + if (i < PlayerNames.size()) { - if (x == COLS) + String displaynick = PlayerNames[i]; + + if (displaynick.length() > width) { - x = 0; - ++y; + displaynick = displaynick.mid (0, width - 3); + displaynick += "..."; } - if (isprint (byte)) - mvaddch (y, x++, char (byte)); - else switch (byte) - { - case RLINE_ON_BLACK: - case RLINE_ON_GREEN: - case RLINE_ON_YELLOW: - case RLINE_ON_BLUE: - case RLINE_ON_MAGENTA: - case RLINE_ON_CYAN: - case RLINE_ON_WHITE: - attron (interface_color_pair (Color (byte - RLINE_ON_BLACK), DEFAULT)); - break; - - case RLINE_OFF_BLACK: - case RLINE_OFF_GREEN: - case RLINE_OFF_YELLOW: - case RLINE_OFF_BLUE: - case RLINE_OFF_MAGENTA: - case RLINE_OFF_CYAN: - case RLINE_OFF_WHITE: - attroff (interface_color_pair (Color (byte - RLINE_OFF_BLACK), DEFAULT)); - break; - - case RLINE_ON_BOLD: - attron (A_BOLD); - break; - - case RLINE_OFF_BOLD: - attroff (A_BOLD); - break; - } + mvprintw (y, x, "%s", displaynick.chars()); } - ++y; + y++; } - g_needOutputRender = false; - g_needRefresh = true; + NeedNicklistRender = false; + NeedRefresh = true; } // ------------------------------------------------------------------------------------------------- @@ -445,12 +449,13 @@ // If we're asking the user if they want to disconnect, we don't render any input strings, // just the confirmation message. - if (g_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) + if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION) { attron (promptColor); mvhline (LINES - 2, 0, ' ', COLS); mvprintw (LINES - 2, 0, "Are you sure you want to disconnect? y/n"); attroff (promptColor); + NeedRefresh = true; return; } @@ -460,29 +465,29 @@ int y = LINES - 2; // If we're inputting a password, replace it with asterisks - if (g_inputState == INPUTSTATE_PASSWORD) + if (CurrentInputState == INPUTSTATE_PASSWORD) { for (char& ch : displayString) ch = '*'; } // Ensure the cursor is within bounds - g_cursor = clamp (g_cursor, 0, displayString.length()); + CursorPosition = clamp (CursorPosition, 0, displayString.length()); // Ensure that the cursor is always in view, adjust panning if this is not the case - if (g_cursor > g_pan + displayLength) - g_pan = g_cursor - displayLength; // cursor went too far right - else if (g_cursor < g_pan) - g_pan = g_cursor; // cursor went past the pan value to the left + if (CursorPosition > InputPanning + displayLength) + InputPanning = CursorPosition - displayLength; // cursor went too far right + else if (CursorPosition < InputPanning) + InputPanning = CursorPosition; // cursor went past the pan value to the left // What part of the string to draw? - int start = g_pan; + int start = InputPanning; int end = min (displayString.length(), start + displayLength); - assert (g_cursor >= start and g_cursor <= end); + assert (CursorPosition >= start and CursorPosition <= end); // Render the input string mvhline (LINES - 2, 0, ' ', COLS); - mvprintw (y, prompt.length() + 1, "%s", displayString.chars()); + mvprintw (y, prompt.length() + 1, "%s", displayString.mid (start, end).chars()); // Render the prompt attron (promptColor); @@ -491,10 +496,10 @@ // Store in memory where the cursor is now (so that we can re-draw it to position the terminal // cursor). - g_cursorChar.ch = g_cursor != 0 ? displayString[g_cursor - 1] : '\0'; - g_cursorChar.x = prompt.length() + (g_cursor - g_pan); - g_needRefresh = true; - g_needInputRender = false; + CursorCharacter.ch = CursorPosition != 0 ? displayString[CursorPosition - 1] : '\0'; + CursorCharacter.x = prompt.length() + (CursorPosition - InputPanning); + NeedRefresh = true; + NeedInputRender = false; } // ------------------------------------------------------------------------------------------------- @@ -506,10 +511,10 @@ int y = LINES - 1; attron (color); mvhline (y, 0, ' ', COLS); - mvprintw (y, 0, "%s", g_statusBarText.chars()); + mvprintw (y, 0, "%s", StatusBarText.chars()); attroff (color); - g_needRefresh = true; - g_needStatusBarRender = false; + NeedRefresh = true; + NeedStatusBarRender = false; } // ------------------------------------------------------------------------------------------------- @@ -546,10 +551,10 @@ text += "^N to connect, ^Q to quit"; - if (text != g_statusBarText) + if (text != StatusBarText) { - g_statusBarText = text; - g_needStatusBarRender = true; + StatusBarText = text; + NeedStatusBarRender = true; } } @@ -563,6 +568,7 @@ interface_render_output(); interface_render_statusbar(); interface_render_input(); + interface_render_nicklist(); } // ------------------------------------------------------------------------------------------------- @@ -571,19 +577,74 @@ interface_position_cursor() -> void { // This is only relevant if the input string is being drawn - if (g_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) + if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION) return; int y = LINES - 2; - if (g_cursorChar.ch != '\0') - mvprintw (y, g_cursorChar.x, "%c", g_cursorChar.ch); + if (CursorCharacter.ch != '\0') + mvprintw (y, CursorCharacter.x, "%c", CursorCharacter.ch); else mvprintw (y, interface_prompt_string().length(), " "); } // ------------------------------------------------------------------------------------------------- // +static FUNCTION +interface_find_previous_word() -> int +{ + const String& input = current_input(); + int pos = CursorPosition; + + // Move past whitespace + while (pos > 0 and isspace (input[pos - 1])) + pos--; + + // Move past the word + while (pos > 0 and not isspace (input[pos - 1])) + pos--; + + return pos; +} + +// ------------------------------------------------------------------------------------------------- +// +static FUNCTION +interface_find_next_word() -> int +{ + const String& input = current_input(); + int pos = CursorPosition; + + // Move past current whitespace + while (pos < input.length() and isspace (input[pos])) + pos++; + + // Move past the word + while (input[pos] != '\0' and not isspace (input[pos])) + pos++; + + return pos; +} + +// ------------------------------------------------------------------------------------------------- +// +static FUNCTION +yank (int a, int b) -> void +{ + if (a >= b) + return; + + if (CursorPosition > a and CursorPosition <= b) + CursorPosition = a; + + String& input = mutable_current_input(); + PasteBuffer = input.mid (a, b); + input.remove (a, b - a); + NeedInputRender = true; +} + +// ------------------------------------------------------------------------------------------------- +// FUNCTION Interface::handle_input() -> void { @@ -596,12 +657,12 @@ return; } - if (g_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) + if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION) { if (ch == 'y' or ch == 'Y') { RCONSession::get_session()->disconnect(); - g_disconnectConfirmFunction(); + DisconnectConfirmFunction(); } else if (ch == 'n' or ch == 'N') set_input_state (INPUTSTATE_NORMAL); @@ -611,13 +672,13 @@ if (ch >= 0x20 and ch <= 0x7E) { - mutable_current_input().insert (g_cursor++, char (ch)); - g_needInputRender = true; + mutable_current_input().insert (CursorPosition++, char (ch)); + NeedInputRender = true; } else switch (ch) { case 'Q' - 'A' + 1: // ^Q - switch (g_inputState) + switch (CurrentInputState) { case INPUTSTATE_CONFIRM_DISCONNECTION: break; @@ -649,26 +710,21 @@ } break; - case '\e': - if (g_inputState == INPUTSTATE_PASSWORD) - set_input_state (INPUTSTATE_ADDRESS); - else if (g_inputState == INPUTSTATE_ADDRESS) - set_input_state (INPUTSTATE_NORMAL); - break; - case KEY_LEFT: - if (g_cursor > 0) + case 'B' - 'A' + 1: // readline ^B + if (CursorPosition > 0) { - g_cursor--; - g_needInputRender = true; + CursorPosition--; + NeedInputRender = true; } break; case KEY_RIGHT: - if (g_cursor < current_input().length()) + case 'F' - 'A' + 1: // readline ^F + if (CursorPosition < current_input().length()) { - g_cursor++; - g_needInputRender = true; + CursorPosition++; + NeedInputRender = true; } break; @@ -678,63 +734,92 @@ break; case KEY_HOME: - if (g_cursor != 0) + case 'A' - 'A' + 1: // readline ^A + if (CursorPosition != 0) { - g_cursor = 0; - g_needInputRender = true; + CursorPosition = 0; + NeedInputRender = true; } break; case KEY_END: - if (g_cursor != current_input().length()) + case 'E' - 'A' + 1: // readline ^E + if (CursorPosition != current_input().length()) { - g_cursor = current_input().length(); - g_needInputRender = true; + CursorPosition = current_input().length(); + NeedInputRender = true; } break; case KEY_BACKSPACE: - if (g_cursor > 0) + if (CursorPosition > 0) { - mutable_current_input().remove_at (--g_cursor); - g_needInputRender = true; + mutable_current_input().remove_at (--CursorPosition); + NeedInputRender = true; } break; case KEY_DC: - if (g_cursor < current_input().length()) + case 'D' - 'A' + 1: // readline ^D + if (CursorPosition < current_input().length()) { - mutable_current_input().remove_at (g_cursor); - g_needInputRender = true; + mutable_current_input().remove_at (CursorPosition); + NeedInputRender = true; } break; case KEY_PPAGE: - g_outputScroll += min (g_pageSize, LINES / 2); - g_needOutputRender = true; + OutputScroll += min (g_pageSize, LINES / 2); + NeedOutputRender = true; break; case KEY_NPAGE: - g_outputScroll -= min (g_pageSize, LINES / 2); - g_needOutputRender = true; + OutputScroll -= min (g_pageSize, LINES / 2); + NeedOutputRender = true; + break; + + case 'U' - 'A' + 1: // readline ^U - delete from start to cursor + if (CursorPosition > 0) + { + yank (0, CursorPosition); + CursorPosition = 0; + } + break; + + case 'K' - 'A' + 1: // readline ^K - delete from cursor to end + yank (CursorPosition, mutable_current_input().length()); + break; + + case 'W' - 'A' + 1: // readline ^W - delete from previous word bounary to current + yank (interface_find_previous_word(), CursorPosition); + break; + + case 'Y' - 'A' + 1: // readline ^Y - paste previously deleted text + if (not PasteBuffer.is_empty()) + { + mutable_current_input().insert (CursorPosition, PasteBuffer); + CursorPosition += PasteBuffer.length(); + NeedInputRender = true; + } break; case '\t': { int space = current_input().find (" "); - if (g_inputState == INPUTSTATE_NORMAL - and g_cursor > 0 - and (space == -1 or space >= g_cursor)) + if (CurrentInputState == INPUTSTATE_NORMAL + and InputCursor > 0 + and (space == -1 or space >= InputCursor)) { - RCONSession::get_session()->request_tab_complete (current_input().mid (0, g_cursor)); + String start = current_input().mid (0, InputCursor); + RCONSession::get_session()->request_tab_complete (start); } } break; case '\n': case KEY_ENTER: - switch (g_inputState) + switch (CurrentInputState) { case INPUTSTATE_CONFIRM_DISCONNECTION: break; // handled above @@ -742,26 +827,27 @@ case INPUTSTATE_ADDRESS: try { - g_address = IPAddress::from_string (current_input()); + CurrentAddress = IPAddress::from_string (current_input()); } catch (std::exception& e) { - print (e.what()); + print ("%1\n", e.what()); return; } - if (g_address.port == 0) - g_address.port = 10666; + if (CurrentAddress.port == 0) + CurrentAddress.port = 10666; set_input_state (INPUTSTATE_PASSWORD); break; case INPUTSTATE_PASSWORD: - if (g_inputState == INPUTSTATE_PASSWORD and not current_input().is_empty()) + if (CurrentInputState == INPUTSTATE_PASSWORD and not current_input().is_empty()) { - RCONSession* session = RCONSession::new_session(); + RCONSession* session = RCONSession::get_session(); + session->disconnect(); session->set_password (current_input()); - session->connect (g_address); + session->connect (CurrentAddress); set_input_state (INPUTSTATE_NORMAL); } break; @@ -769,17 +855,56 @@ case INPUTSTATE_NORMAL: if (RCONSession::get_session()->send_command (current_input())) { - g_input.insert (0, ""); - g_needInputRender = true; + InputHistory.insert (0, ""); + NeedInputRender = true; } break; } break; case 'N' - 'A' + 1: // ^N - if (g_inputState == INPUTSTATE_NORMAL) + if (CurrentInputState == INPUTSTATE_NORMAL) safe_disconnect ([]() {set_input_state (INPUTSTATE_ADDRESS);}); break; + + case '\e': // Escape + // We may have an alt key coming + ch = ::getch(); + + if (ch != ERR) + { + switch (ch) + { + case 'b': + case 'B': + // readline alt-b - move one word to the left + CursorPosition = interface_find_previous_word(); + NeedInputRender = true; + break; + + case 'f': + case 'F': + // readline alt-f - move one word to the right + CursorPosition = interface_find_next_word(); + NeedInputRender = true; + break; + + case 'd': + case 'D': + // readline alt-d - delete from here till next word boundary + yank (CursorPosition, interface_find_next_word()); + break; + } + } + else + { + // No alt-key, handle pure escape + if (CurrentInputState == INPUTSTATE_PASSWORD) + set_input_state (INPUTSTATE_ADDRESS); + else if (CurrentInputState == INPUTSTATE_ADDRESS) + set_input_state (INPUTSTATE_NORMAL); + } + break; } render(); @@ -790,15 +915,16 @@ FUNCTION Interface::render() -> void { - if (g_needStatusBarRender) interface_render_statusbar(); - if (g_needInputRender) interface_render_input(); - if (g_needOutputRender) interface_render_output(); + if (NeedStatusBarRender) interface_render_statusbar(); + if (NeedInputRender) interface_render_input(); + if (NeedOutputRender) interface_render_output(); + if (NeedNicklistRender) interface_render_nicklist(); - if (g_needRefresh) + if (NeedRefresh) { interface_position_cursor(); refresh(); - g_needRefresh = false; + NeedRefresh = false; } } @@ -814,15 +940,26 @@ { if (ch == '\n') { - g_output[g_output.size() - 1].finalize(); - g_output << RendererLine(); + OutputLines.last().finalize(); + OutputLines << ColoredLine(); continue; } - g_output[g_output.size() - 1].add_char (ch); + if (OutputLines.last().length() == 0) + { + time_t now; + time (&now); + char timestamp[32]; + strftime (timestamp, sizeof timestamp, "[%H:%M:%S] ", localtime (&now)); + + for (char* cp = timestamp; *cp != '\0'; ++cp) + OutputLines.last().add_char (*cp); + } + + OutputLines.last().add_char (ch); } - g_needOutputRender = true; + NeedOutputRender = true; } // ------------------------------------------------------------------------------------------------- @@ -832,114 +969,30 @@ { try { - g_address = IPAddress::from_string (address); + CurrentAddress = IPAddress::from_string (address); } catch (std::exception& e) { - print (e.what()); + print ("%1\n", e.what()); return; } - if (g_address.port == 0) - g_address.port = 10666; - - RCONSession* session = RCONSession::new_session(); - session->set_password (password); - session->connect (g_address); -} + if (CurrentAddress.port == 0) + CurrentAddress.port = 10666; -// ------------------------------------------------------------------------------------------------- -// -METHOD -RendererLine::finalize() -> void -{ - if (m_activeColor != DEFAULT) - this->set_color (m_activeColor, false); - - if (m_boldActive) - m_data << RLINE_OFF_BOLD; - - m_final = true; + RCONSession* session = RCONSession::get_session(); + session->disconnect(); + session->set_password (password); + session->connect (CurrentAddress); } // ------------------------------------------------------------------------------------------------- // -METHOD -RendererLine::add_char (char ch) -> void +FUNCTION +Interface::set_player_names (const StringList& names) -> void { - if (m_final) - return; // Don't touch finalized lines. - - if (ch == '\x1C' and m_colorCodeStage == 0) - { - m_colorCodeStage = 1; - return; - } - - if (m_colorCodeStage == 1) - { - if (m_activeColor != DEFAULT) - this->set_color (m_activeColor, false); - - if (m_boldActive) - m_data << RLINE_OFF_BOLD; - - if (ch >= 'a' and ch <= 'v' and ch != 'l') - { - auto colorInfo = g_colorCodes[ch - 'a']; - m_activeColor = colorInfo.color; - m_boldActive = colorInfo.bold; - assert (m_activeColor < 8); - this->set_color (m_activeColor, true); - - if (m_boldActive) - m_data << RLINE_ON_BOLD; - } - - m_colorCodeStage = 0; - return; - } - - if (isprint (ch)) - { - m_string += ch; - m_data << int (ch); - ++m_length; - } -} - -// ------------------------------------------------------------------------------------------------- -// -METHOD -RendererLine::set_color (Color a, bool on) -> void -{ - switch (a) - { - case BLACK: m_data << (on ? RLINE_ON_BLACK : RLINE_OFF_BLACK); break; - case RED: m_data << (on ? RLINE_ON_RED : RLINE_OFF_RED); break; - case GREEN: m_data << (on ? RLINE_ON_GREEN : RLINE_OFF_GREEN); break; - case YELLOW: m_data << (on ? RLINE_ON_YELLOW : RLINE_OFF_YELLOW); break; - case BLUE: m_data << (on ? RLINE_ON_BLUE : RLINE_OFF_BLUE); break; - case MAGENTA: m_data << (on ? RLINE_ON_MAGENTA : RLINE_OFF_MAGENTA); break; - case CYAN: m_data << (on ? RLINE_ON_CYAN : RLINE_OFF_CYAN); break; - case WHITE: m_data << (on ? RLINE_ON_WHITE : RLINE_OFF_WHITE); break; - case NUM_COLORS: - case DEFAULT: assert (false); break; - } -} - -// ------------------------------------------------------------------------------------------------- -// How many rows does this line take up? -// -METHOD -RendererLine::rows (int cols) const -> int -{ - int rows = length() / cols; - - if (length() % cols != 0) - rows++; - - return max (rows, 1); + PlayerNames = names; + NeedNicklistRender = true; } // ------------------------------------------------------------------------------------------------- @@ -955,7 +1008,7 @@ complete += ' '; input.replace (0, part.length(), complete); - g_cursor = complete.length(); - g_needInputRender = true; + InputCursor = complete.length(); + NeedInputRender = true; } } diff -r 9ab869656b9e -r 4f7c2c944637 sources/interface.h --- a/sources/interface.h Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/interface.h Fri May 15 18:36:22 2015 +0300 @@ -40,6 +40,7 @@ FUNCTION set_title (const String& message) -> void; FUNCTION update_statusbar() -> void; FUNCTION connect (String address, String password) -> void; + FUNCTION set_player_names (const StringList& names) -> void; FUNCTION need_refresh() -> void; FUNCTION tab_complete (const String& part, String complete) -> void; }; diff -r 9ab869656b9e -r 4f7c2c944637 sources/list.h --- a/sources/list.h Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/list.h Fri May 15 18:36:22 2015 +0300 @@ -49,79 +49,309 @@ using ConstReverseIterator = typename C::const_reverse_iterator; using Self = Container; - Container(); - Container (int numvalues); - Container (const C& a); - Container (std::initializer_list&& a); + Container(){} + + Container (int numvalues) : + m_container (numvalues) {} + + Container (const C& other) : + m_container (other) {} + + Container (std::initializer_list&& a) : + m_container (a) {} + + T& append (const T& value) + { + m_container.push_back (value); + return m_container[m_container.size() - 1]; + } + + Iterator begin() + { + return m_container.begin(); + } + + ConstIterator begin() const + { + return m_container.cbegin(); + } + + void clear() + { + m_container.clear(); + } + + bool contains (const T& a) const + { + return std::find (m_container.cbegin(), m_container.cend(), a) != m_container.end(); + } + + ConstReverseIterator crbegin() const + { + return m_container.crbegin(); + } + + ConstReverseIterator crend() const + { + return m_container.crbegin(); + } + + const C& container() const + { + return m_container; + } + + Iterator end() + { + return m_container.end(); + } + + ConstIterator end() const + { + return m_container.cend(); + } + + Iterator find (const T& needle) + { + auto it = std::find (m_container.begin(), m_container.end(), needle); + + if (it == m_container.end()) + return end(); + + return it; + } + + ConstIterator find (const T& needle) const + { + auto it = std::find (m_container.cbegin(), m_container.cend(), needle); + + if (it == m_container.cend()) + return end(); + + return it; + } + + Iterator find (Function func) + { + for (Iterator it = begin(); it != end(); ++it) + { + if (func (*it)) + return it; + } + + return end(); + } + + ConstIterator find (Function func) const + { + for (ConstIterator it = begin(); it != end(); ++it) + { + if (func (*it)) + return it; + } + + return end(); + } + + T& first() + { + return *begin(); + } + + const T& first() const + { + return *begin(); + } + + void insert (int pos, const T& value) + { + m_container.insert (m_container.begin() + pos, value); + } + + bool is_empty() const + { + return size() == 0; + } + + T& last() + { + return *(end() - 1); + } - auto append (const T& value) -> T&; - auto begin() -> Iterator; - auto begin() const -> ConstIterator; - auto clear() -> void; - auto contains (const T& a) const -> bool; - auto crbegin() const -> ConstReverseIterator; - auto crend() const -> ConstReverseIterator; - auto container() const -> const C&; - auto end() -> Iterator; - auto end() const -> ConstIterator; - auto find (const T& needle) -> Iterator; - auto find (const T& needle) const -> ConstIterator; - auto find (Function func) -> Iterator; - auto find (Function func) const -> ConstIterator; - auto first() const -> const T&; - auto insert (int pos, const T& value) -> void; - auto is_empty() const -> bool; - auto last() const -> const T&; - auto merge (const Self& other) -> void; - auto pop (T& val) -> bool; - auto prepend (const T& value) -> T&; - auto rbegin() -> ReverseIterator; - auto remove_at (int pos) -> void; - auto remove_duplicates() -> void; - auto remove_one (const T& it) -> void; - auto rend() -> ReverseIterator; - auto resize (int size) -> void; - auto reverse() const -> Self; - auto size() const -> int; - auto sort() -> void; - auto splice (int a, int b) const -> Self; - auto splice (const Range& a) const -> Self; + const T& last() const + { + return *(end() - 1); + } + + void merge (const Self& other) + { + int oldsize = size(); + resize (size() + other.size()); + std::copy (other.begin(), other.end(), begin() + oldsize); + } + + bool pop (T& val) + { + if (is_empty()) + return false; + + val = m_container[size() - 1]; + m_container.erase (m_container.end() - 1); + return true; + } + + T& prepend (const T& value) + { + m_container.push_front (value); + return m_container[0]; + } + + ReverseIterator rbegin() + { + return m_container.rbegin(); + } + + void remove_at (int pos) + { + assert (pos < size()); + m_container.erase (m_container.begin() + pos); + } + + void remove_duplicates() + { + sort(); + resize (std::distance (begin(), std::unique (begin(), end()))); + } + + void remove_one (const T& valueToRemove) + { + auto it = std::find (m_container.begin(), m_container.end(), valueToRemove); + + if (it != m_container.end()) + m_container.erase (it); + } + + ReverseIterator rend() + { + return m_container.rend(); + } + + void resize (int size) + { + m_container.resize (size); + } - auto operator<< (const T& value) -> Self&; - auto operator<< (const Self& vals) -> Self&; - auto operator[] (int n) -> T&; - auto operator[] (int n) const -> const T&; - auto operator[] (Range const& n) const -> Self; - auto operator+ (const Self& other) const -> Self; + Self reverse() const + { + Self rev; + std::copy (rbegin(), rend(), rev.begin()); + return rev; + } + + int size() const + { + return m_container.size(); + } + + void sort() + { + std::sort (begin(), end()); + } + + Self splice (int a, int b) const + { + if (a < 0 or b >= size() or b < a) + return Self(); + + Self result; + + for (int i = a; i <= b; ++i) + result << operator[] (i); + + return result; + } + + Self splice (const Range& a) const + { + return splice (a.min(), a.max()); + } + + Self& operator<< (const T& value) + { + append (value); + return *this; + } + + Self& operator<< (const Self& vals) + { + merge (vals); + return *this; + } + + T& operator[] (int n) + { + assert (n < size()); + return m_container[n]; + } + + const T& operator[] (int n) const + { + assert (n < size()); + return m_container[n]; + } + + Self operator[] (Range const& n) const + { + return splice (n); + } + + Self operator+ (const Self& other) const + { + Self out (*this); + out.merge (other); + return out; + } protected: C m_container; }; +// ------------------------------------------------------------------------------------------------- +// template -Container& operator>> (const T& value, Container& haystack); +Container& operator>> (const T& value, Container& haystack) +{ + haystack.prepend (value); + return haystack; +} + +// ------------------------------------------------------------------------------------------------- +// template using List = Container>; +// ------------------------------------------------------------------------------------------------- +// + template class Vector : public Container> { public: using Super = Container>; + using typename Super::Container; - Vector() {} - Vector (int numvalues) : Super (numvalues) {} - Vector (const Vector& a) : Super (a) {} - Vector (std::initializer_list&& a) : Super (a) {} - Vector (T* data, size_t length) : Super (std::vector (data, data + length)) {} + Vector(){} - auto data() -> T* + Vector (T* data, size_t length) : + Super (std::vector (data, data + length)) {} + + T* data() { return Super::m_container.data(); } - auto data() const -> const T* + const T* data() const { return Super::m_container.data(); } @@ -131,395 +361,3 @@ return data(); } }; - -// -// ------------------------------------------------------------------------------------------------- -// -// IMPLEMENTATIONS -// - -template -Container::Container() {} - -// ------------------------------------------------------------------------------------------------- -// -template -Container::Container (const C& other) : - m_container (other) {} - -// ------------------------------------------------------------------------------------------------- -// -template -Container::Container (std::initializer_list && a) : - m_container (a) {} - -// ------------------------------------------------------------------------------------------------- -// -template -Container::Container (int numvalues) : - m_container (numvalues) {} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::begin() -> Iterator -{ - return m_container.begin(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::begin() const -> ConstIterator -{ - return m_container.cbegin(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::end() -> Iterator -{ - return m_container.end(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::end() const -> ConstIterator -{ - return m_container.cend(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::rbegin() -> ReverseIterator -{ - return m_container.rbegin(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::crbegin() const -> ConstReverseIterator -{ - return m_container.crbegin(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::rend() -> ReverseIterator -{ - return m_container.rend(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::crend() const -> ConstReverseIterator -{ - return m_container.crend(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::remove_at (int pos) -> void -{ - assert (pos < size()); - m_container.erase (m_container.begin() + pos); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::prepend (const T& value) -> T& -{ - m_container.push_front (value); - return m_container[0]; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::append (const T& value) -> T& -{ - m_container.push_back (value); - return m_container[m_container.size() - 1]; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::merge (const Self& other) -> void -{ - int oldsize = size(); - resize (size() + other.size()); - std::copy (other.begin(), other.end(), begin() + oldsize); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::pop (T& val) -> bool -{ - if (is_empty()) - return false; - - val = m_container[size() - 1]; - m_container.erase (m_container.end() - 1); - return true; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::operator<< (const T& value) -> Self& -{ - append (value); - return *this; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::operator<< (const Self& vals) -> Self& -{ - merge (vals); - return *this; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::reverse() const -> Self -{ - Self rev; - std::copy (rbegin(), rend(), rev.begin()); - return rev; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::clear() -> void -{ - m_container.clear(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::insert (int pos, const T& value) -> void -{ - m_container.insert (m_container.begin() + pos, value); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::remove_duplicates() -> void -{ - sort(); - resize (std::distance (begin(), std::unique (begin(), end()))); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::size() const -> int -{ - return m_container.size(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::operator[] (int n) -> T& -{ - assert (n < size()); - return m_container[n]; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::operator[] (int n) const -> const T& -{ - assert (n < size()); - return m_container[n]; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::operator[] (const Range& n) const -> Self -{ - return splice (n); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::resize (int size) -> void -{ - m_container.resize (size); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::sort() -> void -{ - std::sort (begin(), end()); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::find (const T& needle) -> Iterator -{ - auto it = std::find (m_container.begin(), m_container.end(), needle); - - if (it == m_container.end()) - return end(); - - return it; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::find (const T& needle) const -> ConstIterator -{ - auto it = std::find (m_container.cbegin(), m_container.cend(), needle); - - if (it == m_container.cend()) - return end(); - - return it; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::find (Function func) -> Iterator -{ - for (Iterator it = begin(); it != end(); ++it) - { - if (func (*it)) - return it; - } - - return end(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::find (Function func) const -> ConstIterator -{ - for (ConstIterator it = begin(); it != end(); ++it) - { - if (func (*it)) - return it; - } - - return end(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::remove_one (const T& a) -> void -{ - auto it = std::find (m_container.begin(), m_container.end(), a); - - if (it != m_container.end()) - m_container.erase (it); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::is_empty() const -> bool -{ - return size() == 0; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::splice (int a, int b) const -> Self -{ - if (a < 0 or b >= size() or b < a) - return Self(); - - Self result; - - for (int i = a; i <= b; ++i) - result << operator[] (i); - - return result; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::splice (const Range& a) const -> Self -{ - return splice (a.min(), a.max()); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::container() const -> const C& -{ - return m_container; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::first() const -> const T& -{ - return *m_container.cbegin(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::last() const -> const T& -{ - return *(m_container.cend() - 1); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::contains (const T& a) const -> bool -{ - return std::find (m_container.cbegin(), m_container.cend(), a) != m_container.end(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto Container::operator+ (const Self& other) const -> Self -{ - Self out (*this); - out.merge (other); - return out; -} - -// ------------------------------------------------------------------------------------------------- -// -template -auto operator>> (const T& value, Container& haystack) -> Container& -{ - haystack.prepend (value); - return haystack; -} diff -r 9ab869656b9e -r 4f7c2c944637 sources/main.cpp --- a/sources/main.cpp Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/main.cpp Fri May 15 18:36:22 2015 +0300 @@ -35,8 +35,6 @@ #include "huffman/huffman.h" #include "interface.h" -static bool g_shouldExit = false; - // ------------------------------------------------------------------------------------------------- // FUNCTION @@ -51,7 +49,6 @@ } Interface::initialize(); - RCONSession::new_session(); if (argc == 3) Interface::connect (argv[1], argv[2]); @@ -60,9 +57,6 @@ { for (;;) { - if (g_shouldExit) - break; - fd_set fdset; int highest = 0; timeval timeout; @@ -70,11 +64,9 @@ timeout.tv_usec = 250000; // 0.25 seconds FD_ZERO (&fdset); FD_SET (0, &fdset); - RCONSession* session = RCONSession::get_session(); - if (session) { - int fd = session->socket()->file_descriptor(); + int fd = RCONSession::get_session()->socket()->file_descriptor(); highest = max (highest, fd); FD_SET (fd, &fdset); } @@ -85,24 +77,12 @@ // stdin is ready, what's incoming? Interface::handle_input(); - if (session) - session->tick(); - + RCONSession::get_session()->tick(); Interface::render(); } } catch (const Exitception&) {} - if (RCONSession::get_session()) - RCONSession::get_session()->disconnect(); - + RCONSession::get_session()->disconnect(); return EXIT_SUCCESS; } - -// ------------------------------------------------------------------------------------------------- -// -FUNCTION -request_exit() -> void -{ - g_shouldExit = true; -} diff -r 9ab869656b9e -r 4f7c2c944637 sources/mystring.cpp --- a/sources/mystring.cpp Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/mystring.cpp Fri May 15 18:36:22 2015 +0300 @@ -36,16 +36,14 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::compare (const String& other) const -> int +int String::compare (const String& other) const { return m_string.compare (other.std_string()); } // ------------------------------------------------------------------------------------------------- // -METHOD -String::trim (int n) -> void +void String::trim (int n) { if (n > 0) m_string = mid (0, length() - n).std_string(); @@ -55,8 +53,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::strip (const List& unwanted) -> String +String String::strip (const List& unwanted) { String copy (m_string); @@ -71,8 +68,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::to_uppercase() const -> String +String String::to_uppercase() const { String newstr (m_string); @@ -87,8 +83,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::to_lowercase() const -> String +String String::to_lowercase() const { String newstr (m_string); @@ -103,8 +98,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::split (char del) const -> StringList +StringList String::split (char del) const { String delimstr; delimstr += del; @@ -113,8 +107,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::split (const String& del) const -> StringList +StringList String::split (const String& del) const { StringList res; int a = 0; @@ -140,8 +133,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::replace (const char* a, const char* b) -> void +void String::replace (const char* a, const char* b) { long pos; @@ -151,8 +143,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::count (char needle) const -> int +int String::count (char needle) const { int needles = 0; @@ -165,8 +156,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::mid (long a, long b) const -> String +String String::mid (long a, long b) const { if (b == -1 or b > length()) b = length(); @@ -190,8 +180,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::word_position (int n) const -> int +int String::word_position (int n) const { int count = 0; @@ -208,8 +197,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::find (const char* c, int a) const -> int +int String::find (const char* c, int a) const { int pos = m_string.find (c, a); @@ -221,8 +209,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::find_last (const char* c, int a) const -> int +int String::find_last (const char* c, int a) const { if (a == -1 or a >= length()) a = length() - 1; @@ -236,8 +223,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::to_int (bool* ok, int base) const -> long +long String::to_int (bool* ok, int base) const { errno = 0; char* endptr; @@ -251,8 +237,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::to_float (bool* ok) const -> float +float String::to_float (bool* ok) const { errno = 0; char* endptr; @@ -266,8 +251,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::to_double (bool* ok) const -> double +double String::to_double (bool* ok) const { errno = 0; char* endptr; @@ -281,8 +265,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::operator+ (const String& data) const -> String +String String::operator+ (const String& data) const { String newString = *this; newString.append (data); @@ -291,8 +274,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::operator+ (const char* data) const -> String +String String::operator+ (const char* data) const { String newstr = *this; newstr.append (data); @@ -301,39 +283,16 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::is_numeric() const -> bool +bool String::is_numeric() const { - bool gotDot = false; - - for (const char & c : m_string) - { - // Allow leading hyphen for negatives - if (&c == &m_string[0] and c == '-') - continue; - - // Check for decimal point - if (!gotDot and c == '.') - { - gotDot = true; - continue; - } - - if (c >= '0' and c <= '9') - continue; // Digit - - // If the above cases didn't catch this character, it was - // illegal and this is therefore not a number. - return false; - } - - return true; + char* endptr; + strtol (chars(), &endptr, 10); + return not (endptr && *endptr); } // ------------------------------------------------------------------------------------------------- // -METHOD -String::ends_with (const String& other) -> bool +bool String::ends_with (const String& other) { if (length() < other.length()) return false; @@ -344,8 +303,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::starts_with (const String& other) -> bool +bool String::starts_with (const String& other) { if (length() < other.length()) return false; @@ -355,16 +313,18 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::sprintf (const char* fmtstr, ...) -> void +void String::sprintf (const char* fmtstr, ...) { - char* buf; + char* buf = nullptr; int bufsize = 256; va_list va; va_start (va, fmtstr); do + { + delete[] buf; buf = new char[bufsize]; + } while (vsnprintf (buf, bufsize, fmtstr, va) >= bufsize); va_end (va); @@ -374,8 +334,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -StringList::join (const String& delim) -> String +String StringList::join (const String& delim) { String result; @@ -392,8 +351,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::mask_against (const String& pattern) const -> bool +bool String::mask_against (const String& pattern) const { // Elevate to uppercase for case-insensitive matching String pattern_upper = pattern.to_uppercase(); @@ -441,8 +399,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::from_number (int a) -> String +String String::from_number (short int a) { char buf[32]; ::sprintf (buf, "%d", a); @@ -451,8 +408,16 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::from_number (long a) -> String +String String::from_number (int a) +{ + char buf[32]; + ::sprintf (buf, "%d", a); + return String (buf); +} + +// ------------------------------------------------------------------------------------------------- +// +String String::from_number (long int a) { char buf[32]; ::sprintf (buf, "%ld", a); @@ -461,8 +426,25 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::from_number (unsigned long a) -> String +String String::from_number (unsigned short int a) +{ + char buf[32]; + ::sprintf (buf, "%u", a); + return String (buf); +} + +// ------------------------------------------------------------------------------------------------- +// +String String::from_number (unsigned int a) +{ + char buf[32]; + ::sprintf (buf, "%u", a); + return String (buf); +} + +// ------------------------------------------------------------------------------------------------- +// +String String::from_number (unsigned long int a) { char buf[32]; ::sprintf (buf, "%lu", a); @@ -471,8 +453,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::from_number (double a) -> String +String String::from_number (double a) { char buf[64]; ::sprintf (buf, "%f", a); @@ -481,8 +462,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::md5() const -> String +String String::md5() const { char checksum[33]; CalculateMD5 (reinterpret_cast (chars()), length(), checksum); @@ -492,8 +472,7 @@ // ------------------------------------------------------------------------------------------------- // -METHOD -String::normalize (int (*filter)(int)) -> void +void String::normalize (int (*filter)(int)) { int a = 0; int b = length() - 1; diff -r 9ab869656b9e -r 4f7c2c944637 sources/mystring.h --- a/sources/mystring.h Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/mystring.h Fri May 15 18:36:22 2015 +0300 @@ -39,7 +39,7 @@ class StringList; // ------------------------------------------------------------------------------------------------- - +// class String { public: @@ -57,397 +57,114 @@ String (const Vector& data) : m_string (data.data(), data.size()) {} - inline METHOD append (const char* data) -> void; - inline METHOD append (char data) -> void; - inline METHOD append (const String& data) -> void; - inline METHOD begin() -> std::string::iterator; - inline METHOD begin() const -> std::string::const_iterator; - inline METHOD clear() -> void; - METHOD compare (const String& other) const -> int; - METHOD count (char needle) const -> int; - inline METHOD chars() const -> const char*; - inline METHOD end() -> std::string::iterator; - inline METHOD end() const -> std::string::const_iterator; - METHOD ends_with (const String& other) -> bool; - METHOD find (const char* c, int a = 0) const -> int; - METHOD to_lowercase() const -> String; - inline METHOD index_difference (int a, int b) -> int; - inline METHOD insert (int pos, char c) -> void; - inline METHOD is_empty() const -> bool; - METHOD is_numeric() const -> bool; - METHOD find_last (const char* c, int a = -1) const -> int; - inline METHOD length() const -> int; - METHOD mask_against (const String& pattern) const -> bool; - METHOD md5() const -> String; - METHOD mid (long a, long b = -1) const -> String; - inline METHOD modify_index (int& a) -> void; - METHOD normalize (int (*filter)(int) = &std::isspace) -> void; - inline METHOD prepend (String a) -> void; - inline METHOD remove (int pos, int len) -> void; - inline METHOD remove_at (int pos) -> void; - inline METHOD remove_from_end (int len) -> void; - inline METHOD remove_from_start (int len) -> void; - METHOD replace (const char* a, const char* b) -> void; - inline METHOD replace (int pos, int n, const String& a) -> void; - inline METHOD shrink_to_fit() -> void; - METHOD split (const String& del) const -> StringList; - METHOD split (char del) const -> StringList; - METHOD sprintf (const char* fmtstr, ...) -> void; - METHOD starts_with (const String& other) -> bool; - inline METHOD std_string() const -> const std::string&; - inline METHOD strip (char unwanted) -> String; - METHOD strip (const List& unwanted) -> String; - METHOD to_double (bool* ok = nullptr) const -> double; - METHOD to_float (bool* ok = nullptr) const -> float; - METHOD to_int (bool* ok = nullptr, int base = 10) const -> long; - METHOD trim (int n) -> void; - METHOD to_uppercase() const -> String; - METHOD word_position (int n) const -> int; + using Iterator = std::string::iterator; + using ConstIterator = std::string::const_iterator; + + ConstIterator begin() const { return m_string.cbegin(); } + int compare (const String &other) const; + int count (char needle) const; + const char* chars() const { return m_string.c_str(); } + ConstIterator end() const { return m_string.end(); } + int find (const char*c, int a = 0) const; + bool is_empty() const { return m_string[0] == '\0'; } + bool is_numeric() const; + int find_last (const char*c, int a) const; + int length() const { return m_string.length(); } + bool mask_against (const String &pattern) const; + String md5() const; + String mid (long a, long b) const; + StringList split (const String &del) const; + StringList split (char del) const; + const std::string& std_string() const { return m_string; } + double to_double (bool* ok = nullptr) const; + float to_float (bool* ok = nullptr) const; + long to_int (bool* ok = nullptr, int base = 10) const; + String to_lowercase() const; + String to_uppercase() const; + int word_position (int n) const; - static METHOD from_number (int a) -> String; - static METHOD from_number (long a) -> String; - static METHOD from_number (unsigned long a) -> String; - static METHOD from_number (double a) -> String; + void append (const char* data) { m_string.append (data); } + void append (char data) { m_string.push_back (data); } + void append (const String& data) { m_string.append (data.chars()); } + Iterator begin() { return m_string.begin(); } + void clear() { m_string.clear(); } + Iterator end() { return m_string.end(); } + bool ends_with (const String &other); + int index_difference (int a, int b) { modify_index (a); modify_index (b); return b - a; } + void insert (int pos, char c) { m_string.insert (m_string.begin() + pos, c); } + void insert (int pos, const char*c) { m_string.insert (pos, c); } + void modify_index (int &a) { if (a < 0) { a = length() - a; } } + void normalize (int (*filter)(int) = &std::isspace); + void prepend (String a) { m_string = (a + m_string).std_string(); } + void remove (int pos, int len) { m_string.replace (pos, len, ""); } + void remove_at (int pos) { m_string.erase (m_string.begin() + pos); } + void remove_from_end (int len) { remove (length() - len, len); } + void remove_from_start (int len) { remove (0, len); } + void replace (const char* a, const char* b); + void replace (int pos, int n, const String &a) { m_string.replace (pos, n, a.chars()); } + void shrink_to_fit() { m_string.shrink_to_fit(); } + void sprintf (const char* fmtstr, ...); + bool starts_with (const String &other); + String strip (char unwanted) { return strip ({unwanted}); } + String strip (const List &unwanted); + void trim (int n); - METHOD operator+ (const String& data) const -> String; - METHOD operator+ (const char* data) const -> String; - inline METHOD operator+ (int num) const -> String; - inline METHOD operator+= (const String& data) -> String&; - inline METHOD operator+= (const char* data) -> String&; - inline METHOD operator+= (int num) -> String&; - inline METHOD operator+= (char data) -> String&; - inline METHOD operator== (const String& other) const -> bool; - inline METHOD operator== (const char* other) const -> bool; - inline METHOD operator!= (const String& other) const -> bool; - inline METHOD operator!= (const char* other) const -> bool; - inline METHOD operator> (const String& other) const -> bool; - inline METHOD operator< (const String& other) const -> bool; - inline operator const char*() const; - inline operator const std::string&() const; + static String from_number (short int a); + static String from_number (int a); + static String from_number (long int a); + static String from_number (unsigned short int a); + static String from_number (unsigned int a); + static String from_number (unsigned long int a); + static String from_number (double a); + + String operator+ (const String& data) const; + String operator+ (const char* data) const; + String operator+ (int num) const { return *this + String::from_number (num); } + String& operator+= (const String& data) { append (data); return *this; } + String& operator+= (const char* data) { append (data); return *this; } + String& operator+= (int num) { return operator+= (String::from_number (num)); } + String& operator+= (char data) { append (data); return *this; } + bool operator== (const String& other) const { return std_string() == other.std_string(); } + bool operator== (const char* other) const { return m_string == other; } + bool operator!= (const String& other) const { return std_string() != other.std_string(); } + bool operator!= (const char* other) const { return m_string != other; } + bool operator> (const String& other) const { return std_string() > other.std_string(); } + bool operator< (const String& other) const { return std_string() < other.std_string(); } + bool operator>= (const String& other) const { return std_string() >= other.std_string(); } + bool operator<= (const String& other) const { return std_string() <= other.std_string(); } + operator const char*() const { return chars(); } + operator const std::string&() const { return std_string(); } private: std::string m_string; }; // ------------------------------------------------------------------------------------------------- - +// class StringList : public List { public: - template - StringList (Args... args) : - List (args...) {} + using Super = List; + using Super::Super; + + StringList() {} - METHOD join (const String& delim) -> String; + StringList (const Super& other) : + Super (other) {} + + String join (const String& delim); }; // ------------------------------------------------------------------------------------------------- - -inline FUNCTION operator== (const char* a, const String& b) -> bool; -inline FUNCTION operator+ (const char* a, const String& b) -> String; - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::is_empty() const -> bool -{ - return m_string[0] == '\0'; -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::append (const char* data) -> void -{ - m_string.append (data); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::append (char data) -> void -{ - m_string.push_back (data); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::append (const String& data) -> void -{ - m_string.append (data.chars()); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::begin() -> std::string::iterator -{ - return m_string.begin(); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::begin() const -> std::string::const_iterator -{ - return m_string.cbegin(); -} - -// ------------------------------------------------------------------------------------------------- - -inline const char* String::chars() const -{ - return m_string.c_str(); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::end() -> std::string::iterator -{ - return m_string.end(); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::end() const -> std::string::const_iterator -{ - return m_string.end(); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::clear() -> void -{ - m_string.clear(); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::remove_at (int pos) -> void -{ - m_string.erase (m_string.begin() + pos); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::insert (int pos, char c) -> void -{ - m_string.insert (m_string.begin() + pos, c); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::length() const -> int -{ - return m_string.length(); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::remove (int pos, int len) -> void -{ - m_string.replace (pos, len, ""); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::remove_from_start (int len) -> void -{ - remove (0, len); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::remove_from_end (int len) -> void -{ - remove (length() - len, len); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::replace (int pos, int n, const String& a) -> void -{ - m_string.replace (pos, n, a.chars()); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::shrink_to_fit() -> void -{ - m_string.shrink_to_fit(); -} - -// ------------------------------------------------------------------------------------------------- - -inline const std::string& String::std_string() const -{ - return m_string; -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::strip (char unwanted) -> String -{ - return strip ({unwanted}); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::operator+ (int num) const -> String -{ - return *this + String::from_number (num); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::operator+= (const String& data) -> String& -{ - append (data); - return *this; -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::operator+= (const char* data) -> String& -{ - append (data); - return *this; -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::operator+= (int num) -> String& -{ - return operator+= (String::from_number (num)); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::prepend (String a) -> void -{ - m_string = (a + m_string).std_string(); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::operator+= (char data) -> String& -{ - append (data); - return *this; -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::operator== (const String& other) const -> bool -{ - return std_string() == other.std_string(); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::operator== (const char* other) const -> bool -{ - return operator== (String (other)); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::operator!= (const String& other) const -> bool -{ - return std_string() != other.std_string(); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::operator!= (const char* other) const -> bool -{ - return operator!= (String (other)); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::operator> (const String& other) const -> bool -{ - return std_string() > other.std_string(); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::operator< (const String& other) const -> bool -{ - return std_string() < other.std_string(); -} - -// ------------------------------------------------------------------------------------------------- - -inline String::operator const char*() const -{ - return chars(); -} - -// ------------------------------------------------------------------------------------------------- - -inline String::operator const std::string&() const -{ - return std_string(); -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::modify_index (int& a) -> void -{ - if (a < 0) - a = length() - a; -} - -// ------------------------------------------------------------------------------------------------- - -inline METHOD -String::index_difference (int a, int b) -> int -{ - modify_index (a); - modify_index (b); - return b - a; -} - -// ------------------------------------------------------------------------------------------------- - -inline FUNCTION -operator== (const char* a, const String& b) -> bool +// +inline bool operator== (const char* a, const String& b) { return b == a; } // ------------------------------------------------------------------------------------------------- - -inline FUNCTION -operator+ (const char* a, const String& b) -> String +// +inline String operator+ (const char* a, const String& b) { return String (a) + b; } diff -r 9ab869656b9e -r 4f7c2c944637 sources/network/bytestream.cpp --- a/sources/network/bytestream.cpp Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/network/bytestream.cpp Fri May 15 18:36:22 2015 +0300 @@ -68,7 +68,7 @@ // Bytestream::~Bytestream() { - delete m_data; + delete[] m_data; } // ------------------------------------------------------------------------------------------------- @@ -178,8 +178,10 @@ METHOD Bytestream::read_float() -> float { - int value = read_long(); - return reinterpret_cast (value); + float value; + int intvalue = read_long(); + memcpy (&value, &intvalue, sizeof intvalue); + return value; } // ------------------------------------------------------------------------------------------------- @@ -292,7 +294,9 @@ Bytestream::write_float (float val) -> void { // I know this is probably dangerous but this is what Zandronum does so yeah - write_long (reinterpret_cast (val)); + int intvalue; + memcpy (&intvalue, &val, sizeof val); + write_long (intvalue); } // ------------------------------------------------------------------------------------------------- diff -r 9ab869656b9e -r 4f7c2c944637 sources/network/ipaddress.h --- a/sources/network/ipaddress.h Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/network/ipaddress.h Fri May 15 18:36:22 2015 +0300 @@ -38,7 +38,7 @@ struct IPAddress { - class StringParseError + class StringParseError : public std::exception { String m_message; diff -r 9ab869656b9e -r 4f7c2c944637 sources/network/rconsession.cpp --- a/sources/network/rconsession.cpp Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/network/rconsession.cpp Fri May 15 18:36:22 2015 +0300 @@ -1,8 +1,6 @@ #include "rconsession.h" #include "../interface.h" -RCONSession* g_rconSession = nullptr; - // ------------------------------------------------------------------------------------------------- // RCONSession::RCONSession() : @@ -10,42 +8,17 @@ m_lastPing (0), m_numAdmins (0) { - if (g_rconSession != NULL) + if (not m_socket.set_blocking (false)) { - g_rconSession->disconnect(); - delete g_rconSession; + print_to (stderr, "unable to set socket as non-blocking: %s\n", + m_socket.error_string().chars()); + exit (EXIT_FAILURE); } - - g_rconSession = this; } // ------------------------------------------------------------------------------------------------- // -STATIC METHOD -RCONSession::new_session() -> RCONSession* -{ - RCONSession* session = new RCONSession; - - if (not session->socket()->set_blocking (false)) - { - print ("unable to set socket as non-blocking: %s\n", - session->socket()->error_string().chars()); - delete session; - return nullptr; - } - - return session; -} - -// ------------------------------------------------------------------------------------------------- -// -RCONSession::~RCONSession() -{ - disconnect(); - - if (g_rconSession == this) - g_rconSession = nullptr; -} +RCONSession::~RCONSession() {} // ------------------------------------------------------------------------------------------------- // @@ -55,6 +28,7 @@ m_address = address; m_state = RCON_CONNECTING; Interface::update_statusbar(); + send_hello(); } // ------------------------------------------------------------------------------------------------- @@ -134,12 +108,12 @@ switch (ServerResponse (header)) { case SVRC_OLDPROTOCOL: - print ("Your RCON client is using outdated protocol.\n"); + print_error ("Your RCON client is using outdated protocol.\n"); m_state = RCON_DISCONNECTED; break; case SVRC_BANNED: - print ("You have been banned from the server.\n"); + print_error ("You have been banned from the server.\n"); m_state = RCON_DISCONNECTED; break; @@ -150,7 +124,7 @@ break; case SVRC_INVALIDPASSWORD: - print ("Password incorrect.\n"); + print_error ("Login failed.\n"); m_state = RCON_DISCONNECTED; break; @@ -223,20 +197,25 @@ } catch (std::exception& e) { - print ("error while reading packet: %1\n", e.what()); + print_warning ("Couldn't process packet: %1\n", e.what()); } } METHOD RCONSession::process_server_updates (Bytestream& packet) -> void { - switch (RCONUpdateType (packet.read_byte())) + int header = packet.read_byte(); + + switch (RCONUpdateType (header)) { case SVRCU_PLAYERDATA: { - Vector players; + StringList players; + for (int i = packet.read_byte(); i > 0; --i) - players << packet.read_string(); + players.append (packet.read_string()); + + Interface::set_player_names (players); } break; @@ -249,6 +228,10 @@ m_level = packet.read_string(); Interface::update_statusbar(); break; + + default: + print_warning ("Unknown server update type: %d\n", header); + break; } } @@ -309,10 +292,8 @@ STATIC METHOD RCONSession::get_session() -> RCONSession* { - if (g_rconSession == nullptr) - new_session(); - - return g_rconSession; + static RCONSession session; + return &session; } // ------------------------------------------------------------------------------------------------- diff -r 9ab869656b9e -r 4f7c2c944637 sources/network/rconsession.h --- a/sources/network/rconsession.h Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/network/rconsession.h Fri May 15 18:36:22 2015 +0300 @@ -112,7 +112,6 @@ METHOD is_active() const -> bool; METHOD request_tab_complete (const String& part) -> void; - static METHOD new_session() -> RCONSession*; static METHOD get_session() -> RCONSession*; private: diff -r 9ab869656b9e -r 4f7c2c944637 sources/network/udpsocket.cpp --- a/sources/network/udpsocket.cpp Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/network/udpsocket.cpp Fri May 15 18:36:22 2015 +0300 @@ -34,6 +34,7 @@ #include #include #include +#include #include "udpsocket.h" #include "../huffman/huffman.h" @@ -46,7 +47,10 @@ // ----------------------------------------------------------------------------- // -UDPSocket::~UDPSocket() {} +UDPSocket::~UDPSocket() +{ + close (m_socket); +} // ------------------------------------------------------------------------------------------------- // diff -r 9ab869656b9e -r 4f7c2c944637 sources/range.h --- a/sources/range.h Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/range.h Fri May 15 18:36:22 2015 +0300 @@ -48,161 +48,102 @@ { T value; T step; - inline METHOD operator*() -> T&; - inline METHOD operator== (const Iterator& other) const -> bool; - inline METHOD operator!= (const Iterator& other) const -> bool; - inline METHOD operator++() -> Iterator&; + + Iterator (T value, T step) : + value (value), + step (step) {} + + T& operator*() + { + return value; + } + + bool operator== (const Iterator& other) const + { + return value == other.value; + } + + bool operator!= (const Iterator& other) const + { + return value != other.value; + } + + Iterator& operator++() + { + value += step; return *this; + } }; - Range (const T& a, const T& b, const T& step = 1); - Range(); - - METHOD begin() const -> Iterator; - METHOD end() const -> Iterator; - METHOD min() const -> T; - METHOD max() const -> T; - METHOD check_bounds() -> void; - METHOD contains (const T& c) const -> bool; - METHOD contains_exclusively (const T& c) const -> bool; - METHOD overlaps (Range const& other) const -> bool; - METHOD operator== (Range const& other) const -> bool; - METHOD operator!= (Range const& other) const -> bool; -}; + Range (T a, T b, T step = 1) : + m_a (a), + m_b (b), + m_step (step) + { + check_bounds(); + } -// ------------------------------------------------------------------------------------------------- -// -template -Range::Range (const T& a, const T& b, const T& step) : - m_a (a), - m_b (b), - m_step (step) -{ - check_bounds(); -} - -// ------------------------------------------------------------------------------------------------- -// -template -Range::Range() : - m_a (T()), - m_b (T()) {} + Range() : + m_a (T()), + m_b (T()) {} -// ------------------------------------------------------------------------------------------------- -// -template inline METHOD -Range::Iterator::operator*() -> T& -{ - return value; -} - -// ------------------------------------------------------------------------------------------------- -// -template inline METHOD -Range::Iterator::operator== (const Iterator& other) const -> bool -{ - return value == other.value; -} + Iterator begin() const + { + Iterator it; + it.value = min(); + it.step = m_step; + return it; + } -// ------------------------------------------------------------------------------------------------- -// -template inline METHOD -Range::Iterator::operator!= (const Iterator& other) const -> bool -{ - return value != other.value; -} + Iterator end() const + { + Iterator it; + it.value = max() + 1; + it.step = m_step; + return it; + } -// ------------------------------------------------------------------------------------------------- -// -template inline METHOD -Range::Iterator::operator++() -> Iterator& -{ - value += step; - return *this; -} - -// ------------------------------------------------------------------------------------------------- -// -template METHOD -Range::check_bounds() -> void -{ - if (m_b < m_a) - std::swap (m_a, m_b); -} + T min() const + { + return m_a; + } -// ------------------------------------------------------------------------------------------------- -// -template METHOD -Range::contains (const T& c) const -> bool -{ - return (c >= m_a) and (c <= m_b); -} - -// ------------------------------------------------------------------------------------------------- -// -template METHOD -Range::contains_exclusively (const T& c) const -> bool -{ - return (c > m_a) and (c < m_b); -} + T max() const + { + return m_b; + } -// ------------------------------------------------------------------------------------------------- -// -template METHOD -Range::overlaps (Range const& other) const -> bool -{ - return contains (other.m_a) or contains (other.m_b); -} + void check_bounds() + { + if (m_b < m_a) + std::swap (m_a, m_b); + } -// ------------------------------------------------------------------------------------------------- -// -template METHOD -Range::operator== (Range const& other) const -> bool -{ - return m_a == other.m_a and m_b == other.m_b; -} + bool contains (T c) const + { + return c >= m_a + and c <= m_b; + } -// ------------------------------------------------------------------------------------------------- -// -template METHOD -Range::operator!= (Range const& other) const -> bool -{ - return not operator== (other); -} + bool contains_exclusively (T c) const + { + return c > m_a + and c < m_b; + } -// ------------------------------------------------------------------------------------------------- -// -template METHOD -Range::min() const -> T -{ - return m_a; -} + bool overlaps (Range const& other) const + { + return contains (other.m_a) + or contains (other.m_b); + } -// ------------------------------------------------------------------------------------------------- -// -template METHOD -Range::max() const -> T -{ - return m_b; -} + bool operator== (Range const& other) const + { + return m_a == other.m_a + and m_b == other.m_b; + } -// ------------------------------------------------------------------------------------------------- -// -template METHOD -Range::begin() const -> Iterator -{ - Iterator it; - it.value = min(); - it.step = m_step; - return it; -} - -// ------------------------------------------------------------------------------------------------- -// -template METHOD -Range::end() const -> Iterator -{ - Iterator it; - it.value = max() + 1; - it.step = m_step; - return it; -} + bool operator!= (Range const& other) const + { + return not operator== (other); + } +}; \ No newline at end of file diff -r 9ab869656b9e -r 4f7c2c944637 sources/version.cpp --- a/sources/version.cpp Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/version.cpp Fri May 15 18:36:22 2015 +0300 @@ -40,9 +40,11 @@ // ------------------------------------------------------------------------------------------------- // -FUNCTION -full_version_string() -> const char* +const char* full_version_string() { +#ifdef IS_RELEASE + return VERSION_STRING; +#else static char buffer[128] = {0}; if (buffer[0] == '\0') @@ -54,12 +56,12 @@ } return buffer; +#endif } // ------------------------------------------------------------------------------------------------- // -FUNCTION -changeset_date_string() -> const char* +const char* changeset_date_string() { return HG_DATE_STRING; } diff -r 9ab869656b9e -r 4f7c2c944637 sources/version.h --- a/sources/version.h Mon Dec 15 20:19:18 2014 +0200 +++ b/sources/version.h Fri May 15 18:36:22 2015 +0300 @@ -33,9 +33,11 @@ #define APPNAME "zfc9000" #define VERSION_MAJOR 1 -#define VERSION_MINOR 0 +#define VERSION_MINOR 1 #define VERSION_PATCH 0 +// #define IS_RELEASE + // ------------------------------------------------------------------------------------------------- // Version string @@ -53,14 +55,13 @@ // ------------------------------------------------------------------------------------------------- // Returns the bare version string (1.2.3) -inline FUNCTION -version_string() -> const char* +inline const char* version_string() { return VERSION_STRING; } // Returns full version string, with hash (1.2.3-abcd456) -FUNCTION full_version_string() -> const char*; +const char* full_version_string(); // Returns changeset date string -FUNCTION changeset_date_string() -> const char*; +const char* changeset_date_string(); \ No newline at end of file