Windows side of the Console rewrite

develop
Petr Mrázek 2011-07-14 04:05:27 +02:00
parent 630b746cfe
commit 792d272fbf
16 changed files with 386 additions and 185 deletions

@ -29,6 +29,9 @@ SET(DFHACK_OUTPUT_DIR "${dfhack_BINARY_DIR}/bin" CACHE STRING "Where should be t
SET(DFHACK_PLUGIN_OUTPUT_DIR "${DFHACK_OUTPUT_DIR}/plugins") SET(DFHACK_PLUGIN_OUTPUT_DIR "${DFHACK_OUTPUT_DIR}/plugins")
## where to put things during the build (force MSVC to behave) ## where to put things during the build (force MSVC to behave)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${DFHACK_OUTPUT_DIR})
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${DFHACK_OUTPUT_DIR})
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${DFHACK_OUTPUT_DIR})
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${DFHACK_OUTPUT_DIR}) SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${DFHACK_OUTPUT_DIR})
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${DFHACK_OUTPUT_DIR}) SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${DFHACK_OUTPUT_DIR})
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${DFHACK_OUTPUT_DIR}) SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${DFHACK_OUTPUT_DIR})

@ -66,6 +66,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "dfhack/Console.h" #include "dfhack/Console.h"
#include "dfhack/extra/stdiostream.h"
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <sstream> #include <sstream>
@ -78,6 +79,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <termios.h> #include <termios.h>
#include <errno.h> #include <errno.h>
#include <deque>
using namespace DFHack; using namespace DFHack;
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
@ -94,28 +96,7 @@ namespace DFHack
dfout_C = 0; dfout_C = 0;
stream_o = 0; stream_o = 0;
rawmode = 0; rawmode = 0;
history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
history_len = 0;
history = NULL;
}; };
int get_columns(void)
{
winsize ws;
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) return 80;
return ws.ws_col;
}
int get_rows(void)
{
winsize ws;
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) return 25;
return ws.ws_row;
}
void clear()
{
const char * clr = "\033c\033[3J\033[H";
write(STDIN_FILENO,clr,strlen(clr));
}
int isUnsupportedTerm(void) int isUnsupportedTerm(void)
{ {
@ -132,13 +113,10 @@ namespace DFHack
duthomhas::stdiobuf * stream_o; duthomhas::stdiobuf * stream_o;
termios orig_termios; /* in order to restore at exit */ termios orig_termios; /* in order to restore at exit */
int rawmode; /* for atexit() function to check if restore is needed*/ int rawmode; /* for atexit() function to check if restore is needed*/
int history_max_len; std::deque <std::string> history;
int history_len;
char **history;
}; };
} }
// FIXME: prime candidate for being a singleton... Console::Console():std::ostream(0), std::ios(0)
Console::Console()
{ {
d = new Private(); d = new Private();
} }
@ -175,18 +153,30 @@ int Console::print( const char* format, ... )
int Console::get_columns(void) int Console::get_columns(void)
{ {
return d->get_columns(); winsize ws;
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) return 80;
return ws.ws_col;
} }
int Console::get_rows(void) int Console::get_rows(void)
{ {
return d->get_rows(); winsize ws;
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) return 25;
return ws.ws_row;
} }
void Console::clear() void Console::clear()
{ {
*this << "\033c"; if(d->rawmode)
*this << "\033[3J\033[H"; {
const char * clr = "\033c\033[3J\033[H";
::write(STDIN_FILENO,clr,strlen(clr));
}
else
{
*this << "\033c";
*this << "\033[3J\033[H";
}
} }
void Console::gotoxy(int x, int y) void Console::gotoxy(int x, int y)
@ -344,7 +334,7 @@ int Console::prompt_loop(const std::string & prompt, std::string & buffer)
int fd = STDIN_FILENO; int fd = STDIN_FILENO;
size_t plen = prompt.size(); size_t plen = prompt.size();
size_t pos = 0; size_t pos = 0;
size_t cols = d->get_columns(); size_t cols = get_columns();
int history_index = 0; int history_index = 0;
/* The latest history entry is always our current buffer, that /* The latest history entry is always our current buffer, that
@ -386,7 +376,7 @@ int Console::prompt_loop(const std::string & prompt, std::string & buffer)
switch(c) { switch(c) {
case 13: /* enter */ case 13: /* enter */
history.pop_front(); d->history.pop_front();
return buffer.size(); return buffer.size();
case 3: /* ctrl-c */ case 3: /* ctrl-c */
errno = EAGAIN; errno = EAGAIN;
@ -400,41 +390,6 @@ int Console::prompt_loop(const std::string & prompt, std::string & buffer)
prompt_refresh(prompt,buffer,pos); prompt_refresh(prompt,buffer,pos);
} }
break; break;
// I fail to see how is this useful to anyone but hardcore emacs users
/*
case 4: // ctrl-d, remove char at right of cursor
if (len > 1 && pos < (len-1)) {
memmove(buf+pos,buf+pos+1,len-pos);
len--;
buf[len] = '\0';
prompt_refresh(prompt,buffer,pos);
} else if (len == 0) {
history_len--;
free(history[history_len]);
return -1;
}
break;
case 20: // ctrl-t
if (pos > 0 && pos < len) {
int aux = buf[pos-1];
buf[pos-1] = buf[pos];
buf[pos] = aux;
if (pos != len-1) pos++;
prompt_refresh(prompt,buffer,pos);
}
break;
case 2: // ctrl-b
goto left_arrow;
case 6: // ctrl-f
goto right_arrow;
case 16: // ctrl-p
seq[1] = 65;
goto up_down_arrow;
case 14: // ctrl-n
seq[1] = 66;
goto up_down_arrow;
break;
*/
case 27: /* escape sequence */ case 27: /* escape sequence */
if (::read(fd,seq,2) == -1) break; if (::read(fd,seq,2) == -1) break;
if(seq[0] == '[') if(seq[0] == '[')
@ -460,13 +415,12 @@ int Console::prompt_loop(const std::string & prompt, std::string & buffer)
} }
else if (seq[1] == 'A' || seq[1] == 'B') else if (seq[1] == 'A' || seq[1] == 'B')
{ {
up_down_arrow:
/* up and down arrow: history */ /* up and down arrow: history */
if (history.size() > 1) if (d->history.size() > 1)
{ {
/* Update the current history entry before to /* Update the current history entry before to
* overwrite it with tne next one. */ * overwrite it with tne next one. */
history[history_index] = buffer; d->history[history_index] = buffer;
/* Show the new entry */ /* Show the new entry */
history_index += (seq[1] == 'A') ? 1 : -1; history_index += (seq[1] == 'A') ? 1 : -1;
if (history_index < 0) if (history_index < 0)
@ -474,12 +428,12 @@ int Console::prompt_loop(const std::string & prompt, std::string & buffer)
history_index = 0; history_index = 0;
break; break;
} }
else if (history_index >= history.size()) else if (history_index >= d->history.size())
{ {
history_index = history.size()-1; history_index = d->history.size()-1;
break; break;
} }
buffer = history[history_index]; buffer = d->history[history_index];
pos = buffer.size(); pos = buffer.size();
prompt_refresh(prompt,buffer,pos); prompt_refresh(prompt,buffer,pos);
} }
@ -562,11 +516,11 @@ int Console::prompt_loop(const std::string & prompt, std::string & buffer)
// push to front, remove from back if we are above maximum. ignore immediate duplicates // push to front, remove from back if we are above maximum. ignore immediate duplicates
void Console::history_add(const std::string & command) void Console::history_add(const std::string & command)
{ {
if(history.front() == command) if(d->history.front() == command)
return; return;
history.push_front(command); d->history.push_front(command);
if(history.size() > 100) if(d->history.size() > 100)
history.pop_back(); d->history.pop_back();
} }
int Console::lineedit(const std::string & prompt, std::string & output) int Console::lineedit(const std::string & prompt, std::string & output)

