Pull out a colored text output interface out of the Console class.

develop
Alexander Gavrilov 2012-03-10 13:29:33 +04:00
parent c260aca3f1
commit b2737e2bed
7 changed files with 519 additions and 228 deletions

@ -29,6 +29,7 @@ include/Internal.h
include/DFHack.h include/DFHack.h
include/Console.h include/Console.h
include/Core.h include/Core.h
include/ColorText.h
include/DataDefs.h include/DataDefs.h
include/Error.h include/Error.h
include/Export.h include/Export.h
@ -66,6 +67,7 @@ include/modules/Graphic.h
SET(PROJECT_SRCS SET(PROJECT_SRCS
Core.cpp Core.cpp
ColorText.cpp
DataDefs.cpp DataDefs.cpp
DataStatics.cpp DataStatics.cpp
DataStaticsCtor.cpp DataStaticsCtor.cpp

@ -0,0 +1,190 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2011 Petr Mrázek <peterix@gmail.com>
A thread-safe logging console with a line editor for windows.
Based on linenoise win32 port,
copyright 2010, Jon Griffiths <jon_p_griffiths at yahoo dot com>.
All rights reserved.
Based on linenoise, copyright 2010, Salvatore Sanfilippo <antirez at gmail dot com>.
The original linenoise can be found at: http://github.com/antirez/linenoise
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* 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.
* Neither the name of Redis 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 OWNER 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 <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <istream>
#include <string>
#include "ColorText.h"
#include "MiscUtils.h"
#include <cstdio>
#include <cstdlib>
#include <sstream>
using namespace DFHack;
#include "tinythread.h"
using namespace tthread;
void color_ostream::flush_buffer(bool flush)
{
auto buffer = buf();
auto str = buffer->str();
if (!str.empty()) {
add_text(cur_color, buffer->str());
buffer->str(std::string());
}
if (flush)
flush_proxy();
}
void color_ostream::begin_batch()
{
flush_buffer(false);
}
void color_ostream::end_batch()
{
flush_proxy();
}
color_ostream::color_ostream() : ostream(new buffer(this)), cur_color(COLOR_RESET)
{
//
}
color_ostream::~color_ostream()
{
delete buf();
}
void color_ostream::print(const char *format, ...)
{
va_list args;
va_start(args, format);
vprint(format, args);
va_end(args);
}
void color_ostream::vprint(const char *format, va_list args)
{
std::string str = stl_vsprintf(format, args);
if (!str.empty()) {
flush_buffer(false);
add_text(cur_color, str);
if (str[str.size()-1] == '\n')
flush_proxy();
}
}
void color_ostream::printerr(const char * format, ...)
{
va_list args;
va_start(args, format);
vprinterr(format, args);
va_end(args);
}
void color_ostream::vprinterr(const char *format, va_list args)
{
color_value save = cur_color;
fprintf(stderr, format, args);
color(COLOR_LIGHTRED);
vprint(format, args);
color(save);
}
void color_ostream::color(color_value c)
{
if (c == cur_color)
return;
flush_buffer(false);
cur_color = c;
}
void color_ostream::reset_color(void)
{
color(COLOR_RESET);
}
void buffered_color_ostream::add_text(color_value color, const std::string &text)
{
if (text.empty())
return;
if (buffer.empty())
{
buffer.push_back(fragment_type(color, text));
}
else
{
auto &back = buffer.back();
if (back.first != color || std::max(back.second.size(), text.size()) > 128)
buffer.push_back(fragment_type(color, text));
else
buffer.back().second += text;
}
}
void color_ostream_proxy::flush_proxy()
{
if (!buffer.empty())
{
target->begin_batch();
for (auto it = buffer.begin(); it != buffer.end(); ++it)
target->add_text(it->first, it->second);
buffer.clear();
target->end_batch();
}
}
color_ostream_proxy::color_ostream_proxy(color_ostream &target)
: target(&target)
{
//
}
color_ostream_proxy::~color_ostream_proxy()
{
*this << std::flush;
}

@ -126,13 +126,14 @@ const char * getANSIColor(const int c)
namespace DFHack namespace DFHack
{ {
class Private : public std::stringbuf class Private
{ {
public: public:
Private() Private()
{ {
dfout_C = NULL; dfout_C = NULL;
rawmode = false; rawmode = false;
in_batch = false;
supported_terminal = false; supported_terminal = false;
state = con_unclaimed; state = con_unclaimed;
}; };
@ -164,68 +165,71 @@ namespace DFHack
return true; return true;
} }
} }
protected:
int sync()
{
print(str().c_str());
str(std::string()); // Clear the string buffer
return 0;
}
public: public:
/// Print a formatted string, like printf void print(const char *data)
int print(const char * format, ...)
{ {
va_list args; fputs(data, dfout_C);
va_start( args, format );
int ret = vprint( format, args );
va_end( args );
return ret;
} }
int vprint(const char * format, va_list vl)
void print_text(color_ostream::color_value clr, const std::string &chunk)
{ {
if(state == con_lineedit) if(!in_batch && state == con_lineedit)
{ {
disable_raw(); disable_raw();
fprintf(dfout_C,"\x1b[1G"); fprintf(dfout_C,"\x1b[1G");
fprintf(dfout_C,"\x1b[0K"); fprintf(dfout_C,"\x1b[0K");
int ret = vfprintf( dfout_C, format, vl );
color(clr);
print(chunk.c_str());
reset_color();
enable_raw(); enable_raw();
prompt_refresh(); prompt_refresh();
return ret;
} }
else return vfprintf( dfout_C, format, vl ); else
{
color(clr);
print(chunk.c_str());
}
} }
int vprinterr(const char * format, va_list vl)
void begin_batch()
{ {
if(state == con_lineedit) assert(!in_batch);
in_batch = true;
if (state == con_lineedit)
{ {
disable_raw(); disable_raw();
color(Console::COLOR_LIGHTRED);
fprintf(dfout_C,"\x1b[1G"); fprintf(dfout_C,"\x1b[1G");
fprintf(dfout_C,"\x1b[0K"); fprintf(dfout_C,"\x1b[0K");
int ret = vfprintf( dfout_C, format, vl );
reset_color();
enable_raw();
prompt_refresh();
return ret;
} }
else }
void end_batch()
{
assert(in_batch);
flush();
in_batch = false;
if (state == con_lineedit)
{ {
color(Console::COLOR_LIGHTRED);
int ret = vfprintf( dfout_C, format, vl );
reset_color(); reset_color();
return ret; enable_raw();
prompt_refresh();
} }
} }
/// Print a formatted string, like printf, in red
int printerr(const char * format, ...) void flush()
{ {
va_list args; if (!rawmode)
va_start( args, format ); fflush(dfout_C);
int ret = vprinterr( format, args );
va_end( args );
return ret;
} }
/// Clear the console, along with its scrollback /// Clear the console, along with its scrollback
void clear() void clear()
{ {
@ -243,7 +247,9 @@ namespace DFHack
/// Position cursor at x,y. 1,1 = top left corner /// Position cursor at x,y. 1,1 = top left corner
void gotoxy(int x, int y) void gotoxy(int x, int y)
{ {
print("\033[%d;%dH", y,x); char tmp[64];
sprintf(tmp,"\033[%d;%dH", y,x);
print(tmp);
} }
/// Set color (ANSI color number) /// Set color (ANSI color number)
void color(Console::color_value index) void color(Console::color_value index)
@ -291,18 +297,19 @@ namespace DFHack
/// beep. maybe? /// beep. maybe?
//void beep (void); //void beep (void);
/// A simple line edit (raw mode) /// A simple line edit (raw mode)
int lineedit(const std::string& prompt, std::string& output, mutex * lock, CommandHistory & ch) int lineedit(const std::string& prompt, std::string& output, recursive_mutex * lock, CommandHistory & ch)
{ {
output.clear(); output.clear();
reset_color();
this->prompt = prompt; this->prompt = prompt;
if (!supported_terminal) if (!supported_terminal)
{ {
print(prompt.c_str()); print(prompt.c_str());
fflush(dfout_C); fflush(dfout_C);
// FIXME: what do we do here??? // FIXME: what do we do here???
//SDL_mutexV(lock); //SDL_recursive_mutexV(lock);
std::getline(std::cin, output); std::getline(std::cin, output);
//SDL_mutexP(lock); //SDL_recursive_mutexP(lock);
return output.size(); return output.size();
} }
else else
@ -396,7 +403,7 @@ namespace DFHack
if (::write(STDIN_FILENO,seq,strlen(seq)) == -1) return; if (::write(STDIN_FILENO,seq,strlen(seq)) == -1) return;
} }
int prompt_loop(mutex * lock, CommandHistory & history) int prompt_loop(recursive_mutex * lock, CommandHistory & history)
{ {
int fd = STDIN_FILENO; int fd = STDIN_FILENO;
size_t plen = prompt.size(); size_t plen = prompt.size();
@ -606,6 +613,7 @@ namespace DFHack
con_unclaimed, con_unclaimed,
con_lineedit con_lineedit
} state; } state;
bool in_batch;
std::string prompt; // current prompt string std::string prompt; // current prompt string
std::string raw_buffer; // current raw mode buffer std::string raw_buffer; // current raw mode buffer
int raw_cursor; // cursor position in the buffer int raw_cursor; // cursor position in the buffer
@ -615,12 +623,12 @@ namespace DFHack
}; };
} }
Console::Console():std::ostream(0), std::ios(0) Console::Console()
{ {
d = 0; d = 0;
inited = false; inited = false;
// we can't create the mutex at this time. the SDL functions aren't hooked yet. // we can't create the mutex at this time. the SDL functions aren't hooked yet.
wlock = new mutex(); wlock = new recursive_mutex();
} }
Console::~Console() Console::~Console()
{ {
@ -643,7 +651,6 @@ bool Console::init(bool sharing)
d = new Private(); d = new Private();
// make our own weird streams so our IO isn't redirected // make our own weird streams so our IO isn't redirected
d->dfout_C = fopen("/dev/tty", "w"); d->dfout_C = fopen("/dev/tty", "w");
rdbuf(d);
std::cin.tie(this); std::cin.tie(this);
clear(); clear();
d->supported_terminal = !isUnsupportedTerm() && isatty(STDIN_FILENO); d->supported_terminal = !isUnsupportedTerm() && isatty(STDIN_FILENO);
@ -660,7 +667,7 @@ bool Console::shutdown(void)
{ {
if(!d) if(!d)
return true; return true;
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
if(d->rawmode) if(d->rawmode)
d->disable_raw(); d->disable_raw();
d->print("\n"); d->print("\n");
@ -670,46 +677,41 @@ bool Console::shutdown(void)
return true; return true;
} }
int Console::print( const char* format, ... ) void Console::begin_batch()
{ {
va_list args; color_ostream::begin_batch();
lock_guard <mutex> g(*wlock);
int ret; wlock->lock();
if(!inited) ret = -1;
else if (inited)
{ d->begin_batch();
va_start( args, format );
ret = d->vprint(format, args);
va_end(args);
}
return ret;
} }
int Console::printerr( const char* format, ... ) void Console::end_batch()
{ {
va_list args; if (inited)
lock_guard <mutex> g(*wlock); d->end_batch();
int ret;
// also mirror in error log wlock->unlock();
if(!inited) }
{
va_start( args, format ); void Console::flush_proxy()
ret = vfprintf(stderr, format, args); {
va_end(args); lock_guard <recursive_mutex> g(*wlock);
} if (inited)
else d->flush();
{ }
va_start( args, format );
ret = d->vprinterr(format, args); void Console::add_text(color_value color, const std::string &text)
vfprintf(stderr, format, args); {
va_end(args); lock_guard <recursive_mutex> g(*wlock);
} if (inited)
return ret; d->print_text(color, text);
} }
int Console::get_columns(void) int Console::get_columns(void)
{ {
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
int ret = -1; int ret = -1;
if(inited) if(inited)
ret = d->get_columns(); ret = d->get_columns();
@ -718,7 +720,7 @@ int Console::get_columns(void)
int Console::get_rows(void) int Console::get_rows(void)
{ {
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
int ret = -1; int ret = -1;
if(inited) if(inited)
ret = d->get_rows(); ret = d->get_rows();
@ -727,42 +729,28 @@ int Console::get_rows(void)
void Console::clear() void Console::clear()
{ {
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
if(inited) if(inited)
d->clear(); d->clear();
} }
void Console::gotoxy(int x, int y) void Console::gotoxy(int x, int y)
{ {
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
if(inited) if(inited)
d->gotoxy(x,y); d->gotoxy(x,y);
} }
void Console::color(color_value index)
{
lock_guard <mutex> g(*wlock);
if(inited)
d->color(index);
}
void Console::reset_color( void )
{
lock_guard <mutex> g(*wlock);
if(inited)
d->reset_color();
}
void Console::cursor(bool enable) void Console::cursor(bool enable)
{ {
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
if(inited) if(inited)
d->cursor(enable); d->cursor(enable);
} }
int Console::lineedit(const std::string & prompt, std::string & output, CommandHistory & ch) int Console::lineedit(const std::string & prompt, std::string & output, CommandHistory & ch)
{ {
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
int ret = -2; int ret = -2;
if(inited) if(inited)
ret = d->lineedit(prompt,output,wlock,ch); ret = d->lineedit(prompt,output,wlock,ch);

@ -66,10 +66,10 @@ using namespace tthread;
namespace DFHack namespace DFHack
{ {
class Private : public std::stringbuf class Private
{ {
public: public:
Private() : basic_stringbuf<char>::basic_stringbuf() Private()
{ {
dfout_C = 0; dfout_C = 0;
rawmode = 0; rawmode = 0;
@ -78,69 +78,70 @@ namespace DFHack
ConsoleWindow = 0; ConsoleWindow = 0;
default_attributes = 0; default_attributes = 0;
state = con_unclaimed; state = con_unclaimed;
in_batch = false;
raw_cursor = 0; raw_cursor = 0;
}; };
virtual ~Private() virtual ~Private()
{ {
//sync(); //sync();
} }
protected:
int sync()
{
print (str().c_str());
// Clear the string buffer
str(std::string());
return 0;
}
public: public:
/// Print a formatted string, like printf void print(const char *data)
int print(const char * format, ...)
{ {
va_list args; fputs(data, dfout_C);
va_start( args, format );
int ret = vprint( format, args );
va_end( args );
return ret;
} }
int vprint(const char * format, va_list vl)
void print_text(color_ostream::color_value clr, const std::string &chunk)
{ {
if(state == con_lineedit) if(!in_batch && state == con_lineedit)
{ {
clearline(); clearline();
int ret = vfprintf( dfout_C, format, vl );
color(clr);
print(chunk.c_str());
reset_color();
prompt_refresh(); prompt_refresh();
return ret;
} }
else return vfprintf( dfout_C, format, vl ); else
{
color(clr);
print(chunk.c_str());
} }
int vprinterr(const char * format, va_list vl) }
void begin_batch()
{ {
if(state == con_lineedit) assert(!in_batch);
in_batch = true;
if (state == con_lineedit)
{ {
color(Console::COLOR_LIGHTRED);
clearline(); clearline();
int ret = vfprintf( dfout_C, format, vl );
reset_color();
prompt_refresh();
return ret;
} }
else }
void end_batch()
{
assert(in_batch);
flush();
in_batch = false;
if (state == con_lineedit)
{ {
color(Console::COLOR_LIGHTRED);
int ret = vfprintf( dfout_C, format, vl );
reset_color(); reset_color();
return ret; prompt_refresh();
} }
} }
/// Print a formatted string, like printf, in red
int printerr(const char * format, ...) void flush()
{ {
va_list args; fflush(dfout_C);
va_start( args, format );
int ret = vprinterr( format, args );
va_end( args );
return ret;
} }
int get_columns(void) int get_columns(void)
{ {
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 }; CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
@ -250,7 +251,7 @@ namespace DFHack
SetConsoleCursorPosition(console_out, inf.dwCursorPosition); SetConsoleCursorPosition(console_out, inf.dwCursorPosition);
} }
int prompt_loop(mutex * lock, CommandHistory & history) int prompt_loop(recursive_mutex * lock, CommandHistory & history)
{ {
raw_buffer.clear(); // make sure the buffer is empty! raw_buffer.clear(); // make sure the buffer is empty!
size_t plen = prompt.size(); size_t plen = prompt.size();
@ -359,9 +360,10 @@ namespace DFHack
} }
} }
} }
int lineedit(const std::string & prompt, std::string & output, mutex * lock, CommandHistory & ch) int lineedit(const std::string & prompt, std::string & output, recursive_mutex * lock, CommandHistory & ch)
{ {
output.clear(); output.clear();
reset_color();
int count; int count;
state = con_lineedit; state = con_lineedit;
this->prompt = prompt; this->prompt = prompt;
@ -386,6 +388,7 @@ namespace DFHack
con_unclaimed, con_unclaimed,
con_lineedit con_lineedit
} state; } state;
bool in_batch;
std::string prompt; // current prompt string std::string prompt; // current prompt string
std::string raw_buffer; // current raw mode buffer std::string raw_buffer; // current raw mode buffer
int raw_cursor; // cursor position in the buffer int raw_cursor; // cursor position in the buffer
@ -393,7 +396,7 @@ namespace DFHack
} }
Console::Console():std::ostream(0), std::ios(0) Console::Console()
{ {
d = 0; d = 0;
wlock = 0; wlock = 0;
@ -453,7 +456,7 @@ bool Console::init(bool)
// Allocate a console! // Allocate a console!
AllocConsole(); AllocConsole();
d->ConsoleWindow = GetConsoleWindow(); d->ConsoleWindow = GetConsoleWindow();
wlock = new mutex(); wlock = new recursive_mutex();
HMENU hm = GetSystemMenu(d->ConsoleWindow,false); HMENU hm = GetSystemMenu(d->ConsoleWindow,false);
DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND); DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND);
@ -484,7 +487,6 @@ bool Console::init(bool)
std::ios::sync_with_stdio(); std::ios::sync_with_stdio();
// make our own weird streams so our IO isn't redirected // make our own weird streams so our IO isn't redirected
rdbuf(d);
std::cin.tie(this); std::cin.tie(this);
clear(); clear();
inited = true; inited = true;
@ -495,51 +497,47 @@ bool Console::init(bool)
// FIXME: looks awfully empty, doesn't it? // FIXME: looks awfully empty, doesn't it?
bool Console::shutdown(void) bool Console::shutdown(void)
{ {
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
FreeConsole(); FreeConsole();
inited = false; inited = false;
return true; return true;
} }
int Console::print( const char* format, ... )
void Console::begin_batch()
{ {
va_list args; color_ostream::begin_batch();
lock_guard <mutex> g(*wlock);
int ret; wlock->lock();
if(!inited) ret = -1;
else if (inited)
{ d->begin_batch();
va_start( args, format );
ret = d->vprint(format, args);
va_end(args);
}
return ret;
} }
int Console::printerr( const char* format, ... ) void Console::end_batch()
{ {
va_list args; if (inited)
lock_guard <mutex> g(*wlock); d->end_batch();
int ret;
// also mirror in error log wlock->unlock();
if(!inited) }
{
va_start( args, format ); void Console::flush_proxy()
ret = vfprintf(stderr, format, args); {
va_end(args); lock_guard <recursive_mutex> g(*wlock);
} if (inited)
else d->flush();
{ }
va_start( args, format );
ret = d->vprinterr(format, args); void Console::add_text(color_value color, const std::string &text)
vfprintf(stderr, format, args); {
va_end(args); lock_guard <recursive_mutex> g(*wlock);
} if (inited)
return ret; d->print_text(color, text);
} }
int Console::get_columns(void) int Console::get_columns(void)
{ {
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
int ret = -1; int ret = -1;
if(inited) if(inited)
ret = d->get_columns(); ret = d->get_columns();
@ -548,7 +546,7 @@ int Console::get_columns(void)
int Console::get_rows(void) int Console::get_rows(void)
{ {
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
int ret = -1; int ret = -1;
if(inited) if(inited)
ret = d->get_rows(); ret = d->get_rows();
@ -557,35 +555,21 @@ int Console::get_rows(void)
void Console::clear() void Console::clear()
{ {
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
if(inited) if(inited)
d->clear(); d->clear();
} }
void Console::gotoxy(int x, int y) void Console::gotoxy(int x, int y)
{ {
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
if(inited) if(inited)
d->gotoxy(x,y); d->gotoxy(x,y);
} }
void Console::color(color_value index)
{
lock_guard <mutex> g(*wlock);
if(inited)
d->color(index);
}
void Console::reset_color( void )
{
lock_guard <mutex> g(*wlock);
if(inited)
d->reset_color();
}
void Console::cursor(bool enable) void Console::cursor(bool enable)
{ {
lock_guard <mutex> g(*wlock); lock_guard <recursive_mutex> g(*wlock);
if(inited) if(inited)
d->cursor(enable); d->cursor(enable);
} }

@ -0,0 +1,144 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#pragma once
#include "Pragma.h"
#include "Export.h"
#include <list>
#include <fstream>
#include <assert.h>
#include <iostream>
#include <string>
#include <stdarg.h>
#include <sstream>
namespace DFHack
{
class DFHACK_EXPORT color_ostream : public std::ostream
{
public:
enum color_value
{
COLOR_RESET = -1,
COLOR_BLACK = 0,
COLOR_BLUE,
COLOR_GREEN,
COLOR_CYAN,
COLOR_RED,
COLOR_MAGENTA,
COLOR_BROWN,
COLOR_GREY,
COLOR_DARKGREY,
COLOR_LIGHTBLUE,
COLOR_LIGHTGREEN,
COLOR_LIGHTCYAN,
COLOR_LIGHTRED,
COLOR_LIGHTMAGENTA,
COLOR_YELLOW,
COLOR_WHITE,
COLOR_MAX = COLOR_WHITE
};
private:
color_value cur_color;
class buffer : public std::stringbuf
{
public:
color_ostream *owner;
buffer(color_ostream *owner) : owner(owner) {}
virtual ~buffer() { }
protected:
virtual int sync() {
owner->flush_buffer(true);
}
};
buffer *buf() { return (buffer*)rdbuf(); }
void flush_buffer(bool flush);
protected:
// These must be strictly balanced, because
// they might grab and hold mutexes.
virtual void begin_batch();
virtual void end_batch();
virtual void add_text(color_value color, const std::string &text) = 0;
virtual void flush_proxy() {};
friend class color_ostream_proxy;
public:
color_ostream();
virtual ~color_ostream();
/// Print a formatted string, like printf
void print(const char *format, ...);
void vprint(const char *format, va_list args);
/// Print a formatted string, like printf, in red
void printerr(const char *format, ...);
void vprinterr(const char *format, va_list args);
/// Set color (ANSI color number)
void color(color_value c);
/// Reset color to default
void reset_color(void);
virtual bool is_console() { return false; }
};
class DFHACK_EXPORT buffered_color_ostream : public color_ostream
{
protected:
virtual void add_text(color_value color, const std::string &text);
public:
typedef std::pair<color_value,std::string> fragment_type;
buffered_color_ostream() {}
~buffered_color_ostream() {}
const std::list<fragment_type> &fragments() { return buffer; }
protected:
std::list<fragment_type> buffer;
};
class DFHACK_EXPORT color_ostream_proxy : public buffered_color_ostream
{
protected:
color_ostream *target;
virtual void flush_proxy();
public:
color_ostream_proxy(color_ostream &target);
~color_ostream_proxy();
};
}

@ -25,6 +25,7 @@ distribution.
#pragma once #pragma once
#include "Pragma.h" #include "Pragma.h"
#include "Export.h" #include "Export.h"
#include "ColorText.h"
#include <deque> #include <deque>
#include <fstream> #include <fstream>
#include <assert.h> #include <assert.h>
@ -33,6 +34,7 @@ distribution.
namespace tthread namespace tthread
{ {
class mutex; class mutex;
class recursive_mutex;
class condition_variable; class condition_variable;
class thread; class thread;
} }
@ -106,31 +108,18 @@ namespace DFHack
std::size_t capacity; std::size_t capacity;
std::deque <std::string> history; std::deque <std::string> history;
}; };
class Private; class Private;
class DFHACK_EXPORT Console : public std::ostream class DFHACK_EXPORT Console : public color_ostream
{ {
protected:
virtual void begin_batch();
virtual void add_text(color_value color, const std::string &text);
virtual void end_batch();
virtual void flush_proxy();
public: public:
enum color_value
{
COLOR_RESET = -1,
COLOR_BLACK = 0,
COLOR_BLUE,
COLOR_GREEN,
COLOR_CYAN,
COLOR_RED,
COLOR_MAGENTA,
COLOR_BROWN,
COLOR_GREY,
COLOR_DARKGREY,
COLOR_LIGHTBLUE,
COLOR_LIGHTGREEN,
COLOR_LIGHTCYAN,
COLOR_LIGHTRED,
COLOR_LIGHTMAGENTA,
COLOR_YELLOW,
COLOR_WHITE,
COLOR_MAX = COLOR_WHITE
};
///ctor, NOT thread-safe ///ctor, NOT thread-safe
Console(); Console();
///dtor, NOT thread-safe ///dtor, NOT thread-safe
@ -140,18 +129,10 @@ namespace DFHack
/// shutdown the console. NOT thread-safe /// shutdown the console. NOT thread-safe
bool shutdown( void ); bool shutdown( void );
/// Print a formatted string, like printf
int print(const char * format, ...);
/// Print a formatted string, like printf, in red
int printerr(const char * format, ...);
/// Clear the console, along with its scrollback /// Clear the console, along with its scrollback
void clear(); void clear();
/// Position cursor at x,y. 1,1 = top left corner /// Position cursor at x,y. 1,1 = top left corner
void gotoxy(int x, int y); void gotoxy(int x, int y);
/// Set color (ANSI color number)
void color(color_value c);
/// Reset color to default
void reset_color(void);
/// Enable or disable the caret/cursor /// Enable or disable the caret/cursor
void cursor(bool enable = true); void cursor(bool enable = true);
/// Waits given number of milliseconds before continuing. /// Waits given number of milliseconds before continuing.
@ -165,9 +146,11 @@ namespace DFHack
/// A simple line edit (raw mode) /// A simple line edit (raw mode)
int lineedit(const std::string& prompt, std::string& output, CommandHistory & history ); int lineedit(const std::string& prompt, std::string& output, CommandHistory & history );
bool isInited (void) { return inited; }; bool isInited (void) { return inited; };
bool is_console() { return true; }
private: private:
Private * d; Private * d;
tthread::mutex * wlock; tthread::recursive_mutex * wlock;
bool inited; bool inited;
}; };
} }

@ -35,7 +35,7 @@ distribution.
using namespace std; using namespace std;
template <typename T> template <typename T>
void print_bits ( T val, DFHack::Console& out ) void print_bits ( T val, ostream& out )
{ {
stringstream strs; stringstream strs;
T n_bits = sizeof ( val ) * CHAR_BIT; T n_bits = sizeof ( val ) * CHAR_BIT;
@ -63,7 +63,7 @@ void print_bits ( T val, DFHack::Console& out )
val >>= 1; val >>= 1;
} }
strs << endl; strs << endl;
out.print(strs.str().c_str()); out << strs.str();
} }
/* /*