Conflicts:
	depends/clsocket
develop
Petr Mrázek 2012-06-14 00:00:36 +02:00
commit 52f9fe4a6a
24 changed files with 1370 additions and 664 deletions

@ -117,7 +117,9 @@ ENDIF()
ADD_DEFINITIONS(-DPROTOBUF_USE_DLLS)
ADD_DEFINITIONS(-DLUA_BUILD_AS_DLL)
if(UNIX)
if(APPLE)
add_definitions(-D_DARWIN)
elseif(UNIX)
add_definitions(-D_LINUX)
elseif(WIN32)
add_definitions(-DWIN32)
@ -137,6 +139,9 @@ include_directories(depends/tinyxml)
include_directories(depends/tthread)
include_directories(${ZLIB_INCLUDE_DIRS})
include_directories(depends/clsocket/src)
if(APPLE)
include_directories(${CMAKE_INSTALL_PREFIX}/libs/SDL.framework/Headers)
endif()
add_subdirectory(depends)
@ -155,7 +160,11 @@ endif()
# Packaging with CPack!
IF(UNIX)
SET(CPACK_GENERATOR "TGZ")
if(APPLE)
SET(CPACK_GENERATOR "ZIP")
else()
SET(CPACK_GENERATOR "TGZ")
endif()
ELSEIF(WIN32)
SET(CPACK_GENERATOR "ZIP")
ENDIF()

@ -36,9 +36,6 @@ include/MiscUtils.h
include/Module.h
include/Pragma.h
include/MemAccess.h
include/SDL_events.h
include/SDL_keyboard.h
include/SDL_keysym.h
include/TileTypes.h
include/Types.h
include/VersionInfo.h
@ -92,6 +89,13 @@ PlugLoad-linux.cpp
Process-linux.cpp
)
SET(MAIN_SOURCES_DARWIN
Console-darwin.cpp
PlugLoad-darwin.cpp
Process-darwin.cpp
Hooks-darwin.cpp
)
SET(MAIN_SOURCES_LINUX_EGGY
Console-linux.cpp
Hooks-egg.cpp
@ -158,6 +162,8 @@ IF(UNIX)
OPTION(BUILD_EGGY "Make DFHack strangely egg-shaped." OFF)
IF(BUILD_EGGY)
LIST(APPEND PROJECT_SOURCES ${MAIN_SOURCES_LINUX_EGGY})
ELSEIF(APPLE)
LIST(APPEND PROJECT_SOURCES ${MAIN_SOURCES_DARWIN})
ELSE()
LIST(APPEND PROJECT_SOURCES ${MAIN_SOURCES_LINUX})
ENDIF()
@ -212,7 +218,6 @@ ELSE(WIN32)
PROPERTIES COMPILE_FLAGS "/O1 /bigobj")
ENDIF()
# Compilation
ADD_DEFINITIONS(-DBUILD_DFHACK_LIB)
@ -225,6 +230,9 @@ ENDIF()
IF(UNIX)
SET(PROJECT_LIBS rt dl dfhack-md5 dfhack-tinyxml dfhack-tinythread)
IF(APPLE)
SET(PROJECT_LIBS dl dfhack-md5 dfhack-tinyxml dfhack-tinythread)
ENDIF()
ELSE(WIN32)
#FIXME: do we really need psapi?
SET(PROJECT_LIBS psapi dfhack-tinyxml dfhack-tinythread)
@ -257,6 +265,14 @@ ENDIF()
#effectively disables debug builds...
SET_TARGET_PROPERTIES(dfhack PROPERTIES DEBUG_POSTFIX "-debug" )
IF(APPLE)
SET(SDL_LIBRARY ${CMAKE_INSTALL_PREFIX}/libs/SDL.framework)
TARGET_LINK_LIBRARIES(dfhack ${SDL_LIBRARY})
# TARGET_LINK_LIBRARIES(dfhack /usr/lib/libc++.dylib)
SET_TARGET_PROPERTIES(dfhack PROPERTIES VERSION 1.0.0)
SET_TARGET_PROPERTIES(dfhack PROPERTIES SOVERSION 1.0.0)
ENDIF()
TARGET_LINK_LIBRARIES(dfhack protobuf-lite clsocket lua ${PROJECT_LIBS})
SET_TARGET_PROPERTIES(dfhack PROPERTIES LINK_INTERFACE_LIBRARIES "")
@ -264,11 +280,18 @@ TARGET_LINK_LIBRARIES(dfhack-client protobuf-lite clsocket)
TARGET_LINK_LIBRARIES(dfhack-run dfhack-client)
IF(UNIX)
# On linux, copy our version of the df launch script which sets LD_PRELOAD
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/linux/dfhack
if (APPLE)
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/darwin/dfhack
DESTINATION .)
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/darwin/dfhack-run
DESTINATION .)
else()
# On linux, copy our version of the df launch script which sets LD_PRELOAD
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/linux/dfhack
DESTINATION .)
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/linux/dfhack-run
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/linux/dfhack-run
DESTINATION .)
endif()
ELSE()
if(NOT BUILD_EGGY)
# On windows, copy the renamed SDL so DF can still run.