@ -25,6 +25,7 @@ distribution.
#include <conio.h> #include <conio.h>
#include <stdarg.h> #include <stdarg.h>
#include "dfhack/extra/stdiostream.h"
#include < process.h> #include < process.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@ -39,21 +40,57 @@ distribution.
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <sstream> #include <sstream>
#include <deque>
using namespace DFHack; using namespace DFHack;
// FIXME: maybe make configurable with an ini option? // FIXME: maybe make configurable with an ini option?
#define MAX_CONSOLE_LINES 999; #define MAX_CONSOLE_LINES 999;
duthomhas::stdiostream dfout; namespace DFHack
FILE * dfout_C = 0; {
duthomhas::stdiobuf * stream_o = 0; class Private
{
public:
Private()
{
dfout_C = 0;
stream_o = 0;
rawmode = 0;
console_in = 0;
console_out = 0;
ConsoleWindow = 0;
default_attributes = 0;
};
void output(const char* str, size_t len, int x, int y)
{
COORD pos = { (SHORT)x, (SHORT)y };
DWORD count = 0;
WriteConsoleOutputCharacterA(console_out, str, len, pos, &count);
}
FILE * dfout_C;
duthomhas::stdiobuf * stream_o;
int rawmode; /* for atexit() function to check if restore is needed*/
std::deque <std::string> history;
HANDLE console_in;
HANDLE console_out;
HWND ConsoleWindow;
WORD default_attributes;
};
}
Console::Console():std::ostream(0), std::ios(0)
{
d = new Private();
}
HANDLE g_hConsoleOut; // Handle to debug console Console::~Console()
HWND ConsoleWindow; {
WORD default_attributes; }
// FIXME: prime candidate for being a singleton... indeed. bool Console::init(void)
Console::Console()
{ {
int hConHandle; int hConHandle;
long lStdHandle; long lStdHandle;
@ -63,25 +100,26 @@ Console::Console()
// Allocate a console! // Allocate a console!
AllocConsole(); AllocConsole();
ConsoleWindow = GetConsoleWindow(); d->ConsoleWindow = GetConsoleWindow();
HMENU hm = GetSystemMenu(ConsoleWindow,false); HMENU hm = GetSystemMenu(d->ConsoleWindow,false);
DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND); DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND);
// set the screen buffer to be big enough to let us scroll text // set the screen buffer to be big enough to let us scroll text
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
default_attributes = coninfo.wAttributes; d->default_attributes = coninfo.wAttributes;
coninfo.dwSize.Y = MAX_CONSOLE_LINES; // How many lines do you want to have in the console buffer coninfo.dwSize.Y = MAX_CONSOLE_LINES; // How many lines do you want to have in the console buffer
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
// redirect unbuffered STDOUT to the console // redirect unbuffered STDOUT to the console
g_hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE); d->console_out = GetStdHandle(STD_OUTPUT_HANDLE);
lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE); lStdHandle = (long)d->console_out;
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
dfout_C = _fdopen( hConHandle, "w" ); d->dfout_C = _fdopen( hConHandle, "w" );
setvbuf( dfout_C, NULL, _IONBF, 0 ); setvbuf( d->dfout_C, NULL, _IONBF, 0 );
// redirect unbuffered STDIN to the console // redirect unbuffered STDIN to the console
lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE); d->console_in = GetStdHandle(STD_INPUT_HANDLE);
lStdHandle = (long)d->console_in;
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "r" ); fp = _fdopen( hConHandle, "r" );
*stdin = *fp; *stdin = *fp;
@ -92,16 +130,40 @@ Console::Console()
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
stream_o = new duthomhas::stdiobuf(dfout_C); d->stream_o = new duthomhas::stdiobuf(d->dfout_C);
dfout.rdbuf(stream_o); rdbuf(d->stream_o);
std::cin.tie(&dfout); std::cin.tie(this);
clear(); clear();
// result is a terminal controlled by the parasitic code! return true;
} }
Console::~Console() bool Console::shutdown(void)
{ {
FreeConsole(); FreeConsole();
return true;
}
int Console::print( const char* format, ... )
{
va_list args;
va_start( args, format );
int ret = vfprintf( d->dfout_C, format, args );
va_end( args );
return ret;
}
int Console::get_columns(void)
{
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
GetConsoleScreenBufferInfo(d->console_out, &inf);
return (size_t)inf.dwSize.X;
}
int Console::get_rows(void)
{
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
GetConsoleScreenBufferInfo(d->console_out, &inf);
return (size_t)inf.dwSize.Y;
} }
void Console::clear() void Console::clear()
@ -124,7 +186,7 @@ void Console::color(int index)
void Console::reset_color( void ) void Console::reset_color( void )
{ {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, default_attributes); SetConsoleTextAttribute(hConsole, d->default_attributes);
} }
@ -153,4 +215,178 @@ void Console::cursor(bool enable)
void Console::msleep (unsigned int msec) void Console::msleep (unsigned int msec)
{ {
Sleep(msec); Sleep(msec);
}
int Console::enable_raw()
{
return 0;
}
void Console::disable_raw()
{
/* Nothing to do yet */
}
void Console::prompt_refresh( const std::string& prompt, const std::string& buffer, size_t pos)
{
size_t cols = get_columns();
size_t plen = prompt.size();
const char * buf = buffer.c_str();
size_t len = buffer.size();
while ((plen + pos) >= cols)
{
buf++;
len--;
pos--;
}
while (plen + len > cols)
{
len--;
}
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
GetConsoleScreenBufferInfo(d->console_out, &inf);
d->output(prompt.c_str(), plen, 0, inf.dwCursorPosition.Y);
d->output(buf, len, plen, inf.dwCursorPosition.Y);
if (plen + len < (size_t)inf.dwSize.X)
{
/* Blank to EOL */
char* tmp = (char*)malloc(inf.dwSize.X - (plen + len));
memset(tmp, ' ', inf.dwSize.X - (plen + len));
d->output(tmp, inf.dwSize.X - (plen + len), len + plen, inf.dwCursorPosition.Y);
free(tmp);
}
inf.dwCursorPosition.X = (SHORT)(pos + plen);
SetConsoleCursorPosition(d->console_out, inf.dwCursorPosition);
}
int Console::prompt_loop(const std::string & prompt, std::string & buffer)
{
buffer.clear(); // make sure the buffer is empty!
size_t plen = prompt.size();
size_t pos = 0;
int history_index = 0;
/* The latest history entry is always our current buffer, that
* initially is just an empty string. */
history_add("");
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
GetConsoleScreenBufferInfo(d->console_out, &inf);
size_t cols = inf.dwSize.X;
d->output(prompt.c_str(), plen, 0, inf.dwCursorPosition.Y);
inf.dwCursorPosition.X = (SHORT)plen;
SetConsoleCursorPosition(d->console_out, inf.dwCursorPosition);
while (1)
{
INPUT_RECORD rec;
DWORD count;
ReadConsoleInputA(d->console_in, &rec, 1, &count);
if (rec.EventType != KEY_EVENT || !rec.Event.KeyEvent.bKeyDown)
continue;
switch (rec.Event.KeyEvent.wVirtualKeyCode)
{
case VK_RETURN: // enter
d->history.pop_front();
return buffer.size();
case VK_BACK: // backspace
if (pos > 0 && buffer.size() > 0)
{
buffer.erase(pos-1,1);
pos--;
prompt_refresh(prompt,buffer,pos);
}
break;
case VK_LEFT: // left arrow
if (pos > 0)
{
pos--;
prompt_refresh(prompt,buffer,pos);
}
break;
case VK_RIGHT: // right arrow
if (pos != buffer.size())
{
pos++;
prompt_refresh(prompt,buffer,pos);
}
break;
case VK_UP:
case VK_DOWN:
/* up and down arrow: history */
if (d->history.size() > 1)
{
/* Update the current history entry before to
* overwrite it with tne next one. */
d->history[history_index] = buffer;
/* Show the new entry */
history_index += (rec.Event.KeyEvent.wVirtualKeyCode == VK_UP) ? 1 : -1;
if (history_index < 0)
{
history_index = 0;
break;
}
else if (history_index >= d->history.size())
{
history_index = d->history.size()-1;
break;
}
buffer = d->history[history_index];
pos = buffer.size();
prompt_refresh(prompt,buffer,pos);
}
break;
case VK_DELETE:
// delete
if (buffer.size() > 0 && pos < buffer.size())
{
buffer.erase(pos,1);
prompt_refresh(prompt,buffer,pos);
}
break;
case VK_HOME:
pos = 0;
prompt_refresh(prompt,buffer,pos);
break;
case VK_END:
pos = buffer.size();
prompt_refresh(prompt,buffer,pos);
break;
default:
if (rec.Event.KeyEvent.uChar.AsciiChar < ' ' ||
rec.Event.KeyEvent.uChar.AsciiChar > '~')
continue;
if (buffer.size() == pos)
buffer.append(1,rec.Event.KeyEvent.uChar.AsciiChar);
else
buffer.insert(pos,1,rec.Event.KeyEvent.uChar.AsciiChar);
pos++;
prompt_refresh(prompt,buffer,pos);
break;
}
}
}
// push to front, remove from back if we are above maximum. ignore immediate duplicates
void Console::history_add(const std::string & command)
{
if(d->history.front() == command)
return;
d->history.push_front(command);
if(d->history.size() > 100)
d->history.pop_back();
}
int Console::lineedit(const std::string & prompt, std::string & output)
{
output.clear();
int count;
if (enable_raw() == -1)
return -1;
count = prompt_loop(prompt,output);
disable_raw();
*this << std::endl;
return count;
} }

