do not use ncurses terminal sequence escaping by default

This commit is contained in:
Andrzej Rybczak
2015-05-07 23:17:25 +02:00
parent 6384c4bfd6
commit 1348271098
7 changed files with 306 additions and 58 deletions

1
NEWS
View File

@@ -19,6 +19,7 @@ ncmpcpp-0.7 (????-??-??)
* Support for the Perl regular expression syntax was added. * Support for the Perl regular expression syntax was added.
* BOOST_LIB_SUFFIX configure variable is now empty by default. * BOOST_LIB_SUFFIX configure variable is now empty by default.
* Shuffle function now shuffles only selected range if selection in playlist is active. * Shuffle function now shuffles only selected range if selection in playlist is active.
* Do not use ncurses terminal sequence escaping by default as it doesn't have enough support for mouse events.
ncmpcpp-0.6.4 (2015-05-02) ncmpcpp-0.6.4 (2015-05-02)

View File

@@ -13,6 +13,8 @@ AC_ARG_ENABLE(outputs, AS_HELP_STRING([--enable-outputs], [Enable outputs screen
AC_ARG_ENABLE(visualizer, AS_HELP_STRING([--enable-visualizer], [Enable music visualizer screen @<:@default=no@:>@]), [visualizer=$enableval], [visualizer=no]) AC_ARG_ENABLE(visualizer, AS_HELP_STRING([--enable-visualizer], [Enable music visualizer screen @<:@default=no@:>@]), [visualizer=$enableval], [visualizer=no])
AC_ARG_ENABLE(clock, AS_HELP_STRING([--enable-clock], [Enable clock screen @<:@default=no@:>@]), [clock=$enableval], [clock=no]) AC_ARG_ENABLE(clock, AS_HELP_STRING([--enable-clock], [Enable clock screen @<:@default=no@:>@]), [clock=$enableval], [clock=no])
AC_ARG_ENABLE(unicode, AS_HELP_STRING([--enable-unicode], [Enable utf8 support @<:@default=yes@:>@]), [unicode=$enableval], [unicode=yes]) AC_ARG_ENABLE(unicode, AS_HELP_STRING([--enable-unicode], [Enable utf8 support @<:@default=yes@:>@]), [unicode=$enableval], [unicode=yes])
AC_ARG_WITH(ncurses-sequence-escaping, AS_HELP_STRING([--with-ncurses-sequence-escaping], [Use built-in ncurses terminal sequence escaping @<:@default=no@:>@]), [ncurses_sequence_escaping=$withval], [ncurses_sequence_escaping=no])
AC_ARG_WITH(curl, AS_HELP_STRING([--with-curl], [Enable fetching lyrics from the Internet @<:@default=auto@:>@]), [curl=$withval], [curl=auto]) AC_ARG_WITH(curl, AS_HELP_STRING([--with-curl], [Enable fetching lyrics from the Internet @<:@default=auto@:>@]), [curl=$withval], [curl=auto])
AC_ARG_WITH(fftw, AS_HELP_STRING([--with-fftw], [Enable fftw support (required for frequency spectrum vizualization) @<:@default=auto@:>@]), [fftw=$withval], [fftw=auto]) AC_ARG_WITH(fftw, AS_HELP_STRING([--with-fftw], [Enable fftw support (required for frequency spectrum vizualization) @<:@default=auto@:>@]), [fftw=$withval], [fftw=auto])
AC_ARG_WITH(taglib, AS_HELP_STRING([--with-taglib], [Enable tag editor @<:@default=auto@:>@]), [taglib=$withval], [taglib=auto]) AC_ARG_WITH(taglib, AS_HELP_STRING([--with-taglib], [Enable tag editor @<:@default=auto@:>@]), [taglib=$withval], [taglib=auto])
@@ -25,6 +27,13 @@ if test "$clock" = "yes"; then
AC_DEFINE([ENABLE_CLOCK], [1], [enables clock screen]) AC_DEFINE([ENABLE_CLOCK], [1], [enables clock screen])
fi fi
AH_TEMPLATE([NCURSES_SEQUENCE_ESCAPING], [Use built-in ncurses terminal sequence escaping])
if test "$ncurses_sequence_escaping" = "yes"; then
AC_DEFINE([NCURSES_SEQUENCE_ESCAPING], [1])
else
AC_DEFINE([NCURSES_SEQUENCE_ESCAPING], [0])
fi
dnl ================================ dnl ================================
dnl = checking for -std=c++0x flag = dnl = checking for -std=c++0x flag =
dnl ================================ dnl ================================

View File

@@ -304,11 +304,11 @@ bool MouseEvent::canBeRun() const
void MouseEvent::run() void MouseEvent::run()
{ {
using Global::VolumeState; using Global::VolumeState;
using Global::wFooter;
m_old_mouse_event = m_mouse_event;
getmouse(&m_mouse_event);
# if NCURSES_MOUSE_VERSION == 1 m_old_mouse_event = m_mouse_event;
m_mouse_event = wFooter->getMouseEvent();
# if NCURSES_SEQUENCE_ESCAPING && NCURSES_MOUSE_VERSION == 1
// workaround shitty ncurses behavior introduced in >=5.8, when we mysteriously get // workaround shitty ncurses behavior introduced in >=5.8, when we mysteriously get
// a few times after ncmpcpp startup 2^27 code instead of BUTTON{1,3}_RELEASED. since that // a few times after ncmpcpp startup 2^27 code instead of BUTTON{1,3}_RELEASED. since that
// 2^27 thing shows constantly instead of BUTTON2_PRESSED, it was redefined to be recognized // 2^27 thing shows constantly instead of BUTTON2_PRESSED, it was redefined to be recognized
@@ -318,7 +318,9 @@ void MouseEvent::run()
// is about to occur and we need to prevent that. // is about to occur and we need to prevent that.
if (m_old_mouse_event.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED) && m_mouse_event.bstate & BUTTON5_PRESSED) if (m_old_mouse_event.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED) && m_mouse_event.bstate & BUTTON5_PRESSED)
return; return;
# endif // NCURSES_MOUSE_VERSION == 1 # endif // NCURSES_SEQUENCE_ESCAPING && NCURSES_MOUSE_VERSION == 1
//Statusbar::printf("(%1%, %2%, %3%)", m_mouse_event.bstate, m_mouse_event.x, m_mouse_event.y);
if (m_mouse_event.bstate & BUTTON1_PRESSED if (m_mouse_event.bstate & BUTTON1_PRESSED
&& m_mouse_event.y == LINES-(Config.statusbar_visibility ? 2 : 1) && m_mouse_event.y == LINES-(Config.statusbar_visibility ? 2 : 1)

View File

@@ -152,10 +152,12 @@ int main(int argc, char **argv)
auto connect_attempt = boost::posix_time::from_time_t(0); auto connect_attempt = boost::posix_time::from_time_t(0);
auto past = boost::posix_time::from_time_t(0); auto past = boost::posix_time::from_time_t(0);
/// enable mouse // enable mouse
# if NCURSES_SEQUENCE_ESCAPING
mouseinterval(0); mouseinterval(0);
# endif // NCURSES_SEQUENCE_ESCAPING
if (Config.mouse_support) if (Config.mouse_support)
mousemask(ALL_MOUSE_EVENTS, 0); mousemask(ALL_MOUSE_EVENTS, nullptr);
while (!Actions::ExitMainLoop) while (!Actions::ExitMainLoop)
{ {

View File

@@ -131,7 +131,9 @@ void Scrollpad::clear()
m_window = newpad(m_height, m_width); m_window = newpad(m_height, m_width);
setTimeout(m_window_timeout); setTimeout(m_window_timeout);
setColor(m_color); setColor(m_color);
# if NCURSES_SEQUENCE_ESCAPING
keypad(m_window, 1); keypad(m_window, 1);
# endif // NCURSES_SEQUENCE_ESCAPING
} }
const std::string &Scrollpad::buffer() const std::string &Scrollpad::buffer()

View File

@@ -362,6 +362,7 @@ Window::Window(size_t startx,
m_border(std::move(border)), m_border(std::move(border)),
m_prompt_hook(0), m_prompt_hook(0),
m_title(std::move(title)), m_title(std::move(title)),
m_escape_terminal_sequences(true),
m_bold_counter(0), m_bold_counter(0),
m_underline_counter(0), m_underline_counter(0),
m_reverse_counter(0), m_reverse_counter(0),
@@ -389,7 +390,9 @@ Window::Window(size_t startx,
m_window = newpad(m_height, m_width); m_window = newpad(m_height, m_width);
setColor(m_color); setColor(m_color);
# if NCURSES_SEQUENCE_ESCAPING
keypad(m_window, 1); keypad(m_window, 1);
# endif // NCURSES_SEQUENCE_ESCAPING
} }
Window::Window(const Window &rhs) Window::Window(const Window &rhs)
@@ -407,6 +410,7 @@ Window::Window(const Window &rhs)
, m_color_stack(rhs.m_color_stack) , m_color_stack(rhs.m_color_stack)
, m_input_queue(rhs.m_input_queue) , m_input_queue(rhs.m_input_queue)
, m_fds(rhs.m_fds) , m_fds(rhs.m_fds)
, m_escape_terminal_sequences(rhs.m_escape_terminal_sequences)
, m_bold_counter(rhs.m_bold_counter) , m_bold_counter(rhs.m_bold_counter)
, m_underline_counter(rhs.m_underline_counter) , m_underline_counter(rhs.m_underline_counter)
, m_reverse_counter(rhs.m_reverse_counter) , m_reverse_counter(rhs.m_reverse_counter)
@@ -429,6 +433,7 @@ Window::Window(Window &&rhs)
, m_color_stack(std::move(rhs.m_color_stack)) , m_color_stack(std::move(rhs.m_color_stack))
, m_input_queue(std::move(rhs.m_input_queue)) , m_input_queue(std::move(rhs.m_input_queue))
, m_fds(std::move(rhs.m_fds)) , m_fds(std::move(rhs.m_fds))
, m_escape_terminal_sequences(rhs.m_escape_terminal_sequences)
, m_bold_counter(rhs.m_bold_counter) , m_bold_counter(rhs.m_bold_counter)
, m_underline_counter(rhs.m_underline_counter) , m_underline_counter(rhs.m_underline_counter)
, m_reverse_counter(rhs.m_reverse_counter) , m_reverse_counter(rhs.m_reverse_counter)
@@ -453,6 +458,7 @@ Window &Window::operator=(Window rhs)
std::swap(m_color_stack, rhs.m_color_stack); std::swap(m_color_stack, rhs.m_color_stack);
std::swap(m_input_queue, rhs.m_input_queue); std::swap(m_input_queue, rhs.m_input_queue);
std::swap(m_fds, rhs.m_fds); std::swap(m_fds, rhs.m_fds);
std::swap(m_escape_terminal_sequences, rhs.m_escape_terminal_sequences);
std::swap(m_bold_counter, rhs.m_bold_counter); std::swap(m_bold_counter, rhs.m_bold_counter);
std::swap(m_underline_counter, rhs.m_underline_counter); std::swap(m_underline_counter, rhs.m_underline_counter);
std::swap(m_reverse_counter, rhs.m_reverse_counter); std::swap(m_reverse_counter, rhs.m_reverse_counter);
@@ -529,7 +535,9 @@ void Window::recreate(size_t width, size_t height)
m_window = newpad(height, width); m_window = newpad(height, width);
setTimeout(m_window_timeout); setTimeout(m_window_timeout);
setColor(m_color); setColor(m_color);
# if NCURSES_SEQUENCE_ESCAPING
keypad(m_window, 1); keypad(m_window, 1);
# endif // NCURSES_SEQUENCE_ESCAPING
} }
void Window::moveTo(size_t new_x, size_t new_y) void Window::moveTo(size_t new_x, size_t new_y)
@@ -665,6 +673,198 @@ bool Window::FDCallbacksListEmpty() const
return m_fds.empty(); return m_fds.empty();
} }
int Window::getInputChar()
{
# if NCURSES_SEQUENCE_ESCAPING
return wgetch(m_window);
# else
int key = wgetch(m_window);
if (!m_escape_terminal_sequences || key != KEY_ESCAPE)
return key;
key = wgetch(m_window);
switch (key)
{
case '\t': // tty
return KEY_SHIFT_TAB;
case 'O': // F1 to F4 in xterm
key = wgetch(m_window);
switch (key)
{
case 'P':
key = KEY_F1;
break;
case 'Q':
key = KEY_F2;
break;
case 'R':
key = KEY_F3;
break;
case 'S':
key = KEY_F4;
break;
default:
key = ERR;
break;
}
return key;
case '[':
key = wgetch(m_window);
switch (key)
{
case 'A':
return KEY_UP;
case 'B':
return KEY_DOWN;
case 'C':
return KEY_RIGHT;
case 'D':
return KEY_LEFT;
case 'F': // xterm
return KEY_END;
case 'H': // xterm
return KEY_HOME;
case 'M':
key = wgetch(m_window);
m_mouse_event.x = wgetch(m_window);
m_mouse_event.y = wgetch(m_window);
switch (key & ~24)
{
case ' ':
m_mouse_event.bstate = BUTTON1_PRESSED;
break;
case '!':
m_mouse_event.bstate = BUTTON2_PRESSED;
break;
case '"':
m_mouse_event.bstate = BUTTON3_PRESSED;
break;
case '`':
m_mouse_event.bstate = BUTTON4_PRESSED;
break;
case 'a':
m_mouse_event.bstate = BUTTON5_PRESSED;
break;
default:
return ERR;
}
if (key & 8)
m_mouse_event.bstate |= BUTTON_ALT;
if (key & 16)
m_mouse_event.bstate |= BUTTON_CTRL;
m_mouse_event.x -= 33;
if (m_mouse_event.x < 0 || m_mouse_event.x >= COLS)
return ERR;
m_mouse_event.y -= 33;
if (m_mouse_event.y < 0 || m_mouse_event.y >= LINES)
return ERR;
return KEY_MOUSE;
case 'Z':
return KEY_SHIFT_TAB;
case '[': // F1 to F5 in tty
key = wgetch(m_window);
switch (key)
{
case 'A':
key = KEY_F1;
break;
case 'B':
key = KEY_F2;
break;
case 'C':
key = KEY_F3;
break;
case 'D':
key = KEY_F4;
break;
case 'E':
key = KEY_F5;
break;
default:
key = ERR;
break;
}
return key;
case '1': // HOME in tty, F1 to F8
key = wgetch(m_window);
switch (key)
{
case '~':
return KEY_HOME;
case '1':
key = KEY_F1;
break;
case '2':
key = KEY_F2;
break;
case '3':
key = KEY_F3;
break;
case '4':
key = KEY_F4;
break;
case '5':
key = KEY_F5;
break;
case '7': // not a typo
key = KEY_F6;
break;
case '8':
key = KEY_F7;
break;
case '9':
key = KEY_F8;
break;
default:
key = ERR;
break;
}
return wgetch(m_window) == '~' ? key : ERR;
case '2': // INSERT, F9 to F12
key = wgetch(m_window);
switch (key)
{
case '~':
return KEY_IC;
case '0':
key = KEY_F9;
break;
case '1':
key = KEY_F10;
break;
case '3': // not a typo
key = KEY_F11;
break;
case '4':
key = KEY_F12;
break;
default:
key = ERR;
break;
}
return wgetch(m_window) == '~' ? key : ERR;
case '3':
return wgetch(m_window) == '~' ? KEY_DC : ERR;
case '4': // tty
return wgetch(m_window) == '~' ? KEY_END : ERR;
case '5':
return wgetch(m_window) == '~' ? KEY_PPAGE : ERR;
case '6':
return wgetch(m_window) == '~' ? KEY_NPAGE : ERR;
case '7':
return wgetch(m_window) == '~' ? KEY_HOME : ERR;
case '8':
return wgetch(m_window) == '~' ? KEY_END : ERR;
default:
return ERR;
}
break;
default:
m_input_queue.push(key);
return KEY_ESCAPE;
}
# endif // NCURSES_SEQUENCE_ESCAPING
}
int Window::readKey() int Window::readKey()
{ {
int result; int result;
@@ -692,7 +892,8 @@ int Window::readKey()
if (select(fd_max+1, &fdset, 0, 0, m_window_timeout < 0 ? 0 : &timeout) > 0) if (select(fd_max+1, &fdset, 0, 0, m_window_timeout < 0 ? 0 : &timeout) > 0)
{ {
result = FD_ISSET(STDIN_FILENO, &fdset) ? wgetch(m_window) : ERR; result = FD_ISSET(STDIN_FILENO, &fdset) ? getInputChar() : ERR;
for (FDCallbacks::const_iterator it = m_fds.begin(); it != m_fds.end(); ++it) for (FDCallbacks::const_iterator it = m_fds.begin(); it != m_fds.end(); ++it)
if (FD_ISSET(it->first, &fdset)) if (FD_ISSET(it->first, &fdset))
it->second(); it->second();
@@ -709,6 +910,8 @@ void Window::pushChar(int ch)
std::string Window::prompt(const std::string &base, size_t width, bool encrypted) std::string Window::prompt(const std::string &base, size_t width, bool encrypted)
{ {
std::string result;
rl::aborted = false; rl::aborted = false;
rl::w = this; rl::w = this;
getyx(m_window, rl::start_y, rl::start_x); getyx(m_window, rl::start_y, rl::start_x);
@@ -716,15 +919,19 @@ std::string Window::prompt(const std::string &base, size_t width, bool encrypted
rl::encrypted = encrypted; rl::encrypted = encrypted;
rl::base = base.c_str(); rl::base = base.c_str();
mmask_t oldmask;
std::string result;
curs_set(1); curs_set(1);
# if NCURSES_SEQUENCE_ESCAPING
mmask_t oldmask;
keypad(m_window, 0); keypad(m_window, 0);
mousemask(0, &oldmask); mousemask(0, &oldmask);
# endif // NCURSES_SEQUENCE_ESCAPING
m_escape_terminal_sequences = false;
char *input = readline(nullptr); char *input = readline(nullptr);
m_escape_terminal_sequences = true;
# if NCURSES_SEQUENCE_ESCAPING
mousemask(oldmask, nullptr); mousemask(oldmask, nullptr);
keypad(m_window, 1); keypad(m_window, 1);
# endif // NCURSES_SEQUENCE_ESCAPING
curs_set(0); curs_set(0);
if (input != nullptr) if (input != nullptr)
{ {
@@ -829,6 +1036,14 @@ int Window::getTimeout() const
return m_window_timeout; return m_window_timeout;
} }
const MEVENT &Window::getMouseEvent()
{
# if NCURSES_SEQUENCE_ESCAPING
getmouse(&m_mouse_event);
# endif // NCURSES_SEQUENCE_ESCAPING
return m_mouse_event;
}
void Window::scroll(Scroll where) void Window::scroll(Scroll where)
{ {
idlok(m_window, 1); idlok(m_window, 1);

View File

@@ -36,66 +36,75 @@
#include <queue> #include <queue>
// define some Ctrl-? keys // define some Ctrl-? keys
#define KEY_CTRL_A 1 const int KEY_CTRL_A = 1;
#define KEY_CTRL_B 2 const int KEY_CTRL_B = 2;
#define KEY_CTRL_C 3 const int KEY_CTRL_C = 3;
#define KEY_CTRL_D 4 const int KEY_CTRL_D = 4;
#define KEY_CTRL_E 5 const int KEY_CTRL_E = 5;
#define KEY_CTRL_F 6 const int KEY_CTRL_F = 6;
#define KEY_CTRL_G 7 const int KEY_CTRL_G = 7;
#define KEY_CTRL_H 8 const int KEY_CTRL_H = 8;
#define KEY_CTRL_I 9 const int KEY_CTRL_I = 9;
#define KEY_CTRL_J 10 const int KEY_CTRL_J = 10;
#define KEY_CTRL_K 11 const int KEY_CTRL_K = 11;
#define KEY_CTRL_L 12 const int KEY_CTRL_L = 12;
#define KEY_CTRL_M 13 const int KEY_CTRL_M = 13;
#define KEY_CTRL_N 14 const int KEY_CTRL_N = 14;
#define KEY_CTRL_O 15 const int KEY_CTRL_O = 15;
#define KEY_CTRL_P 16 const int KEY_CTRL_P = 16;
#define KEY_CTRL_Q 17 const int KEY_CTRL_Q = 17;
#define KEY_CTRL_R 18 const int KEY_CTRL_R = 18;
#define KEY_CTRL_S 19 const int KEY_CTRL_S = 19;
#define KEY_CTRL_T 20 const int KEY_CTRL_T = 20;
#define KEY_CTRL_U 21 const int KEY_CTRL_U = 21;
#define KEY_CTRL_V 22 const int KEY_CTRL_V = 22;
#define KEY_CTRL_W 23 const int KEY_CTRL_W = 23;
#define KEY_CTRL_X 24 const int KEY_CTRL_X = 24;
#define KEY_CTRL_Y 25 const int KEY_CTRL_Y = 25;
#define KEY_CTRL_Z 26 const int KEY_CTRL_Z = 26;
inline int KEY_ALT(int key)
{
return key << 8;
}
// define F? keys // define F? keys
#define KEY_F1 265 const int KEY_F1 = 265;
#define KEY_F2 266 const int KEY_F2 = 266;
#define KEY_F3 267 const int KEY_F3 = 267;
#define KEY_F4 268 const int KEY_F4 = 268;
#define KEY_F5 269 const int KEY_F5 = 269;
#define KEY_F6 270 const int KEY_F6 = 270;
#define KEY_F7 271 const int KEY_F7 = 271;
#define KEY_F8 272 const int KEY_F8 = 272;
#define KEY_F9 273 const int KEY_F9 = 273;
#define KEY_F10 274 const int KEY_F10 = 274;
#define KEY_F11 275 const int KEY_F11 = 275;
#define KEY_F12 276 const int KEY_F12 = 276;
// other handy keys // other handy keys
#define KEY_ESCAPE 27 const int KEY_ESCAPE = 27;
#define KEY_SHIFT_TAB 353 const int KEY_SHIFT_TAB = 353;
#define KEY_SPACE 32 const int KEY_SPACE = 32;
#define KEY_TAB 9 const int KEY_TAB = 9;
// define alternative KEY_BACKSPACE (used in some terminal emulators) // define alternative KEY_BACKSPACE (used in some terminal emulators)
#define KEY_BACKSPACE_2 127 const int KEY_BACKSPACE_2 = 127;
// KEY_ENTER is 343, which doesn't make any sense. This makes it useful. // KEY_ENTER is 343, which doesn't make any sense. This makes it useful.
#undef KEY_ENTER #undef KEY_ENTER
#define KEY_ENTER 13 const int KEY_ENTER = 13;
#if NCURSES_MOUSE_VERSION == 1 #if NCURSES_SEQUENCE_ESCAPING
# if NCURSES_MOUSE_VERSION == 1
// NOTICE: define BUTTON5_PRESSED to be BUTTON2_PRESSED with additional mask // NOTICE: define BUTTON5_PRESSED to be BUTTON2_PRESSED with additional mask
// (I noticed that it sometimes returns 134217728 (2^27) instead of expected // (I noticed that it sometimes returns 134217728 (2^27) instead of expected
// mask, so the modified define does it right. // mask, so the modified define does it right.
# define BUTTON5_PRESSED (BUTTON2_PRESSED | (1U << 27)) # define BUTTON5_PRESSED (BUTTON2_PRESSED | (1U << 27))
#endif // NCURSES_MOUSE_VERSION == 1 # endif // NCURSES_MOUSE_VERSION == 1
#else
# define BUTTON5_PRESSED (1U << 27)
#endif // NCURSES_SEQUENCE_ESCAPING
// undefine macros with colliding names // undefine macros with colliding names
#undef border #undef border
@@ -295,6 +304,9 @@ struct Window
/// @return current window's timeout /// @return current window's timeout
int getTimeout() const; int getTimeout() const;
/// @return current mouse event if readKey() returned KEY_MOUSE
const MEVENT &getMouseEvent();
/// Reads the string from standard input using readline library. /// Reads the string from standard input using readline library.
/// @param base base string that has to be edited /// @param base base string that has to be edited
/// @param length max length of the string, unlimited by default /// @param length max length of the string, unlimited by default
@@ -470,6 +482,8 @@ protected:
Border m_border; Border m_border;
private: private:
int getInputChar();
/// Sets state of bold attribute (internal use only) /// Sets state of bold attribute (internal use only)
/// @param bold_state state of bold attribute /// @param bold_state state of bold attribute
/// ///
@@ -512,6 +526,9 @@ private:
typedef std::vector< std::pair<int, void (*)()> > FDCallbacks; typedef std::vector< std::pair<int, void (*)()> > FDCallbacks;
FDCallbacks m_fds; FDCallbacks m_fds;
MEVENT m_mouse_event;
bool m_escape_terminal_sequences;
/// counters for format flags /// counters for format flags
int m_bold_counter; int m_bold_counter;
int m_underline_counter; int m_underline_counter;