@ -0,0 +1,773 @@
/*
https://github.com/peterix/dfhack
A thread-safe logging console with a line editor.
Based on linenoise:
linenoise -- guerrilla line editing library against the idea that a
line editing lib needs to be 20,000 lines of C code.
You can find the latest source code at:
http://github.com/antirez/linenoise
Does a number of crazy assumptions that happen to be true in 99.9999% of
the 2010 UNIX computers around.
------------------------------------------------------------------------
Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
Copyright (c) 2011, Petr Mrázek <peterix@gmail.com>
All rights reserved.
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.
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 <cstdio>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string.h>
#include <string>
#include <stdarg.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <errno.h>
#include <deque>
// George Vulov for MacOSX
#ifndef __LINUX__
#define TEMP_FAILURE_RETRY(expr) \
({ long int _res; \
do _res = (long int) (expr); \
while (_res == -1L && errno == EINTR); \
_res; })
#endif
#include "Console.h"
#include "Hooks.h"
using namespace DFHack;
#include "tinythread.h"
using namespace tthread;
static int isUnsupportedTerm(void)
{
static const char *unsupported_term[] = {"dumb","cons25",NULL};
char *term = getenv("TERM");
int j;
if (term == NULL) return 0;
for (j = 0; unsupported_term[j]; j++)
if (!strcasecmp(term,unsupported_term[j])) return 1;
return 0;
}
const char * ANSI_CLS = "\033[2J";
const char * ANSI_BLACK = "\033[22;30m";
const char * ANSI_RED = "\033[22;31m";
const char * ANSI_GREEN = "\033[22;32m";
const char * ANSI_BROWN = "\033[22;33m";
const char * ANSI_BLUE = "\033[22;34m";
const char * ANSI_MAGENTA = "\033[22;35m";
const char * ANSI_CYAN = "\033[22;36m";
const char * ANSI_GREY = "\033[22;37m";
const char * ANSI_DARKGREY = "\033[01;30m";
const char * ANSI_LIGHTRED = "\033[01;31m";
const char * ANSI_LIGHTGREEN = "\033[01;32m";
const char * ANSI_YELLOW = "\033[01;33m";
const char * ANSI_LIGHTBLUE = "\033[01;34m";
const char * ANSI_LIGHTMAGENTA = "\033[01;35m";
const char * ANSI_LIGHTCYAN = "\033[01;36m";
const char * ANSI_WHITE = "\033[01;37m";
const char * RESETCOLOR = "\033[0m";
const char * getANSIColor(const int c)
{
switch (c)
{
case -1: return RESETCOLOR; // HACK! :P
case 0 : return ANSI_BLACK;
case 1 : return ANSI_BLUE; // non-ANSI
case 2 : return ANSI_GREEN;
case 3 : return ANSI_CYAN; // non-ANSI
case 4 : return ANSI_RED; // non-ANSI
case 5 : return ANSI_MAGENTA;
case 6 : return ANSI_BROWN;
case 7 : return ANSI_GREY;
case 8 : return ANSI_DARKGREY;
case 9 : return ANSI_LIGHTBLUE; // non-ANSI
case 10: return ANSI_LIGHTGREEN;
case 11: return ANSI_LIGHTCYAN; // non-ANSI;
case 12: return ANSI_LIGHTRED; // non-ANSI;
case 13: return ANSI_LIGHTMAGENTA;
case 14: return ANSI_YELLOW; // non-ANSI
case 15: return ANSI_WHITE;
default: return "";
}
}
namespace DFHack
{
class Private
{
public:
Private()
{
dfout_C = NULL;
rawmode = false;
in_batch = false;
supported_terminal = false;
state = con_unclaimed;
};
virtual ~Private()
{
//sync();
}
private:
bool read_char(unsigned char & out)
{
FD_ZERO(&descriptor_set);
FD_SET(STDIN_FILENO, &descriptor_set);
FD_SET(exit_pipe[0], &descriptor_set);
int ret = TEMP_FAILURE_RETRY(
select (FD_SETSIZE,&descriptor_set, NULL, NULL, NULL)
);
if(ret == -1)
return false;
if (FD_ISSET(exit_pipe[0], &descriptor_set))
return false;
if (FD_ISSET(STDIN_FILENO, &descriptor_set))
{
// read byte from stdin
ret = TEMP_FAILURE_RETRY(
read(STDIN_FILENO, &out, 1)
);
if(ret == -1)
return false;
return true;
}
return false;
}
public:
void print(const char *data)
{
fputs(data, dfout_C);
}
void print_text(color_ostream::color_value clr, const std::string &chunk)
{
if(!in_batch && state == con_lineedit)
{
disable_raw();
fprintf(dfout_C,"\x1b[1G");
fprintf(dfout_C,"\x1b[0K");
color(clr);
print(chunk.c_str());
reset_color();
enable_raw();
prompt_refresh();
}
else
{
color(clr);
print(chunk.c_str());
}
}
void begin_batch()
{
assert(!in_batch);
in_batch = true;
if (state == con_lineedit)
{
disable_raw();
fprintf(dfout_C,"\x1b[1G");
fprintf(dfout_C,"\x1b[0K");
}
}
void end_batch()
{
assert(in_batch);
flush();
in_batch = false;
if (state == con_lineedit)
{
reset_color();
enable_raw();
prompt_refresh();
}
}
void flush()
{
if (!rawmode)
fflush(dfout_C);
}
/// Clear the console, along with its scrollback
void clear()
{
if(rawmode)
{
const char * clr = "\033c\033[3J\033[H";
::write(STDIN_FILENO,clr,strlen(clr));
}
else
{
print("\033c\033[3J\033[H");
fflush(dfout_C);
}
}
/// Position cursor at x,y. 1,1 = top left corner
void gotoxy(int x, int y)
{
char tmp[64];
sprintf(tmp,"\033[%d;%dH", y,x);
print(tmp);
}
/// Set color (ANSI color number)
void color(Console::color_value index)
{
if(!rawmode)
fprintf(dfout_C,getANSIColor(index));
else
{
const char * colstr = getANSIColor(index);
int lstr = strlen(colstr);
::write(STDIN_FILENO,colstr,lstr);
}
}
/// Reset color to default
void reset_color(void)
{
color(Console::COLOR_RESET);
if(!rawmode)
fflush(dfout_C);
}
/// Enable or disable the caret/cursor
void cursor(bool enable = true)
{
if(enable)
print("\033[?25h");
else
print("\033[?25l");
}
/// Waits given number of milliseconds before continuing.
void msleep(unsigned int msec);
/// get the current number of columns
int get_columns(void)
{
winsize ws;
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) return 80;
return ws.ws_col;
}
/// get the current number of rows
int get_rows(void)
{
winsize ws;
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) return 25;
return ws.ws_row;
}
/// beep. maybe?
//void beep (void);
/// A simple line edit (raw mode)
int lineedit(const std::string& prompt, std::string& output, recursive_mutex * lock, CommandHistory & ch)
{
output.clear();
reset_color();
this->prompt = prompt;
if (!supported_terminal)
{
print(prompt.c_str());
fflush(dfout_C);
// FIXME: what do we do here???
//SDL_recursive_mutexV(lock);
std::getline(std::cin, output);
//SDL_recursive_mutexP(lock);
return output.size();
}
else
{
int count;
if (enable_raw() == -1) return 0;
if(state == con_lineedit)
return -1;
state = con_lineedit;
count = prompt_loop(lock,ch);
state = con_unclaimed;
disable_raw();
print("\n");
if(count != -1)
{
output = raw_buffer;
}
return count;
}
}
int enable_raw()
{
struct termios raw;
if (!supported_terminal)
return -1;
if (tcgetattr(STDIN_FILENO,&orig_termios) == -1)
return -1;
raw = orig_termios; //modify the original mode
// input modes: no break, no CR to NL, no parity check, no strip char,
// no start/stop output control.
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
// output modes - disable post processing
raw.c_oflag &= ~(OPOST);
// control modes - set 8 bit chars
raw.c_cflag |= (CS8);
// local modes - choing off, canonical off, no extended functions,
// no signal chars (^Z,^C)
#ifdef CONSOLE_NO_CATCH
raw.c_lflag &= ~( ECHO | ICANON | IEXTEN );
#else
raw.c_lflag &= ~( ECHO | ICANON | IEXTEN | ISIG );
#endif
// control chars - set return condition: min number of bytes and timer.
// We want read to return every single byte, without timeout.
raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0;// 1 byte, no timer
// put terminal in raw mode after flushing
if (tcsetattr(STDIN_FILENO,TCSAFLUSH,&raw) < 0)
return -1;
rawmode = 1;
return 0;
}
void disable_raw()
{
/* Don't even check the return value as it's too late. */
if (rawmode && tcsetattr(STDIN_FILENO,TCSAFLUSH,&orig_termios) != -1)
rawmode = 0;
}
void prompt_refresh()
{
char seq[64];
int cols = get_columns();
int plen = prompt.size();
const char * buf = raw_buffer.c_str();
int len = raw_buffer.size();
int cooked_cursor = raw_cursor;
// Use math! This is silly.
while((plen+cooked_cursor) >= cols)
{
buf++;
len--;
cooked_cursor--;
}
while (plen+len > cols)
{
len--;
}
/* Cursor to left edge */
snprintf(seq,64,"\x1b[1G");
if (::write(STDIN_FILENO,seq,strlen(seq)) == -1) return;
/* Write the prompt and the current buffer content */
if (::write(STDIN_FILENO,prompt.c_str(),plen) == -1) return;
if (::write(STDIN_FILENO,buf,len) == -1) return;
/* Erase to right */
snprintf(seq,64,"\x1b[0K");
if (::write(STDIN_FILENO,seq,strlen(seq)) == -1) return;
/* Move cursor to original position. */
snprintf(seq,64,"\x1b[1G\x1b[%dC", (int)(cooked_cursor+plen));
if (::write(STDIN_FILENO,seq,strlen(seq)) == -1) return;
}
int prompt_loop(recursive_mutex * lock, CommandHistory & history)
{
int fd = STDIN_FILENO;
size_t plen = prompt.size();
int history_index = 0;
raw_buffer.clear();
raw_cursor = 0;
/* The latest history entry is always our current buffer, that
* initially is just an empty string. */
const std::string empty;
history.add(empty);
if (::write(fd,prompt.c_str(),prompt.size()) == -1) return -1;
while(1)
{
unsigned char c;
int isok;
unsigned char seq[2], seq2;
lock->unlock();
if(!read_char(c))
{
lock->lock();
return -2;
}
lock->lock();
/* Only autocomplete when the callback is set. It returns < 0 when
* there was an error reading from fd. Otherwise it will return the
* character that should be handled next. */
if (c == 9)
{
/*
if( completionCallback != NULL) {
c = completeLine(fd,prompt,buf,buflen,&len,&pos,cols);
// Return on errors
if (c < 0) return len;
// Read next character when 0
if (c == 0) continue;
}
else
{
// ignore tab
continue;
}
*/
// just ignore tabs
continue;
}
switch(c)
{
case 13: // enter
history.remove();
return raw_buffer.size();
case 3: // ctrl-c
errno = EAGAIN;
return -1;
case 127: // backspace
case 8: // ctrl-h
if (raw_cursor > 0 && raw_buffer.size() > 0)
{
raw_buffer.erase(raw_cursor-1,1);
raw_cursor--;
prompt_refresh();
}
break;
case 27: // escape sequence
lock->unlock();
if(!read_char(seq[0]) || !read_char(seq[1]))
{
lock->lock();
return -2;
}
lock->lock();
if(seq[0] == '[')
{
if (seq[1] == 'D')
{
left_arrow:
if (raw_cursor > 0)
{
raw_cursor--;
prompt_refresh();
}
}
else if ( seq[1] == 'C')
{
right_arrow:
/* right arrow */
if (size_t(raw_cursor) != raw_buffer.size())
{
raw_cursor++;
prompt_refresh();
}
}
else if (seq[1] == 'A' || seq[1] == 'B')
{
/* up and down arrow: history */
if (history.size() > 1)
{
/* Update the current history entry before to
* overwrite it with tne next one. */
history[history_index] = raw_buffer;
/* Show the new entry */
history_index += (seq[1] == 'A') ? 1 : -1;
if (history_index < 0)
{
history_index = 0;
break;
}
else if (size_t(history_index) >= history.size())
{
history_index = history.size()-1;
break;
}
raw_buffer = history[history_index];
raw_cursor = raw_buffer.size();
prompt_refresh();
}
}
else if(seq[1] == 'H')
{
// home
raw_cursor = 0;
prompt_refresh();
}
else if(seq[1] == 'F')
{
// end
raw_cursor = raw_buffer.size();
prompt_refresh();
}
else if (seq[1] > '0' && seq[1] < '7')
{
// extended escape
lock->unlock();
if(!read_char(seq2))
{
lock->lock();
return -2;
}
lock->lock();
if (seq[1] == '3' && seq2 == '~' )
{
// delete
if (raw_buffer.size() > 0 && size_t(raw_cursor) < raw_buffer.size())
{
raw_buffer.erase(raw_cursor,1);
prompt_refresh();
}
}
}
}
break;
default:
if (raw_buffer.size() == size_t(raw_cursor))
{
raw_buffer.append(1,c);
raw_cursor++;
if (plen+raw_buffer.size() < size_t(get_columns()))
{
/* Avoid a full update of the line in the
* trivial case. */
if (::write(fd,&c,1) == -1) return -1;
}
else
{
prompt_refresh();
}
}
else
{
raw_buffer.insert(raw_cursor,1,c);
raw_cursor++;
prompt_refresh();
}
break;
case 21: // Ctrl+u, delete the whole line.
raw_buffer.clear();
raw_cursor = 0;
prompt_refresh();
break;
case 11: // Ctrl+k, delete from current to end of line.
raw_buffer.erase(raw_cursor);
prompt_refresh();
break;
case 1: // Ctrl+a, go to the start of the line
raw_cursor = 0;
prompt_refresh();
break;
case 5: // ctrl+e, go to the end of the line
raw_cursor = raw_buffer.size();
prompt_refresh();
break;
case 12: // ctrl+l, clear screen
clear();
prompt_refresh();
}
}
return raw_buffer.size();
}
FILE * dfout_C;
bool supported_terminal;
// state variables
bool rawmode; // is raw mode active?
termios orig_termios; // saved/restored by raw mode
// current state
enum console_state
{
con_unclaimed,
con_lineedit
} state;
bool in_batch;
std::string prompt; // current prompt string
std::string raw_buffer; // current raw mode buffer
int raw_cursor; // cursor position in the buffer
// thread exit mechanism
int exit_pipe[2];
fd_set descriptor_set;
};
}
Console::Console()
{
d = 0;
inited = false;
// we can't create the mutex at this time. the SDL functions aren't hooked yet.
wlock = new recursive_mutex();
}
Console::~Console()
{
if(inited)
shutdown();
if(wlock)
delete wlock;
if(d)
delete d;
}
bool Console::init(bool sharing)
{
if(sharing)
{
inited = false;
return false;
}
freopen("stdout.log", "w", stdout);
d = new Private();
// make our own weird streams so our IO isn't redirected
d->dfout_C = fopen("/dev/tty", "w");
std::cin.tie(this);
clear();
d->supported_terminal = !isUnsupportedTerm() && isatty(STDIN_FILENO);
// init the exit mechanism
pipe(d->exit_pipe);
FD_ZERO(&d->descriptor_set);
FD_SET(STDIN_FILENO, &d->descriptor_set);
FD_SET(d->exit_pipe[0], &d->descriptor_set);
inited = true;
return true;
}
bool Console::shutdown(void)
{
if(!d)
return true;
lock_guard <recursive_mutex> g(*wlock);
if(d->rawmode)
d->disable_raw();
d->print("\n");
inited = false;
// kill the thing
close(d->exit_pipe[1]);
return true;
}
void Console::begin_batch()
{
//color_ostream::begin_batch();
wlock->lock();
if (inited)
d->begin_batch();
}
void Console::end_batch()
{
if (inited)
d->end_batch();
wlock->unlock();
}
void Console::flush_proxy()
{
lock_guard <recursive_mutex> g(*wlock);
if (inited)
d->flush();
}
void Console::add_text(color_value color, const std::string &text)
{
lock_guard <recursive_mutex> g(*wlock);
if (inited)
d->print_text(color, text);
}
int Console::get_columns(void)
{
lock_guard <recursive_mutex> g(*wlock);
int ret = -1;
if(inited)
ret = d->get_columns();
return ret;
}
int Console::get_rows(void)
{
lock_guard <recursive_mutex> g(*wlock);
int ret = -1;
if(inited)
ret = d->get_rows();
return ret;
}
void Console::clear()
{
lock_guard <recursive_mutex> g(*wlock);
if(inited)
d->clear();
}
void Console::gotoxy(int x, int y)
{
lock_guard <recursive_mutex> g(*wlock);
if(inited)
d->gotoxy(x,y);
}
void Console::cursor(bool enable)
{
lock_guard <recursive_mutex> g(*wlock);
if(inited)
d->cursor(enable);
}
int Console::lineedit(const std::string & prompt, std::string & output, CommandHistory & ch)
{
lock_guard <recursive_mutex> g(*wlock);
int ret = -2;
if(inited)
ret = d->lineedit(prompt,output,wlock,ch);
return ret;
}
void Console::msleep (unsigned int msec)
{
if (msec > 1000) sleep(msec/1000000);
usleep((msec % 1000000) * 1000);
}