@ -121,22 +121,24 @@ int fHKthread(void * iodata)
// A thread function... for the interactive console. // A thread function... for the interactive console.
int fIOthread(void * iodata) int fIOthread(void * iodata)
{ {
Core * core = ((IODATA*) iodata)->core; IODATA * iod = ((IODATA*) iodata);
Core * core = iod->core;
PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr; PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr;
Console & con = core->con;
if(plug_mgr == 0 || core == 0) if(plug_mgr == 0 || core == 0)
{ {
core->con << "Something horrible happened to the plugin manager in Core's constructor..." << std::endl; con.print("Something horrible happened to the plugin manager in Core's constructor...\n");
return 0; return 0;
} }
core->con.print("DFHack is ready. Have a nice day! Type in '?' or 'help' for help.\n"); con.print("DFHack is ready. Have a nice day! Type in '?' or 'help' for help.\n");
//dfterm << << endl; //dfterm << << endl;
int clueless_counter = 0; int clueless_counter = 0;
while (true) while (true)
{ {
string command = ""; string command = "";
core->con.lineedit("[DFHack]# ",command); con.lineedit("[DFHack]# ",command);
core->con.history_add(command); con.history_add(command);
//core->con <<"[DFHack]# "; //con <<"[DFHack]# ";
//char * line = linenoise("[DFHack]# ", core->con.dfout_C); //char * line = linenoise("[DFHack]# ", core->con.dfout_C);
// dfout <<"[DFHack]# "; // dfout <<"[DFHack]# ";
/* /*
@ -149,20 +151,20 @@ int fIOthread(void * iodata)
//getline(cin, command); //getline(cin, command);
if(command=="help" || command == "?") if(command=="help" || command == "?")
{ {
core->con << "Available commands" << endl; con.print("Available commands\n");
core->con << "------------------" << endl; con.print("------------------\n");
for(int i = 0; i < plug_mgr->size();i++) for(int i = 0; i < plug_mgr->size();i++)
{ {
const Plugin * plug = (plug_mgr->operator[](i)); const Plugin * plug = (plug_mgr->operator[](i));
if(!plug->size()) if(!plug->size())
continue; continue;
core->con << "Plugin " << plug->getName() << " :" << std::endl; con.print("Plugin %s :\n", plug->getName().c_str());
for (int j = 0; j < plug->size();j++) for (int j = 0; j < plug->size();j++)
{ {
const PluginCommand & pcmd = (plug->operator[](j)); const PluginCommand & pcmd = (plug->operator[](j));
core->con << setw(12) << pcmd.name << "| " << pcmd.description << endl; con << setw(12) << pcmd.name << "| " << pcmd.description << endl;
} }
core->con << endl; con << endl;
} }
} }
else if( command == "" ) else if( command == "" )
@ -184,18 +186,18 @@ int fIOthread(void * iodata)
command_result res = plug_mgr->InvokeCommand(first, parts); command_result res = plug_mgr->InvokeCommand(first, parts);
if(res == CR_NOT_IMPLEMENTED) if(res == CR_NOT_IMPLEMENTED)
{ {
core->con << "Invalid command." << endl; con << "Invalid command." << endl;
clueless_counter ++; clueless_counter ++;
} }
else if(res == CR_FAILURE) else if(res == CR_FAILURE)
{ {
core->con << "ERROR!" << endl; con << "ERROR!" << endl;
} }
} }
} }
if(clueless_counter == 3) if(clueless_counter == 3)
{ {
core->con << "Do 'help' or '?' for the list of available commands." << endl; con << "Do 'help' or '?' for the list of available commands." << endl;
clueless_counter = 0; clueless_counter = 0;
} }
} }

@ -538,6 +538,10 @@ DFhackCExport size_t SDL_strlcpy(char *dst, const char *src, size_t maxlen)
if(!_SDL_strlcpy) if(!_SDL_strlcpy)
{ {
HMODULE realSDLlib = LoadLibrary("SDLreal.dll"); HMODULE realSDLlib = LoadLibrary("SDLreal.dll");
if(!realSDLlib)
{
exit(-111);
}
_SDL_strlcpy = (size_t (*)(char*, const char*, size_t))GetProcAddress(realSDLlib,"SDL_strlcpy"); _SDL_strlcpy = (size_t (*)(char*, const char*, size_t))GetProcAddress(realSDLlib,"SDL_strlcpy");
} }
return _SDL_strlcpy(dst,src,maxlen); return _SDL_strlcpy(dst,src,maxlen);
@ -698,6 +702,7 @@ bool FirstCall()
fprintf(stderr, "Can't load SDLreal.dll\n"); fprintf(stderr, "Can't load SDLreal.dll\n");
return 0; return 0;
} }
fprintf(stderr, "FirstCall()\n");
// stuff for DF // stuff for DF
_SDL_AddTimer = (void*(*)(uint32_t, void*, void*)) GetProcAddress(realSDLlib,"SDL_AddTimer"); _SDL_AddTimer = (void*(*)(uint32_t, void*, void*)) GetProcAddress(realSDLlib,"SDL_AddTimer");
_SDL_CondSignal = (int (*)(SDL::Cond*))GetProcAddress(realSDLlib,"SDL_CondSignal"); _SDL_CondSignal = (int (*)(SDL::Cond*))GetProcAddress(realSDLlib,"SDL_CondSignal");

@ -71,6 +71,7 @@ bool hasEnding (std::string const &fullString, std::string const &ending)
Plugin::Plugin(Core * core, const std::string & file) Plugin::Plugin(Core * core, const std::string & file)
{ {
filename = file; filename = file;
Console & con = core->con;
plugin_lib = 0; plugin_lib = 0;
plugin_init = 0; plugin_init = 0;
plugin_shutdown = 0; plugin_shutdown = 0;
@ -80,20 +81,20 @@ Plugin::Plugin(Core * core, const std::string & file)
DFLibrary * plug = OpenPlugin(file.c_str()); DFLibrary * plug = OpenPlugin(file.c_str());
if(!plug) if(!plug)
{ {
core->con << "Can't load plugin " << filename << endl; con << "Can't load plugin " << filename << endl;
return; return;
} }
const char * (*_PlugName)() =(const char * (*)()) LookupPlugin(plug, "plugin_name"); const char * (*_PlugName)() =(const char * (*)()) LookupPlugin(plug, "plugin_name");
if(!_PlugName) if(!_PlugName)
{ {
core->con << "Plugin " << filename << " has no name." << endl; con << "Plugin " << filename << " has no name." << endl;
ClosePlugin(plug); ClosePlugin(plug);
return; return;
} }
plugin_init = (command_result (*)(Core *, std::vector <PluginCommand> &)) LookupPlugin(plug, "plugin_init"); plugin_init = (command_result (*)(Core *, std::vector <PluginCommand> &)) LookupPlugin(plug, "plugin_init");
if(!plugin_init) if(!plugin_init)
{ {
core->con << "Plugin " << filename << " has no init function." << endl; con << "Plugin " << filename << " has no init function." << endl;
ClosePlugin(plug); ClosePlugin(plug);
return; return;
} }

@ -168,13 +168,13 @@ void VersionInfoFactory::ParseVTable(TiXmlElement* vtable, VersionInfo* mem)
string type = pClassEntry->Value(); string type = pClassEntry->Value();
const char *cstr_name = pClassEntry->Attribute("name"); const char *cstr_name = pClassEntry->Attribute("name");
const char *cstr_vtable = pClassEntry->Attribute("vtable"); const char *cstr_vtable = pClassEntry->Attribute("vtable");
uint32_t vtable = 0; uint32_t vtable_num = 0;
if(cstr_vtable) if(cstr_vtable)
vtable = strtol(cstr_vtable, NULL, 16); vtable_num = strtol(cstr_vtable, NULL, 16);
// it's a simple class // it's a simple class
if(type== "class") if(type== "class")
{ {
mem->setClass(cstr_name, vtable); mem->setClass(cstr_name, vtable_num);
} }
// it's a multi-type class // it's a multi-type class
else if (type == "multiclass") else if (type == "multiclass")
@ -184,7 +184,7 @@ void VersionInfoFactory::ParseVTable(TiXmlElement* vtable, VersionInfo* mem)
uint32_t typeoffset = 0; uint32_t typeoffset = 0;
if(cstr_typeoffset) if(cstr_typeoffset)
typeoffset = strtol(cstr_typeoffset, NULL, 16); typeoffset = strtol(cstr_typeoffset, NULL, 16);
t_class * mclass = mem->setClass(cstr_name, vtable, typeoffset); t_class * mclass = mem->setClass(cstr_name, vtable_num, typeoffset);
// parse class sub-entries // parse class sub-entries
pClassSubEntry = pClassEntry->FirstChildElement(); pClassSubEntry = pClassEntry->FirstChildElement();
for(;pClassSubEntry;pClassSubEntry=pClassSubEntry->NextSiblingElement()) for(;pClassSubEntry;pClassSubEntry=pClassSubEntry->NextSiblingElement())

@ -25,13 +25,11 @@ distribution.
#pragma once #pragma once
#include "dfhack/Pragma.h" #include "dfhack/Pragma.h"
#include "dfhack/Export.h" #include "dfhack/Export.h"
#include "dfhack/extra/stdiostream.h" #include <ostream>
#include <deque>
namespace DFHack namespace DFHack
{ {
class Private; class Private;
class DFHACK_EXPORT Console : public duthomhas::stdiostream class DFHACK_EXPORT Console : public std::ostream
{ {
public: public:
Console(); Console();
@ -69,7 +67,6 @@ namespace DFHack
void prompt_refresh( const std::string & prompt, const std::string & buffer, size_t pos); void prompt_refresh( const std::string & prompt, const std::string & buffer, size_t pos);
int enable_raw(); int enable_raw();
void disable_raw(); void disable_raw();
std::deque <std::string> history;
void history_clear(); void history_clear();
Private * d; Private * d;
}; };

@ -50,7 +50,6 @@ namespace DFHack
class Constructions; class Constructions;
class VersionInfo; class VersionInfo;
class VersionInfoFactory; class VersionInfoFactory;
class Console;
class PluginManager; class PluginManager;
class Core; class Core;
// anon type, pretty much // anon type, pretty much

@ -213,7 +213,7 @@ protected:
std::ios_base::openmode which = std::ios_base::in | std::ios_base::out std::ios_base::openmode which = std::ios_base::in | std::ios_base::out
) { ) {
pushbacks.clear(); pushbacks.clear();
return std::fseek( fp, position, SEEK_SET ) return std::fseek( fp, (long) position, SEEK_SET )
? (-1) ? (-1)
: std::ftell( fp ); : std::ftell( fp );
} }

@ -787,7 +787,7 @@ bool Maps::SortBlockEvents(uint32_t x, uint32_t y, uint32_t z, vector <t_vein *>
if(veins) veins->clear(); if(veins) veins->clear();
if(ices) ices->clear(); if(ices) ices->clear();
if(splatter) splatter->clear(); if(splatter) splatter->clear();
if(grass) splatter->clear(); if(grass) grass->clear();
if(constructions) constructions->clear(); if(constructions) constructions->clear();
Private::t_offsets &off = d->offsets; Private::t_offsets &off = d->offsets;

@ -106,10 +106,10 @@ bool Translation::Start()
for (uint32_t i = 0;i < genericVec.size();i++) for (uint32_t i = 0;i < genericVec.size();i++)
{ {
uint32_t genericNamePtr = genericVec.at(i); uint32_t genericNamePtr = genericVec.at(i);
for(int i=0; i<10;i++) for(int j=0; j<10;i++)
{ {
string word = p->readSTLString (genericNamePtr + i * d->sizeof_string); string word = p->readSTLString (genericNamePtr + j * d->sizeof_string);
translations[i].push_back (word); translations[j].push_back (word);
} }
} }

@ -89,6 +89,7 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
bool showPlants = true; bool showPlants = true;
bool showSlade = true; bool showSlade = true;
bool showTemple = true; bool showTemple = true;
Console & con = c->con;
if(parameters.size() && parameters[0] == "all") if(parameters.size() && parameters[0] == "all")
{ {
showHidden = true; showHidden = true;
@ -98,7 +99,7 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
DFHack::Maps *maps = c->getMaps(); DFHack::Maps *maps = c->getMaps();
if (!maps->Start()) if (!maps->Start())
{ {
c->con << "Cannot get map info!" << std::endl; con << "Cannot get map info!" << std::endl;
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
@ -108,13 +109,13 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
DFHack::Materials *mats = c->getMaterials(); DFHack::Materials *mats = c->getMaterials();
if (!mats->ReadInorganicMaterials()) if (!mats->ReadInorganicMaterials())
{ {
c->con << "Unable to read inorganic material definitons!" << std::endl; con << "Unable to read inorganic material definitons!" << std::endl;
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
if (showPlants && !mats->ReadOrganicMaterials()) if (showPlants && !mats->ReadOrganicMaterials())
{ {
c->con << "Unable to read organic material definitons; plants won't be listed!" << std::endl; con << "Unable to read organic material definitons; plants won't be listed!" << std::endl;
showPlants = false; showPlants = false;
} }
@ -134,21 +135,21 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
if (!(showSlade && maps->ReadGlobalFeatures(globalFeatures))) if (!(showSlade && maps->ReadGlobalFeatures(globalFeatures)))
{ {
c->con << "Unable to read global features; slade won't be listed!" << std::endl; con << "Unable to read global features; slade won't be listed!" << std::endl;
} }
if (!maps->ReadLocalFeatures(localFeatures)) if (!maps->ReadLocalFeatures(localFeatures))
{ {
c->con << "Unable to read local features; adamantine " con << "Unable to read local features; adamantine "
<< (showTemple ? "and demon temples " : "") << (showTemple ? "and demon temples " : "")
<< "won't be listed!" << std::endl; << "won't be listed!" << std::endl;
} }
uint32_t vegCount = 0; uint32_t vegCount = 0;
DFHack::Vegetation *veg = c->getVegetation(); DFHack::Vegetation *veg = c->getVegetation();
if (showPlants && !veg->Start()) if (showPlants && !veg->Start())
{ {
c->con << "Unable to read vegetation; plants won't be listed!" << std::endl; con << "Unable to read vegetation; plants won't be listed!" << std::endl;
} }
for(uint32_t z = 0; z < z_max; z++) for(uint32_t z = 0; z < z_max; z++)
@ -217,7 +218,7 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
if (!info) if (!info)
{ {
c->con << "Bad type: " << type << std::endl; con << "Bad type: " << type << std::endl;
continue; continue;
} }
@ -306,39 +307,39 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
MatMap::const_iterator it; MatMap::const_iterator it;
c->con << "Base materials:" << std::endl; con << "Base materials:" << std::endl;
for (it = baseMats.begin(); it != baseMats.end(); ++it) for (it = baseMats.begin(); it != baseMats.end(); ++it)
{ {
c->con << std::setw(25) << DFHack::TileMaterialString[it->first] << " : " << it->second << std::endl; con << std::setw(25) << DFHack::TileMaterialString[it->first] << " : " << it->second << std::endl;
} }
c->con << std::endl << "Layer materials:" << std::endl; con << std::endl << "Layer materials:" << std::endl;
printMats(c->con, layerMats, mats->inorganic); printMats(con, layerMats, mats->inorganic);
c->con << "Vein materials:" << std::endl; con << "Vein materials:" << std::endl;
printMats(c->con, veinMats, mats->inorganic); printMats(con, veinMats, mats->inorganic);
if (showPlants) if (showPlants)
{ {
c->con << "Shrubs:" << std::endl; con << "Shrubs:" << std::endl;
printMats(c->con, plantMats, mats->organic); printMats(con, plantMats, mats->organic);
c->con << "Wood in trees:" << std::endl; con << "Wood in trees:" << std::endl;
printMats(c->con, treeMats, mats->organic); printMats(con, treeMats, mats->organic);
} }
if (hasAquifer) if (hasAquifer)
{ {
c->con << "Has aquifer" << std::endl; con << "Has aquifer" << std::endl;
} }
if (hasDemonTemple) if (hasDemonTemple)
{ {
c->con << "Has demon temple" << std::endl; con << "Has demon temple" << std::endl;
} }
if (hasLair) if (hasLair)
{ {
c->con << "Has lair" << std::endl; con << "Has lair" << std::endl;
} }
// Cleanup // Cleanup
@ -349,6 +350,6 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
mats->Finish(); mats->Finish();
maps->Finish(); maps->Finish();
c->Resume(); c->Resume();
c->con << std::endl; con << std::endl;
return CR_OK; return CR_OK;
} }

@ -101,10 +101,10 @@ DFhackCExport command_result reveal(DFHack::Core * c, std::vector<std::string> &
{ {
no_hell = false; no_hell = false;
} }
Console & con = c->con;
if(revealed != NOT_REVEALED) if(revealed != NOT_REVEALED)
{ {
c->con << "Map is already revealed or this is a different map." << std::endl; con << "Map is already revealed or this is a different map." << std::endl;
return CR_FAILURE; return CR_FAILURE;
} }
@ -115,20 +115,20 @@ DFhackCExport command_result reveal(DFHack::Core * c, std::vector<std::string> &
World->ReadGameMode(gm); World->ReadGameMode(gm);
if(gm.g_mode != GAMEMODE_DWARF) if(gm.g_mode != GAMEMODE_DWARF)
{ {
c->con << "Only in fortress mode." << std::endl; con << "Only in fortress mode." << std::endl;
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
if(!Maps->Start()) if(!Maps->Start())
{ {
c->con << "Can't init map." << std::endl; con << "Can't init map." << std::endl;
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
if(no_hell && !Maps->StartFeatures()) if(no_hell && !Maps->StartFeatures())
{ {
c->con << "Unable to read local features; can't reveal map safely" << std::endl; con << "Unable to read local features; can't reveal map safely" << std::endl;
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
@ -175,19 +175,19 @@ DFhackCExport command_result reveal(DFHack::Core * c, std::vector<std::string> &
World->SetPauseState(true); World->SetPauseState(true);
} }
c->Resume(); c->Resume();
c->con << "Map revealed." << std::endl; con << "Map revealed." << std::endl;
if(!no_hell) if(!no_hell)
c->con << "Unpausing can unleash the forces of hell, so it has been temporarily disabled." << std::endl; con << "Unpausing can unleash the forces of hell, so it has been temporarily disabled." << std::endl;
c->con << "Run 'unreveal' to revert to previous state." << std::endl; con << "Run 'unreveal' to revert to previous state." << std::endl;
return CR_OK; return CR_OK;
} }
DFhackCExport command_result unreveal(DFHack::Core * c, std::vector<std::string> & params) DFhackCExport command_result unreveal(DFHack::Core * c, std::vector<std::string> & params)
{ {
DFHack::designations40d designations; Console & con = c->con;
if(!revealed) if(!revealed)
{ {
c->con << "There's nothing to revert!" << std::endl; con << "There's nothing to revert!" << std::endl;
return CR_FAILURE; return CR_FAILURE;
} }
c->Suspend(); c->Suspend();
@ -197,14 +197,14 @@ DFhackCExport command_result unreveal(DFHack::Core * c, std::vector<std::string>
World->ReadGameMode(gm); World->ReadGameMode(gm);
if(gm.g_mode != GAMEMODE_DWARF) if(gm.g_mode != GAMEMODE_DWARF)
{ {
c->con << "Only in fortress mode." << std::endl; con << "Only in fortress mode." << std::endl;
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
Maps = c->getMaps(); Maps = c->getMaps();
if(!Maps->Start()) if(!Maps->Start())
{ {
c->con << "Can't init map." << std::endl; con << "Can't init map." << std::endl;
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
@ -214,7 +214,7 @@ DFhackCExport command_result unreveal(DFHack::Core * c, std::vector<std::string>
Maps->getSize(x_max_b,y_max_b,z_max_b); Maps->getSize(x_max_b,y_max_b,z_max_b);
if(x_max != x_max_b || y_max != y_max_b || z_max != z_max_b) if(x_max != x_max_b || y_max != y_max_b || z_max != z_max_b)
{ {
c->con << "The map is not of the same size..." << std::endl; con << "The map is not of the same size..." << std::endl;
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
@ -233,7 +233,7 @@ DFhackCExport command_result unreveal(DFHack::Core * c, std::vector<std::string>
// give back memory. // give back memory.
hidesaved.clear(); hidesaved.clear();
revealed = NOT_REVEALED; revealed = NOT_REVEALED;
c->con << "Map hidden!" << std::endl; con << "Map hidden!" << std::endl;
c->Resume(); c->Resume();
return CR_OK; return CR_OK;
} }

@ -43,13 +43,15 @@ DFhackCExport command_result vdig (Core * c, vector <string> & parameters)
if(parameters.size() && parameters[0]=="x") if(parameters.size() && parameters[0]=="x")
updown = true; updown = true;
Console & con = c->con;
c->Suspend(); c->Suspend();
DFHack::Maps * Maps = c->getMaps(); DFHack::Maps * Maps = c->getMaps();
DFHack::Gui * Gui = c->getGui(); DFHack::Gui * Gui = c->getGui();
// init the map // init the map
if(!Maps->Start()) if(!Maps->Start())
{ {
c->con << "Can't init map. Make sure you have a map loaded in DF.\n"; con << "Can't init map. Make sure you have a map loaded in DF.\n";
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
@ -61,14 +63,14 @@ DFhackCExport command_result vdig (Core * c, vector <string> & parameters)
Gui->getCursorCoords(cx,cy,cz); Gui->getCursorCoords(cx,cy,cz);
while(cx == -30000) while(cx == -30000)
{ {
c->con << "Cursor is not active. Point the cursor at a vein.\n"; con << "Cursor is not active. Point the cursor at a vein.\n";
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
DFHack::DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz); DFHack::DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz);
if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1) if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1)
{ {
c->con << "I won't dig the borders. That would be cheating!\n"; con << "I won't dig the borders. That would be cheating!\n";
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
@ -78,12 +80,12 @@ DFhackCExport command_result vdig (Core * c, vector <string> & parameters)
int16_t veinmat = MCache->veinMaterialAt(xy); int16_t veinmat = MCache->veinMaterialAt(xy);
if( veinmat == -1 ) if( veinmat == -1 )
{ {
c->con << "This tile is not a vein.\n"; con << "This tile is not a vein.\n";
delete MCache; delete MCache;
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
c->con.print("%d/%d/%d tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole); con.print("%d/%d/%d tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole);
stack <DFHack::DFCoord> flood; stack <DFHack::DFCoord> flood;
flood.push(xy); flood.push(xy);

@ -38,6 +38,7 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
DFhackCExport command_result weather (Core * c, vector <string> & parameters) DFhackCExport command_result weather (Core * c, vector <string> & parameters)
{ {
Console & con = c->con;
bool lock = false; bool lock = false;
bool unlock = false; bool unlock = false;
bool snow = false; bool snow = false;
@ -58,7 +59,7 @@ DFhackCExport command_result weather (Core * c, vector <string> & parameters)
} }
if(lock && unlock) if(lock && unlock)
{ {
c->con << "Lock or unlock? DECIDE!" << std::endl; con << "Lock or unlock? DECIDE!" << std::endl;
return CR_FAILURE; return CR_FAILURE;
} }
int cnt = 0; int cnt = 0;
@ -67,7 +68,7 @@ DFhackCExport command_result weather (Core * c, vector <string> & parameters)
cnt += clear; cnt += clear;
if(cnt > 1) if(cnt > 1)
{ {
c->con << "Rain, snow or clear sky? DECIDE!" << std::endl; con << "Rain, snow or clear sky? DECIDE!" << std::endl;
return CR_FAILURE; return CR_FAILURE;
} }
bool something = lock || unlock || rain || snow || clear; bool something = lock || unlock || rain || snow || clear;
@ -75,14 +76,14 @@ DFhackCExport command_result weather (Core * c, vector <string> & parameters)
DFHack::World * w = c->getWorld(); DFHack::World * w = c->getWorld();
if(!w->wmap) if(!w->wmap)
{ {
c->con << "Weather support seems broken :(" << std::endl; con << "Weather support seems broken :(" << std::endl;
c->Resume(); c->Resume();
return CR_FAILURE; return CR_FAILURE;
} }
if(!something) if(!something)
{ {
// paint weather map // paint weather map
c->con << "Weather map (C = clear, R = rain, S = snow):" << std::endl; con << "Weather map (C = clear, R = rain, S = snow):" << std::endl;
for(int y = 0; y<5;y++) for(int y = 0; y<5;y++)
{ {
for(int x = 0; x<5;x++) for(int x = 0; x<5;x++)
@ -90,20 +91,20 @@ DFhackCExport command_result weather (Core * c, vector <string> & parameters)
switch((*w->wmap)[x][y]) switch((*w->wmap)[x][y])
{ {
case DFHack::CLEAR: case DFHack::CLEAR:
c->con << "C "; con << "C ";
break; break;
case DFHack::RAINING: case DFHack::RAINING:
c->con << "R "; con << "R ";
break; break;
case DFHack::SNOWING: case DFHack::SNOWING:
c->con << "S "; con << "S ";
break; break;
default: default:
c->con << (int) (*w->wmap)[x][y] << " "; con << (int) (*w->wmap)[x][y] << " ";
break; break;
} }
} }
c->con << std::endl; con << std::endl;
} }
} }
else else
@ -111,17 +112,17 @@ DFhackCExport command_result weather (Core * c, vector <string> & parameters)
// weather changing action! // weather changing action!
if(rain) if(rain)
{ {
c->con << "Here comes the rain." << std::endl; con << "Here comes the rain." << std::endl;
w->SetCurrentWeather(RAINING); w->SetCurrentWeather(RAINING);
} }
if(snow) if(snow)
{ {
c->con << "Snow everywhere!" << std::endl; con << "Snow everywhere!" << std::endl;
w->SetCurrentWeather(SNOWING); w->SetCurrentWeather(SNOWING);
} }
if(clear) if(clear)
{ {
c->con << "Suddenly, sunny weather!" << std::endl; con << "Suddenly, sunny weather!" << std::endl;
w->SetCurrentWeather(CLEAR); w->SetCurrentWeather(CLEAR);
} }
// FIXME: weather lock needs map ID to work reliably... needs to be implemented. // FIXME: weather lock needs map ID to work reliably... needs to be implemented.