@ -60,6 +60,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <errno.h>
#include <deque>
// George Vulov for MacOSX
#ifndef __LINUX__
#define TEMP_FAILURE_RETRY(expr) \
({ long int _res; \
do _res = (long int) (expr); \
while (_res == -1L && errno == EINTR); \
_res; })
#endif
#include "Console.h"
#include "Hooks.h"
using namespace DFHack;

@ -204,7 +204,7 @@ struct sortable
static std::string getLuaHelp(std::string path)
{
ifstream script(path);
ifstream script(path.c_str());
if (script.good())
{
@ -237,7 +237,7 @@ static std::map<string,string> listLuaScripts(std::string path)
static bool fileExists(std::string path)
{
ifstream script(path);
ifstream script(path.c_str());
return script.good();
}
@ -279,21 +279,29 @@ static command_result runLuaScript(color_ostream &out, std::string filename, vec
command_result Core::runCommand(color_ostream &out, const std::string &command)
{
fprintf(stderr,"Inside runCommand");
fprintf(stderr," with command %s\n",command.c_str());
if (!command.empty())
{
fprintf(stderr,"Command is not empty, tokenizing\n");
vector <string> parts;
Core::cheap_tokenise(command,parts);
fprintf(stderr,"Tokenized, got %d parts\n",parts.size());
if(parts.size() == 0)
return CR_NOT_IMPLEMENTED;
string first = parts[0];
fprintf(stderr,"Erasing beginning\n");
parts.erase(parts.begin());
fprintf(stderr,"I think we're about there\n");
if (first[0] == '#')
return CR_OK;
cerr << "Invoking: " << command << endl;
fprintf(stderr,"Returning with the next recursion\n");
return runCommand(out, first, parts);
}
else
@ -628,7 +636,7 @@ bool Core::loadScriptFile(color_ostream &out, string fname, bool silent)
{
if(!silent)
out << "Loading script at " << fname << std::endl;
ifstream script(fname);
ifstream script(fname.c_str());
if (script.good())
{
string command;
@ -674,6 +682,7 @@ void fIOthread(void * iodata)
{
string command = "";
int ret = con.lineedit("[DFHack]# ",command, main_history);
fprintf(stderr,"Command: [%s]\n",command.c_str());
if(ret == -2)
{
cerr << "Console is shutting down properly." << endl;
@ -687,9 +696,13 @@ void fIOthread(void * iodata)
else if(ret)
{
// a proper, non-empty command was entered
fprintf(stderr,"Adding command to history\n");
main_history.add(command);
fprintf(stderr,"Saving history\n");
main_history.save("dfhack.history");
}
fprintf(stderr,"Running command\n");
auto rv = core->runCommand(con, command);
@ -1205,25 +1218,25 @@ bool Core::ncurses_wgetch(int in, int & out)
return true;
}
int Core::UnicodeAwareSym(const SDL::KeyboardEvent& ke)
int Core::UnicodeAwareSym(const SDL_KeyboardEvent& ke)
{
// Assume keyboard layouts don't change the order of numbers:
if( '0' <= ke.ksym.sym && ke.ksym.sym <= '9') return ke.ksym.sym;
if(SDL::K_F1 <= ke.ksym.sym && ke.ksym.sym <= SDL::K_F12) return ke.ksym.sym;
if( '0' <= ke.keysym.sym && ke.keysym.sym <= '9') return ke.keysym.sym;
if(SDLK_F1 <= ke.keysym.sym && ke.keysym.sym <= SDLK_F12) return ke.keysym.sym;
// These keys are mapped to the same control codes as Ctrl-?
switch (ke.ksym.sym) {
case SDL::K_RETURN:
case SDL::K_KP_ENTER:
case SDL::K_TAB:
case SDL::K_ESCAPE:
case SDL::K_DELETE:
return ke.ksym.sym;
switch (ke.keysym.sym) {
case SDLK_RETURN:
case SDLK_KP_ENTER:
case SDLK_TAB:
case SDLK_ESCAPE:
case SDLK_DELETE:
return ke.keysym.sym;
default:
break;
}
int unicode = ke.ksym.unicode;
int unicode = ke.keysym.unicode;
// convert Ctrl characters to their 0x40-0x5F counterparts:
if (unicode < ' ')
@ -1253,28 +1266,28 @@ int Core::UnicodeAwareSym(const SDL::KeyboardEvent& ke)
}
//MEMO: return false if event is consumed
int Core::SDL_Event(SDL::Event* ev)
int Core::DFH_SDL_Event(SDL_Event* ev)
{
// do NOT process events before we are ready.
if(!started) return true;
if(!ev)
return true;
if(ev && (ev->type == SDL::ET_KEYDOWN || ev->type == SDL::ET_KEYUP))
if(ev && (ev->type == SDL_KEYDOWN || ev->type == SDL_KEYUP))
{
SDL::KeyboardEvent * ke = (SDL::KeyboardEvent *)ev;
SDL_KeyboardEvent * ke = (SDL_KeyboardEvent *)ev;
if(ke->state == SDL::BTN_PRESSED && !hotkey_states[ke->ksym.sym])
if(ke->state == SDL_PRESSED && !hotkey_states[ke->keysym.sym])
{
hotkey_states[ke->ksym.sym] = true;
hotkey_states[ke->keysym.sym] = true;
int mod = 0;
if (ke->ksym.mod & SDL::KMOD_SHIFT) mod |= 1;
if (ke->ksym.mod & SDL::KMOD_CTRL) mod |= 2;
if (ke->ksym.mod & SDL::KMOD_ALT) mod |= 4;
if (ke->keysym.mod & KMOD_SHIFT) mod |= 1;
if (ke->keysym.mod & KMOD_CTRL) mod |= 2;
if (ke->keysym.mod & KMOD_ALT) mod |= 4;
// Use unicode so Windows gives the correct value for the
// user's Input Language
if((ke->ksym.unicode & 0xff80) == 0)
if((ke->keysym.unicode & 0xff80) == 0)
{
int key = UnicodeAwareSym(*ke);
SelectHotkey(key, mod);
@ -1282,12 +1295,12 @@ int Core::SDL_Event(SDL::Event* ev)
else
{
// Pretend non-ascii characters don't happen:
SelectHotkey(ke->ksym.sym, mod);
SelectHotkey(ke->keysym.sym, mod);
}
}
else if(ke->state == SDL::BTN_RELEASED)
else if(ke->state == SDL_RELEASED)
{
hotkey_states[ke->ksym.sym] = false;
hotkey_states[ke->keysym.sym] = false;
}
}
return true;
@ -1304,8 +1317,8 @@ bool Core::SelectHotkey(int sym, int modifiers)
while (screen->child)
screen = screen->child;
if (sym == SDL::K_KP_ENTER)
sym = SDL::K_RETURN;
if (sym == SDLK_KP_ENTER)
sym = SDLK_RETURN;
std::string cmd;
@ -1328,7 +1341,7 @@ bool Core::SelectHotkey(int sym, int modifiers)
if (cmd.empty()) {
// Check the hotkey keybindings
int idx = sym - SDL::K_F1;
int idx = sym - SDLK_F1;
if(idx >= 0 && idx < 8)
{
if (modifiers & 1)
@ -1383,13 +1396,13 @@ static bool parseKeySpec(std::string keyspec, int *psym, int *pmod, std::string
}
if (keyspec.size() == 1 && keyspec[0] >= 'A' && keyspec[0] <= 'Z') {
*psym = SDL::K_a + (keyspec[0]-'A');
*psym = SDLK_a + (keyspec[0]-'A');
return true;
} else if (keyspec.size() == 2 && keyspec[0] == 'F' && keyspec[1] >= '1' && keyspec[1] <= '9') {
*psym = SDL::K_F1 + (keyspec[1]-'1');
*psym = SDLK_F1 + (keyspec[1]-'1');
return true;
} else if (keyspec == "Enter") {
*psym = SDL::K_RETURN;
*psym = SDLK_RETURN;
return true;
} else
return false;

@ -0,0 +1,163 @@
/*
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.
*/
#include <stdio.h>
#include <dlfcn.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <vector>
#include <string>
#include <map>
/*typedef struct interpose_s
{
void *new_func;
void *orig_func;
} interpose_t;*/
#include "DFHack.h"
#include "Core.h"
#include "Hooks.h"
#include <iostream>
/*static const interpose_t interposers[] __attribute__ ((section("__DATA, __interpose"))) =
{
{ (void *)DFH_SDL_Init, (void *)SDL_Init },
{ (void *)DFH_SDL_PollEvent, (void *)SDL_PollEvent },
{ (void *)DFH_SDL_Quit, (void *)SDL_Quit },
{ (void *)DFH_SDL_NumJoysticks, (void *)SDL_NumJoysticks },
};*/
/*******************************************************************************
* SDL part starts here *
*******************************************************************************/
// hook - called for each game tick (or more often)
DFhackCExport int SDL_NumJoysticks(void)
{
DFHack::Core & c = DFHack::Core::getInstance();
return c.Update();
}
// hook - called at program exit
static void (*_SDL_Quit)(void) = 0;
DFhackCExport void SDL_Quit(void)
{
DFHack::Core & c = DFHack::Core::getInstance();
c.Shutdown();
/*if(_SDL_Quit)
{
_SDL_Quit();
}*/
_SDL_Quit();
}
// called by DF to check input events
static int (*_SDL_PollEvent)(SDL_Event* event) = 0;
DFhackCExport int SDL_PollEvent(SDL_Event* event)
{
pollevent_again:
// if SDL returns 0 here, it means there are no more events. return 0
int orig_return = _SDL_PollEvent(event);
if(!orig_return)
return 0;
// otherwise we have an event to filter
else if( event != 0 )
{
DFHack::Core & c = DFHack::Core::getInstance();
// if we consume the event, ask SDL for more.
if(!c.DFH_SDL_Event(event))
goto pollevent_again;
}
return orig_return;
}
struct WINDOW;
DFhackCExport int wgetch(WINDOW *win)
{
static int (*_wgetch)(WINDOW * win) = (int (*)( WINDOW * )) dlsym(RTLD_NEXT, "wgetch");
if(!_wgetch)
{
exit(EXIT_FAILURE);
}
DFHack::Core & c = DFHack::Core::getInstance();
wgetch_again:
int in = _wgetch(win);
int out;
if(c.ncurses_wgetch(in, out))
{
// not consumed, give to DF
return out;
}
else
{
// consumed, repeat
goto wgetch_again;
}
}
// hook - called at program start, initialize some stuffs we'll use later
static int (*_SDL_Init)(uint32_t flags) = 0;
DFhackCExport int SDL_Init(uint32_t flags)
{
// reroute stderr
fprintf(stderr,"dfhack: attempting to hook in\n");
freopen("stderr.log", "w", stderr);
// we don't reroute stdout until we figure out if this should be done at all
// See: Console-linux.cpp
// find real functions
fprintf(stderr,"dfhack: saving real SDL functions\n");
_SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init");
_SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit");
_SDL_PollEvent = (int (*)(SDL_Event*))dlsym(RTLD_NEXT,"SDL_PollEvent");
fprintf(stderr,"dfhack: saved real SDL functions\n");
// check if we got them
if(_SDL_Init && _SDL_Quit && _SDL_PollEvent)
{
fprintf(stderr,"dfhack: hooking successful\n");
}
else
{
// bail, this would be a disaster otherwise
fprintf(stderr,"dfhack: something went horribly wrong\n");
exit(1);
}
DFHack::Core & c = DFHack::Core::getInstance();
//c.Init();
int ret = _SDL_Init(flags);
return ret;
}

@ -65,13 +65,13 @@ DFhackCExport int egg_prerender(void)
}
// hook - called for each SDL event, returns 0 when the event has been consumed. 1 otherwise
DFhackCExport int egg_sdl_event(SDL::Event* event)
DFhackCExport int egg_sdl_event(SDL_Event* event)
{
// if the event is valid, intercept
if( event != 0 )
{
DFHack::Core & c = DFHack::Core::getInstance();
return c.SDL_Event(event);
return c.DFH_SDL_Event(event);
}
return true;
}

@ -431,7 +431,7 @@ DFhackCExport int SDL_PollEvent(SDL::Event* event)
{
DFHack::Core & c = DFHack::Core::getInstance();
// if we consume the event, ask SDL for more.
if(!c.SDL_Event(event))
if(!c.DFH_SDL_Event(event))
goto pollevent_again;
}
return orig_return;

@ -0,0 +1,12 @@
/*
* MacPool.h
* Handles creation and destruction of autorelease pool for DFHack on the Mac
*/
#ifndef MACPOOL_H
#define MACPOOL_H
int create_pool();
int destroy_pool();
#endif

@ -0,0 +1,22 @@
/*
* MacPool.m
*
*/
#import <Foundation/Foundation.h>
#import "MacPool.h"
NSAutoreleasePool *thePool;
int create_pool() {
fprintf(stderr,"Creating autorelease pool\n");
thePool = [[NSAutoreleasePool alloc] init];
return 1;
}
int destroy_pool() {
fprintf(stderr,"Draining and releasing autorelease pool\n");
[thePool drain];
[thePool release];
return 0;
}

@ -0,0 +1,44 @@
#include <stdio.h>
#include <dlfcn.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <vector>
#include <string>
#include <map>
#include "DFHack.h"
#include "PluginManager.h"
#include "Hooks.h"
#include <iostream>
/*
* Plugin loading functions
*/
namespace DFHack
{
DFLibrary * OpenPlugin (const char * filename)
{
dlerror();
DFLibrary * ret = (DFLibrary *) dlopen(filename, RTLD_NOW);
if(!ret)
{
std::cerr << dlerror() << std::endl;
}
return ret;
}
void * LookupPlugin (DFLibrary * plugin ,const char * function)
{
return (DFLibrary *) dlsym((void *)plugin, function);
}
void ClosePlugin (DFLibrary * plugin)
{
dlclose((void *) plugin);
}
}

@ -0,0 +1,229 @@
/*
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.
*/
#include "Internal.h"
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <mach-o/dyld.h>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
using namespace std;
#include <md5wrapper.h>
#include "MemAccess.h"
#include "VersionInfoFactory.h"
#include "VersionInfo.h"
#include "Error.h"
#include <string.h>
using namespace DFHack;
Process::Process(VersionInfoFactory * known_versions)
{
int target_result;
char path[1024];
char *real_path;
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0) {
real_path = realpath(path, NULL);
}
identified = false;
my_descriptor = 0;
md5wrapper md5;
uint32_t length;
uint8_t first_kb [1024];
memset(first_kb, 0, sizeof(first_kb));
// get hash of the running DF process
string hash = md5.getHashFromFile(real_path, length, (char *) first_kb);
// create linux process, add it to the vector
VersionInfo * vinfo = known_versions->getVersionInfoByMD5(hash);
if(vinfo)
{
my_descriptor = new VersionInfo(*vinfo);
identified = true;
}
else
{
char * wd = getcwd(NULL, 0);
cerr << "Unable to retrieve version information.\n";
cerr << "File: " << real_path << endl;
cerr << "MD5: " << hash << endl;
cerr << "working dir: " << wd << endl;
cerr << "length:" << length << endl;
cerr << "1KB hexdump follows:" << endl;
for(int i = 0; i < 64; i++)
{
fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
first_kb[i*16],
first_kb[i*16+1],
first_kb[i*16+2],
first_kb[i*16+3],
first_kb[i*16+4],
first_kb[i*16+5],
first_kb[i*16+6],
first_kb[i*16+7],
first_kb[i*16+8],
first_kb[i*16+9],
first_kb[i*16+10],
first_kb[i*16+11],
first_kb[i*16+12],
first_kb[i*16+13],
first_kb[i*16+14],
first_kb[i*16+15]
);
}
free(wd);
}
}
Process::~Process()
{
// destroy our copy of the memory descriptor
delete my_descriptor;
}
string Process::doReadClassName (void * vptr)
{
//FIXME: BAD!!!!!
char * typeinfo = Process::readPtr(((char *)vptr - 0x4));
char * typestring = Process::readPtr(typeinfo + 0x4);
string raw = readCString(typestring);
size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers
size_t end = raw.length();
return raw.substr(start,end-start);
}
//FIXME: cross-reference with ELF segment entries?
void Process::getMemRanges( vector<t_memrange> & ranges )
{
char buffer[1024];
char permissions[5]; // r/-, w/-, x/-, p/s, 0
FILE *mapFile = ::fopen("/proc/self/maps", "r");
size_t start, end, offset, device1, device2, node;
while (fgets(buffer, 1024, mapFile))
{
t_memrange temp;
temp.name[0] = 0;
sscanf(buffer, "%zx-%zx %s %zx %2zx:%2zx %zu %[^\n]",
&start,
&end,
(char*)&permissions,
&offset, &device1, &device2, &node,
(char*)temp.name);
temp.start = (void *) start;
temp.end = (void *) end;
temp.read = permissions[0] == 'r';
temp.write = permissions[1] == 'w';
temp.execute = permissions[2] == 'x';
temp.shared = permissions[3] == 's';
temp.valid = true;
ranges.push_back(temp);
}
}
uint32_t Process::getBase()
{
return 0;
}
static int getdir (string dir, vector<string> &files)
{
DIR *dp;
struct dirent *dirp;
if((dp = opendir(dir.c_str())) == NULL)
{
cout << "Error(" << errno << ") opening " << dir << endl;
return errno;
}
while ((dirp = readdir(dp)) != NULL) {
files.push_back(string(dirp->d_name));
}
closedir(dp);
return 0;
}
bool Process::getThreadIDs(vector<uint32_t> & threads )
{
stringstream ss;
vector<string> subdirs;
if(getdir("/proc/self/task/",subdirs) != 0)
{
//FIXME: needs exceptions. this is a fatal error
cerr << "unable to enumerate threads. This is BAD!" << endl;
return false;
}
threads.clear();
for(size_t i = 0; i < subdirs.size();i++)
{
uint32_t tid;
if(sscanf(subdirs[i].c_str(),"%d", &tid))
{
threads.push_back(tid);
}
}
return true;
}
string Process::getPath()
{
char path[1024];
char *real_path;
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0) {
real_path = realpath(path, NULL);
}
std::string path_string(real_path);
int last_slash = path_string.find_last_of("/");
std::string directory = path_string.substr(0,last_slash);
return directory;
}
int Process::getPID()
{
return getpid();
}
bool Process::setPermisions(const t_memrange & range,const t_memrange &trgrange)
{
int result;
int protect=0;
if(trgrange.read)protect|=PROT_READ;
if(trgrange.write)protect|=PROT_WRITE;
if(trgrange.execute)protect|=PROT_EXEC;
result=mprotect((void *)range.start, (size_t)range.end-(size_t)range.start,protect);
return result==0;
}

@ -65,13 +65,20 @@ namespace DFHack
bool save (const char * filename)
{
std::ofstream outfile (filename);
fprintf(stderr,"Save: Initialized stream\n");
if(outfile.bad())
return false;
fprintf(stderr,"Save: Iterating...\n");
for(auto iter = history.begin();iter < history.end(); iter++)
{
fprintf(stderr,"Save: Dumping %s\n",(*iter).c_str());
outfile << *iter << std::endl;
fprintf(stderr,"Save: Flushing\n");
outfile.flush();
}
fprintf(stderr,"Save: Closing\n");
outfile.close();
fprintf(stderr,"Save: Done\n");
return true;
}
/// add a command to the history

@ -86,14 +86,14 @@ namespace DFHack
{
friend int ::SDL_NumJoysticks(void);
friend void ::SDL_Quit(void);
friend int ::SDL_PollEvent(SDL::Event *);
friend int ::SDL_PollEvent(SDL_Event *);
friend int ::SDL_Init(uint32_t flags);
friend int ::wgetch(WINDOW * w);
friend int ::egg_init(void);
friend int ::egg_shutdown(void);
friend int ::egg_tick(void);
friend int ::egg_prerender(void);
friend int ::egg_sdl_event(SDL::Event* event);
friend int ::egg_sdl_event(SDL_Event* event);
friend int ::egg_curses_event(int orig_return);
public:
/// Get the single Core instance or make one.
@ -170,7 +170,7 @@ namespace DFHack
int Update (void);
int TileUpdate (void);
int Shutdown (void);
int SDL_Event(SDL::Event* event);
int DFH_SDL_Event(SDL_Event* event);
bool ncurses_wgetch(int in, int & out);
void onUpdate(color_ostream &out);
@ -215,7 +215,7 @@ namespace DFHack
tthread::mutex * HotkeyMutex;
tthread::condition_variable * HotkeyCond;
int UnicodeAwareSym(const SDL::KeyboardEvent& ke);
int UnicodeAwareSym(const SDL_KeyboardEvent& ke);
bool SelectHotkey(int key, int modifiers);
// for state change tracking

@ -33,6 +33,8 @@ distribution.
#include <string>
#include <stdint.h>
#include "SDL.h"
// function and variable pointer... we don't try to understand what SDL does here
typedef void * fPtr;
typedef void * vPtr;
@ -46,7 +48,7 @@ namespace SDL
// be declared as friend functions/known
DFhackCExport int SDL_NumJoysticks(void);
DFhackCExport void SDL_Quit(void);
DFhackCExport int SDL_PollEvent(SDL::Event* event);
DFhackCExport int SDL_PollEvent(SDL_Event* event);
DFhackCExport int SDL_Init(uint32_t flags);
DFhackCExport int wgetch(WINDOW * win);
@ -63,7 +65,7 @@ DFhackCExport int egg_tick(void);
DFhackCExport int egg_prerender(void);
// hook - called for each SDL event, can filter both the event and the return value
DFhackCExport int egg_sdl_event(SDL::Event* event);
DFhackCExport int egg_sdl_event(SDL_Event* event);
// hook - ncurses event. return -1 to consume
DFhackCExport int egg_curses_event(int orig_return);

@ -1,210 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2009 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
// Fake - only structs. Shamelessly pilfered from the SDL library.
// Needed for processing its event types without polluting our namespaces with C garbage
#pragma once
#include "SDL_keyboard.h"
namespace SDL
{
enum ButtonState
{
BTN_RELEASED = 0,
BTN_PRESSED = 1
};
/** Event enumerations */
enum EventType
{
ET_NOEVENT = 0, /**< Unused (do not remove) */
ET_ACTIVEEVENT, /**< Application loses/gains visibility */
ET_KEYDOWN, /**< Keys pressed */
ET_KEYUP, /**< Keys released */
ET_MOUSEMOTION, /**< Mouse moved */
ET_MOUSEBUTTONDOWN, /**< Mouse button pressed */
ET_MOUSEBUTTONUP, /**< Mouse button released */
ET_JOYAXISMOTION, /**< Joystick axis motion */
ET_JOYBALLMOTION, /**< Joystick trackball motion */
ET_JOYHATMOTION, /**< Joystick hat position change */
ET_JOYBUTTONDOWN, /**< Joystick button pressed */
ET_JOYBUTTONUP, /**< Joystick button released */
ET_QUIT, /**< User-requested quit */
ET_SYSWMEVENT, /**< System specific event */
ET_EVENT_RESERVEDA, /**< Reserved for future use.. */
ET_EVENT_RESERVEDB, /**< Reserved for future use.. */
ET_VIDEORESIZE, /**< User resized video mode */
ET_VIDEOEXPOSE, /**< Screen needs to be redrawn */
ET_EVENT_RESERVED2, /**< Reserved for future use.. */
ET_EVENT_RESERVED3, /**< Reserved for future use.. */
ET_EVENT_RESERVED4, /**< Reserved for future use.. */
ET_EVENT_RESERVED5, /**< Reserved for future use.. */
ET_EVENT_RESERVED6, /**< Reserved for future use.. */
ET_EVENT_RESERVED7, /**< Reserved for future use.. */
/** Events ET_USEREVENT through ET_MAXEVENTS-1 are for your use */
ET_USEREVENT = 24,
/** This last event is only for bounding internal arrays
* It is the number of bits in the event mask datatype -- Uint32
*/
ET_NUMEVENTS = 32
};
/** Application visibility event structure */
struct ActiveEvent
{
uint8_t type; /**< ET_ACTIVEEVENT */
uint8_t gain; /**< Whether given states were gained or lost (1/0) */
uint8_t state; /**< A mask of the focus states */
};
/** Keyboard event structure */
struct KeyboardEvent
{
uint8_t type; /**< ET_KEYDOWN or ET_KEYUP */
uint8_t which; /**< The keyboard device index */
uint8_t state; /**< BTN_PRESSED or BTN_RELEASED */
keysym ksym;
};
/** Mouse motion event structure */
struct MouseMotionEvent
{
uint8_t type; /**< ET_MOUSEMOTION */
uint8_t which; /**< The mouse device index */
uint8_t state; /**< The current button state */
uint16_t x, y; /**< The X/Y coordinates of the mouse */
int16_t xrel; /**< The relative motion in the X direction */
int16_t yrel; /**< The relative motion in the Y direction */
};
/** Mouse button event structure */
struct MouseButtonEvent
{
uint8_t type; /**< ET_MOUSEBUTTONDOWN or ET_MOUSEBUTTONUP */
uint8_t which; /**< The mouse device index */
uint8_t button; /**< The mouse button index */
uint8_t state; /**< BTN_PRESSED or BTN_RELEASED */
uint16_t x, y; /**< The X/Y coordinates of the mouse at press time */
};
/** Joystick axis motion event structure */
struct JoyAxisEvent
{
uint8_t type; /**< ET_JOYAXISMOTION */
uint8_t which; /**< The joystick device index */
uint8_t axis; /**< The joystick axis index */
int16_t value; /**< The axis value (range: -32768 to 32767) */
};
/** Joystick trackball motion event structure */
struct JoyBallEvent
{
uint8_t type; /**< ET_JOYBALLMOTION */
uint8_t which; /**< The joystick device index */
uint8_t ball; /**< The joystick trackball index */
int16_t xrel; /**< The relative motion in the X direction */
int16_t yrel; /**< The relative motion in the Y direction */
};
/** Joystick hat position change event structure */
struct JoyHatEvent
{
uint8_t type; /**< ET_JOYHATMOTION */
uint8_t which; /**< The joystick device index */
uint8_t hat; /**< The joystick hat index */
uint8_t value; /**< The hat position value:
* SDL_HAT_LEFTUP SDL_HAT_UP SDL_HAT_RIGHTUP
* SDL_HAT_LEFT SDL_HAT_CENTERED SDL_HAT_RIGHT
* SDL_HAT_LEFTDOWN SDL_HAT_DOWN SDL_HAT_RIGHTDOWN
* Note that zero means the POV is centered.
*/
};
/** Joystick button event structure */
struct JoyButtonEvent
{
uint8_t type; /**< ET_JOYBUTTONDOWN or ET_JOYBUTTONUP */
uint8_t which; /**< The joystick device index */
uint8_t button; /**< The joystick button index */
uint8_t state; /**< BTN_PRESSED or BTN_RELEASED */
};
/** The "window resized" event
* When you get this event, you are responsible for setting a new video
* mode with the new width and height.
*/
struct ResizeEvent
{
uint8_t type; /**< ET_VIDEORESIZE */
int w; /**< New width */
int h; /**< New height */
};
/** The "screen redraw" event */
struct ExposeEvent
{
uint8_t type; /**< ET_VIDEOEXPOSE */
};
/** The "quit requested" event */
struct QuitEvent
{
uint8_t type; /**< ET_QUIT */
};
/** A user-defined event type */
struct UserEvent
{
uint8_t type; /**< ETL_USEREVENT through ET_NUMEVENTS-1 */
int code; /**< User defined event code */
void *data1; /**< User defined data pointer */
void *data2; /**< User defined data pointer */
};
/** If you want to use this event, you should include SDL_syswm.h */
struct SysWMmsg;
struct SysWMEvent
{
uint8_t type;
SysWMmsg *msg;
};
/** General event structure */
union Event
{
uint8_t type;
ActiveEvent active;
KeyboardEvent key;
MouseMotionEvent motion;
MouseButtonEvent button;
JoyAxisEvent jaxis;
JoyBallEvent jball;
JoyHatEvent jhat;
JoyButtonEvent jbutton;
ResizeEvent resize;
ExposeEvent expose;
QuitEvent quit;
UserEvent user;
SysWMEvent syswm;
};
}

@ -1,61 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2009 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
// Fake - only structs. Shamelessly pilfered from the SDL library.
// Needed for processing its event types without polluting our namespaces with C garbage
#pragma once
#include "SDL_keysym.h"
#include <stdint.h>
namespace SDL
{
/** Keysym structure
*
* - The scancode is hardware dependent, and should not be used by general
* applications. If no hardware scancode is available, it will be 0.
*
* - The 'unicode' translated character is only available when character
* translation is enabled by the SDL_EnableUNICODE() API. If non-zero,
* this is a UNICODE character corresponding to the keypress. If the
* high 9 bits of the character are 0, then this maps to the equivalent
* ASCII character:
* @code
* char ch;
* if ( (keysym.unicode & 0xFF80) == 0 ) {
* ch = keysym.unicode & 0x7F;
* } else {
* An international character..
* }
* @endcode
*/
typedef struct keysym
{
uint8_t scancode; /**< hardware specific scancode */
Key sym; /**< SDL virtual keysym */
Mod mod; /**< current key modifiers */
uint16_t unicode; /**< translated character */
} keysym;
/** This is the mask which refers to all hotkey bindings */
#define ALL_HOTKEYS 0xFFFFFFFF
}

@ -1,329 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2009 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
// Fake - only structs. Shamelessly pilfered from the SDL library.
// Needed for processing its event types without polluting our namespaces with C garbage
#pragma once
namespace SDL
{
/** What we really want is a mapping of every raw key on the keyboard.
* To support international keyboards, we use the range 0xA1 - 0xFF
* as international virtual keycodes. We'll follow in the footsteps of X11...
* @brief The names of the keys
*/
enum Key
{
/** @name ASCII mapped keysyms
* The keyboard syms have been cleverly chosen to map to ASCII
*/
/*@{*/
K_UNKNOWN = 0,
K_FIRST = 0,
K_BACKSPACE = 8,
K_TAB = 9,
K_CLEAR = 12,
K_RETURN = 13,
K_PAUSE = 19,
K_ESCAPE = 27,
K_SPACE = 32,
K_EXCLAIM = 33,
K_QUOTEDBL = 34,
K_HASH = 35,
K_DOLLAR = 36,
K_AMPERSAND = 38,
K_QUOTE = 39,
K_LEFTPAREN = 40,
K_RIGHTPAREN = 41,
K_ASTERISK = 42,
K_PLUS = 43,
K_COMMA = 44,
K_MINUS = 45,
K_PERIOD = 46,
K_SLASH = 47,
K_0 = 48,
K_1 = 49,
K_2 = 50,
K_3 = 51,
K_4 = 52,
K_5 = 53,
K_6 = 54,
K_7 = 55,
K_8 = 56,
K_9 = 57,
K_COLON = 58,
K_SEMICOLON = 59,
K_LESS = 60,
K_EQUALS = 61,
K_GREATER = 62,
K_QUESTION = 63,
K_AT = 64,
/*
Skip uppercase letters
*/
K_LEFTBRACKET = 91,
K_BACKSLASH = 92,
K_RIGHTBRACKET = 93,
K_CARET = 94,
K_UNDERSCORE = 95,
K_BACKQUOTE = 96,
K_a = 97,
K_b = 98,
K_c = 99,
K_d = 100,
K_e = 101,
K_f = 102,
K_g = 103,
K_h = 104,
K_i = 105,
K_j = 106,
K_k = 107,
K_l = 108,
K_m = 109,
K_n = 110,
K_o = 111,
K_p = 112,
K_q = 113,
K_r = 114,
K_s = 115,
K_t = 116,
K_u = 117,
K_v = 118,
K_w = 119,
K_x = 120,
K_y = 121,
K_z = 122,
K_DELETE = 127,
/* End of ASCII mapped keysyms */
/*@}*/
/** @name International keyboard syms */
/*@{*/
K_WORLD_0 = 160, /* 0xA0 */
K_WORLD_1 = 161,
K_WORLD_2 = 162,
K_WORLD_3 = 163,
K_WORLD_4 = 164,
K_WORLD_5 = 165,
K_WORLD_6 = 166,
K_WORLD_7 = 167,
K_WORLD_8 = 168,
K_WORLD_9 = 169,
K_WORLD_10 = 170,
K_WORLD_11 = 171,
K_WORLD_12 = 172,
K_WORLD_13 = 173,
K_WORLD_14 = 174,
K_WORLD_15 = 175,
K_WORLD_16 = 176,
K_WORLD_17 = 177,
K_WORLD_18 = 178,
K_WORLD_19 = 179,
K_WORLD_20 = 180,
K_WORLD_21 = 181,
K_WORLD_22 = 182,
K_WORLD_23 = 183,
K_WORLD_24 = 184,
K_WORLD_25 = 185,
K_WORLD_26 = 186,
K_WORLD_27 = 187,
K_WORLD_28 = 188,
K_WORLD_29 = 189,
K_WORLD_30 = 190,
K_WORLD_31 = 191,
K_WORLD_32 = 192,
K_WORLD_33 = 193,
K_WORLD_34 = 194,
K_WORLD_35 = 195,
K_WORLD_36 = 196,
K_WORLD_37 = 197,
K_WORLD_38 = 198,
K_WORLD_39 = 199,
K_WORLD_40 = 200,
K_WORLD_41 = 201,
K_WORLD_42 = 202,
K_WORLD_43 = 203,
K_WORLD_44 = 204,
K_WORLD_45 = 205,
K_WORLD_46 = 206,
K_WORLD_47 = 207,
K_WORLD_48 = 208,
K_WORLD_49 = 209,
K_WORLD_50 = 210,
K_WORLD_51 = 211,
K_WORLD_52 = 212,
K_WORLD_53 = 213,
K_WORLD_54 = 214,
K_WORLD_55 = 215,
K_WORLD_56 = 216,
K_WORLD_57 = 217,
K_WORLD_58 = 218,
K_WORLD_59 = 219,
K_WORLD_60 = 220,
K_WORLD_61 = 221,
K_WORLD_62 = 222,
K_WORLD_63 = 223,
K_WORLD_64 = 224,
K_WORLD_65 = 225,
K_WORLD_66 = 226,
K_WORLD_67 = 227,
K_WORLD_68 = 228,
K_WORLD_69 = 229,
K_WORLD_70 = 230,
K_WORLD_71 = 231,
K_WORLD_72 = 232,
K_WORLD_73 = 233,
K_WORLD_74 = 234,
K_WORLD_75 = 235,
K_WORLD_76 = 236,
K_WORLD_77 = 237,
K_WORLD_78 = 238,
K_WORLD_79 = 239,
K_WORLD_80 = 240,
K_WORLD_81 = 241,
K_WORLD_82 = 242,
K_WORLD_83 = 243,
K_WORLD_84 = 244,
K_WORLD_85 = 245,
K_WORLD_86 = 246,
K_WORLD_87 = 247,
K_WORLD_88 = 248,
K_WORLD_89 = 249,
K_WORLD_90 = 250,
K_WORLD_91 = 251,
K_WORLD_92 = 252,
K_WORLD_93 = 253,
K_WORLD_94 = 254,
K_WORLD_95 = 255, /* 0xFF */
/*@}*/
/** @name Numeric keypad */
/*@{*/
K_KP0 = 256,
K_KP1 = 257,
K_KP2 = 258,
K_KP3 = 259,
K_KP4 = 260,
K_KP5 = 261,
K_KP6 = 262,
K_KP7 = 263,
K_KP8 = 264,
K_KP9 = 265,
K_KP_PERIOD = 266,
K_KP_DIVIDE = 267,
K_KP_MULTIPLY = 268,
K_KP_MINUS = 269,
K_KP_PLUS = 270,
K_KP_ENTER = 271,
K_KP_EQUALS = 272,
/*@}*/
/** @name Arrows + Home/End pad */
/*@{*/
K_UP = 273,
K_DOWN = 274,
K_RIGHT = 275,
K_LEFT = 276,
K_INSERT = 277,
K_HOME = 278,
K_END = 279,
K_PAGEUP = 280,
K_PAGEDOWN = 281,
/*@}*/
/** @name Function keys */
/*@{*/
K_F1 = 282,
K_F2 = 283,
K_F3 = 284,
K_F4 = 285,
K_F5 = 286,
K_F6 = 287,
K_F7 = 288,
K_F8 = 289,
K_F9 = 290,
K_F10 = 291,
K_F11 = 292,
K_F12 = 293,
K_F13 = 294,
K_F14 = 295,
K_F15 = 296,
/*@}*/
/** @name Key state modifier keys */
/*@{*/
K_NUMLOCK = 300,
K_CAPSLOCK = 301,
K_SCROLLOCK = 302,
K_RSHIFT = 303,
K_LSHIFT = 304,
K_RCTRL = 305,
K_LCTRL = 306,
K_RALT = 307,
K_LALT = 308,
K_RMETA = 309,
K_LMETA = 310,
K_LSUPER = 311, /**< Left "Windows" key */
K_RSUPER = 312, /**< Right "Windows" key */
K_MODE = 313, /**< "Alt Gr" key */
K_COMPOSE = 314, /**< Multi-key compose key */
/*@}*/
/** @name Miscellaneous function keys */
/*@{*/
K_HELP = 315,
K_PRINT = 316,
K_SYSREQ = 317,
K_BREAK = 318,
K_MENU = 319,
K_POWER = 320, /**< Power Macintosh power key */
K_EURO = 321, /**< Some european keyboards */
K_UNDO = 322, /**< Atari keyboard has Undo */
/*@}*/
/* Add any other keys here */
K_LAST
};
/** Enumeration of valid key mods (possibly OR'd together) */
enum Mod {
KMOD_NONE = 0x0000,
KMOD_LSHIFT= 0x0001,
KMOD_RSHIFT= 0x0002,
KMOD_LCTRL = 0x0040,
KMOD_RCTRL = 0x0080,
KMOD_LALT = 0x0100,
KMOD_RALT = 0x0200,
KMOD_LMETA = 0x0400,
KMOD_RMETA = 0x0800,
KMOD_NUM = 0x1000,
KMOD_CAPS = 0x2000,
KMOD_MODE = 0x4000,
KMOD_RESERVED = 0x8000,
KMOD_CTRL = (KMOD_LCTRL|KMOD_RCTRL),
KMOD_SHIFT = (KMOD_LSHIFT|KMOD_RSHIFT),
KMOD_ALT = (KMOD_LALT|KMOD_RALT),
KMOD_META = (KMOD_LMETA|KMOD_RMETA)
};
}

@ -950,7 +950,7 @@ void Gui::showAnnouncement(std::string message, int color, bool bright)
new_rep->flags.bits.continuation = continued;
new_rep->flags.bits.announcement = true;
int size = std::min(message.size(), 73U);
int size = std::min(message.size(), (size_t)73);
new_rep->text = message.substr(0, size);
message = message.substr(size);

@ -1 +1 @@
Subproject commit ff87e784a8e274fcc3d1f57e57746735eb7285c2
Subproject commit f0e931933dd553ad1e9b2a9acde2cca59791ed9e

@ -213,7 +213,7 @@ command_result export_dwarves (color_ostream &con, std::vector <std::string> & p
return CR_OK;
}
ofstream outf(filename);
ofstream outf(filename.c_str());
if (!outf) {
con.printerr("Failed to open file %s\n", filename.c_str());
return CR_FAILURE;

@ -78,7 +78,7 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
static string brushname = "point";
static string mode="magma";
static string flowmode="f+";
static string setmode ="s.";
static string _setmode ="s.";
static unsigned int amount = 7;
static int width = 1, height = 1, z_levels = 1;
@ -120,7 +120,7 @@ command_result df_liquids (color_ostream &out_, vector <string> & parameters)
str <<"[" << mode << ":" << brushname;
if (brushname == "range")
str << "(w" << width << ":h" << height << ":z" << z_levels << ")";
str << ":" << amount << ":" << flowmode << ":" << setmode << "]#";
str << ":" << amount << ":" << flowmode << ":" << _setmode << "]#";
if(out.lineedit(str.str(),input,liquids_hist) == -1)
return CR_FAILURE;
liquids_hist.add(input);
@ -246,15 +246,15 @@ command_result df_liquids (color_ostream &out_, vector <string> & parameters)
}
else if(command == "s+")
{
setmode = "s+";
_setmode = "s+";
}
else if(command == "s-")
{
setmode = "s-";
_setmode = "s-";
}
else if(command == "s.")
{
setmode = "s.";
_setmode = "s.";
}
// blah blah, bad code, bite me.
else if(command == "0")
@ -301,7 +301,7 @@ command_result df_liquids_here (color_ostream &out, vector <string> & parameters
out << "[" << mode << ":" << brushname;
if (brushname == "range")
out << "(w" << width << ":h" << height << ":z" << z_levels << ")";
out << ":" << amount << ":" << flowmode << ":" << setmode << "]\n";
out << ":" << amount << ":" << flowmode << ":" << _setmode << "]\n";
return df_liquids_execute(out);
}
@ -457,16 +457,16 @@ command_result df_liquids_execute(color_ostream &out)
df::tile_liquid old_liquid = des.bits.liquid_type;
df::tile_liquid new_liquid = old_liquid;
// Compute new liquid type and amount
if(setmode == "s.")
if(_setmode == "s.")
{
new_amount = amount;
}
else if(setmode == "s+")
else if(_setmode == "s+")
{
if(old_amount < amount)
new_amount = amount;
}
else if(setmode == "s-")
else if(_setmode == "s-")
{
if (old_amount > amount)
new_amount = amount;

@ -124,7 +124,7 @@ command_result mapexport (color_ostream &out, std::vector <std::string> & parame
if (filename.rfind(".dfmap") == std::string::npos) filename += ".dfmap";
out << "Writing to " << filename << "..." << std::endl;
std::ofstream output_file(filename, std::ios::out | std::ios::trunc | std::ios::binary);
std::ofstream output_file(filename.c_str(), std::ios::out | std::ios::trunc | std::ios::binary);
if (!output_file.is_open())
{
out.printerr("Couldn't open the output file.\n");

@ -1 +1 @@
Subproject commit 37a823541538023b9f3d0d1e8039cf32851de68d
Subproject commit 17b653665567a5f1df628217820f76bb0b9c70a5