Merge branch 'dfapi'
Conflicts: CMakeLists.txt library/DFProcess-linux.cpp library/include/dfhack-c/modules/Creatures_C.h library/include/dfhack/modules/Maps.h library/modules/Creatures_C.cppdevelop
commit
bd9643c8cc
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
||||
DFHack tools for DF 31.21
|
@ -1,6 +0,0 @@
|
||||
mkdir MINGW32-debug
|
||||
cd MINGW32-debug
|
||||
cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Debug
|
||||
cmake-gui .
|
||||
mingw32-make 2> ..\mingw-build-log.txt
|
||||
pause
|
@ -1,7 +0,0 @@
|
||||
mkdir MINGW32-release
|
||||
cd MINGW32-release
|
||||
cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release
|
||||
|
||||
cmake-gui .
|
||||
mingw32-make 2> ..\mingw-build-log.txt
|
||||
pause
|
@ -1,5 +0,0 @@
|
||||
mkdir VC2005
|
||||
cd VC2005
|
||||
echo Pre-generating a build folder
|
||||
cmake ..\.. -G"Visual Studio 8 2005"
|
||||
cmake-gui .
|
@ -1,5 +0,0 @@
|
||||
mkdir VC2008
|
||||
cd VC2008
|
||||
echo Pre-generating a build folder
|
||||
cmake ..\.. -G"Visual Studio 9 2008"
|
||||
cmake-gui .
|
@ -1,55 +0,0 @@
|
||||
#!/usr/bin/expect
|
||||
# procedure to attempt connecting; result 0 if OK, 1 otherwise
|
||||
proc connect {} {
|
||||
expect "login:"
|
||||
send "kitteh\r"
|
||||
expect "password:"
|
||||
send "a\r"
|
||||
expect {
|
||||
kitteh {return 0}
|
||||
failed return 1
|
||||
"invalid password" return 1
|
||||
timeout return 1
|
||||
connected
|
||||
}
|
||||
# timed out
|
||||
return 1
|
||||
}
|
||||
|
||||
# procedure to do build stuff; result 0 if OK, 1 otherwise
|
||||
proc dobuild {} {
|
||||
set timeout -1
|
||||
send "pkg-win32.bat\r\n"
|
||||
puts "\nBuilding...\n"
|
||||
expect {
|
||||
"BUILD OK" {return 0}
|
||||
"MSVC ERROR" {return 1}
|
||||
"CMAKE ERROR" {return 1}
|
||||
"ENV ERROR" {return 1}
|
||||
}
|
||||
}
|
||||
|
||||
spawn telnet win7
|
||||
|
||||
set rez [connect]
|
||||
if { $rez == 1 } {
|
||||
puts "\nError connecting to server!\n"
|
||||
exit 1
|
||||
}
|
||||
|
||||
send "net use X: \\\\vboxsvr\\projects\r\n"
|
||||
expect "The command completed successfully."
|
||||
send "X:\r\n"
|
||||
expect "X:"
|
||||
send "cd X:\\dfhack\\build\r\n"
|
||||
expect "build"
|
||||
|
||||
set buildrez [dobuild]
|
||||
if { $buildrez == 1 } {
|
||||
puts "\nThere was an error during build.\n"
|
||||
} else {
|
||||
puts "\nAll OK.\n"
|
||||
}
|
||||
send "exit\r"
|
||||
expect eof
|
||||
exit $buildrez
|
@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
rm -r debian
|
||||
mkdir debian
|
||||
cd debian
|
||||
cmake ../.. -DCMAKE_BUILD_TYPE="Release" -DDFHACK_INSTALL="debian" -DMEMXML_DATA_PATH="/usr/share/dfhack" -DBUILD_DFHACK_C_BINDINGS=ON -DBUILD_DFHACK_DEVEL=ON -DBUILD_DFHACK_DOXYGEN=OFF -DBUILD_DFHACK_EXAMPLES=OFF -DBUILD_DFHACK_PLAYGROUND=OFF -DBUILD_DFHACK_PYTHON_BINDINGS=ON
|
||||
make package
|
||||
mv *.deb ../
|
@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
rm -r ubuntu64
|
||||
mkdir ubuntu64
|
||||
cd ubuntu64
|
||||
cmake ../.. -DCMAKE_BUILD_TYPE="Release" -DDFHACK_INSTALL="ubuntu-10.10" -DMEMXML_DATA_PATH="/usr/share/dfhack" -DDFHACK_PACKAGE_DIR=".." -DBUILD_DFHACK_C_BINDINGS=ON -DBUILD_DFHACK_DEVEL=ON -DBUILD_DFHACK_DOXYGEN=OFF -DBUILD_DFHACK_EXAMPLES=OFF -DBUILD_DFHACK_PLAYGROUND=OFF -DBUILD_DFHACK_PYTHON_BINDINGS=ON
|
||||
make package
|
||||
mv *.deb ../
|
@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
rm -r ubuntu
|
||||
mkdir ubuntu
|
||||
cd ubuntu
|
||||
cmake ../.. -DCMAKE_BUILD_TYPE="Release" -DDFHACK_INSTALL="ubuntu-10.10" -DMEMXML_DATA_PATH="/usr/share/dfhack" -DDFHACK_PACKAGE_DIR=".." -DBUILD_DFHACK_C_BINDINGS=ON -DBUILD_DFHACK_DEVEL=ON -DBUILD_DFHACK_DOXYGEN=OFF -DBUILD_DFHACK_EXAMPLES=OFF -DBUILD_DFHACK_PLAYGROUND=OFF -DBUILD_DFHACK_PYTHON_BINDINGS=ON
|
||||
make package
|
||||
mv *.deb ../
|
@ -1,37 +0,0 @@
|
||||
@ECHO OFF
|
||||
rd /S /Q MSVC10
|
||||
mkdir MSVC10
|
||||
cd MSVC10
|
||||
echo CLEANUP DONE
|
||||
|
||||
cmake ..\.. -G"Visual Studio 10" -DDFHACK_INSTALL="portable" -DMEMXML_DATA_PATH="." -DBUILD_DFHACK_C_BINDINGS=OFF -DBUILD_DFHACK_DEVEL=OFF -DBUILD_DFHACK_DOXYGEN=OFF -DBUILD_DFHACK_EXAMPLES=OFF -DBUILD_DFHACK_PLAYGROUND=OFF -DBUILD_DFHACK_PYTHON_BINDINGS=OFF > ..\pkg-win32-cmake.log
|
||||
if errorlevel 1 goto cmakeerror
|
||||
echo CMAKE OK
|
||||
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" > ..\pkg-win32-env.log
|
||||
if errorlevel 1 goto enverror
|
||||
echo ENV OK
|
||||
|
||||
msbuild PACKAGE.vcxproj /p:Configuration=Release /l:FileLogger,Microsoft.Build.Engine;logfile=..\pkg-win32-msbuild.log;encoding=utf-8 -noconsolelogger > NUL
|
||||
if errorlevel 1 goto msvcerror
|
||||
move /Y *.zip ..
|
||||
echo BUILD OK
|
||||
set errorlevel=0
|
||||
goto end
|
||||
|
||||
:cmakeerror
|
||||
echo CMAKE ERROR
|
||||
set errorlevel=1
|
||||
goto end
|
||||
|
||||
:enverror
|
||||
echo ENV ERROR
|
||||
set errorlevel=1
|
||||
goto end
|
||||
|
||||
:msvcerror
|
||||
echo MSVC ERROR
|
||||
set errorlevel=1
|
||||
goto end
|
||||
|
||||
:end
|
@ -1,14 +0,0 @@
|
||||
#/bin/sh
|
||||
# Remote into a virtualbox VM to build with MSVC.
|
||||
# Very specific to my own local setup. ~px
|
||||
|
||||
# VARS. TODO: parametrize
|
||||
export DFHACK_VER=0.5.7
|
||||
export PKG=dfhack-bin-$DFHACK_VER
|
||||
export TARGET=Release
|
||||
|
||||
# let's build it all
|
||||
VBoxManage startvm "7 Prof"
|
||||
sleep 20
|
||||
expect linux-remote.expect $TARGET
|
||||
|
@ -1,13 +0,0 @@
|
||||
import context
|
||||
|
||||
__all__ = [ "buildings",
|
||||
"constructions",
|
||||
"context",
|
||||
"creatures",
|
||||
"dftypes",
|
||||
"flags",
|
||||
"gui",
|
||||
"items",
|
||||
"maps",
|
||||
"materials",
|
||||
"vegetation" ]
|
@ -1,34 +0,0 @@
|
||||
from ctypes import *
|
||||
from dftypes import *
|
||||
import util
|
||||
|
||||
libdfhack.Buildings_GetCustomWorkshopType.argtypes = [ c_void_p, POINTER(CustomWorkshop) ]
|
||||
|
||||
class Buildings(object):
|
||||
def __init__(self, ptr):
|
||||
self._b_ptr = ptr
|
||||
|
||||
def start(self):
|
||||
num = c_uint()
|
||||
|
||||
if libdfhack.Buildings_Start(self._b_ptr, byref(num)) > 0:
|
||||
return int(num.value)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def finish(self):
|
||||
return libdfhack.Buildings_Finish(self._b_ptr) > 0
|
||||
|
||||
def read(self, index):
|
||||
b = Building()
|
||||
|
||||
if libdfhack.Buildings_Read(self._b_ptr, c_uint(index), byref(b)) > 0:
|
||||
return b
|
||||
else:
|
||||
return None
|
||||
|
||||
def read_custom_workshop_types(self):
|
||||
return libdfhack.Buildings_ReadCustomWorkshopTypes(self._b_ptr)
|
||||
|
||||
def get_custom_workshop_type(self, custom_workshop):
|
||||
return libdfhack.Buildings_GetCustomWorkshopType(self._b_ptr, byref(custom_workshop))
|
@ -1,25 +0,0 @@
|
||||
from ctypes import c_uint, byref
|
||||
from dftypes import libdfhack, Construction
|
||||
|
||||
class Constructions(object):
|
||||
def __init__(self, ptr):
|
||||
self._c_ptr = ptr
|
||||
|
||||
def start(self):
|
||||
num = c_uint()
|
||||
|
||||
if libdfhack.Constructions_Start(self._c_ptr, byref(num)) > 0:
|
||||
return int(num.value)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def finish(self):
|
||||
return libdfhack.Constructions_Finish(self._c_ptr) > 0
|
||||
|
||||
def read(self, index):
|
||||
c = Construction()
|
||||
|
||||
if libdfhack.Constructions_Read(self._c_ptr, c_uint(index), byref(c)) > 0:
|
||||
return c
|
||||
else:
|
||||
return None
|
@ -1,191 +0,0 @@
|
||||
from ctypes import *
|
||||
from dftypes import *
|
||||
|
||||
libdfhack.ContextManager_Alloc.restype = c_void_p
|
||||
libdfhack.ContextManager_Free.argtypes = [ c_void_p ]
|
||||
|
||||
libdfhack.ContextManager_getContext.restype = c_void_p
|
||||
libdfhack.ContextManager_getSingleContext.restype = c_void_p
|
||||
|
||||
libdfhack.Context_Free.argtypes = [ c_void_p ]
|
||||
|
||||
libdfhack.Context_getMemoryInfo.restype = c_void_p
|
||||
libdfhack.Context_getProcess.restype = c_void_p
|
||||
|
||||
libdfhack.Context_getCreatures.restype = c_void_p
|
||||
libdfhack.Context_getMaps.restype = c_void_p
|
||||
libdfhack.Context_getGui.restype = c_void_p
|
||||
libdfhack.Context_getMaterials.restype = c_void_p
|
||||
libdfhack.Context_getTranslation.restype = c_void_p
|
||||
libdfhack.Context_getVegetation.restype = c_void_p
|
||||
libdfhack.Context_getBuildings.restype = c_void_p
|
||||
libdfhack.Context_getConstructions.restype = c_void_p
|
||||
libdfhack.Context_getItems.restype = c_void_p
|
||||
libdfhack.Context_getWorld.restype = c_void_p
|
||||
libdfhack.Context_getWindowIO.restype = c_void_p
|
||||
|
||||
class ContextManager(object):
|
||||
def __init__(self, memory_path):
|
||||
self._cm_ptr = libdfhack.ContextManager_Alloc(create_string_buffer(memory_path))
|
||||
|
||||
def __del__(self):
|
||||
libdfhack.ContextManager_Free(self._cm_ptr)
|
||||
|
||||
def refresh(self):
|
||||
return libdfhack.ContextManager_Refresh(self._cm_ptr) > 0
|
||||
|
||||
def purge(self):
|
||||
libdfhack.ContextManager_purge(self._cm_ptr)
|
||||
|
||||
def get_context(self, index):
|
||||
p = libdfhack.ContextManager_getContext(self._cm_ptr, index)
|
||||
|
||||
if p:
|
||||
return Context(p)
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_single_context(self):
|
||||
p = libdfhack.ContextManager_getSingleContext(self._cm_ptr)
|
||||
|
||||
if p:
|
||||
return Context(p)
|
||||
else:
|
||||
return None
|
||||
|
||||
class Context(object):
|
||||
def __init__(self, ptr):
|
||||
self._c_ptr = ptr
|
||||
|
||||
self._mat_obj = None
|
||||
self._map_obj = None
|
||||
self._veg_obj = None
|
||||
self._build_obj = None
|
||||
self._con_obj = None
|
||||
self._gui_obj = None
|
||||
self._tran_obj = None
|
||||
self._item_obj = None
|
||||
self._creature_obj = None
|
||||
self._world_obj = None
|
||||
self._window_io_obj = None
|
||||
|
||||
def __del__(self):
|
||||
libdfhack.Context_Free(self._c_ptr)
|
||||
|
||||
def attach(self):
|
||||
return libdfhack.Context_Attach(self._c_ptr) > 0
|
||||
|
||||
def detach(self):
|
||||
self._mat_obj = None
|
||||
self._map_obj = None
|
||||
self._veg_obj = None
|
||||
self._build_obj = None
|
||||
self._con_obj = None
|
||||
self._gui_obj = None
|
||||
self._tran_obj = None
|
||||
self._item_obj = None
|
||||
self._creature_obj = None
|
||||
self._world_obj = None
|
||||
self._window_io_obj = None
|
||||
|
||||
return libdfhack.Context_Detach(self._c_ptr) > 0
|
||||
|
||||
def suspend(self):
|
||||
return libdfhack.Context_Suspend(self._c_ptr) > 0
|
||||
|
||||
def resume(self):
|
||||
return libdfhack.Context_Resume(self._c_ptr) > 0
|
||||
|
||||
def force_resume(self):
|
||||
return libdfhack.Context_ForceResume(self._c_ptr) > 0
|
||||
|
||||
def async_suspend(self):
|
||||
return libdfhack.Context_AsyncSuspend(self._c_ptr) > 0
|
||||
|
||||
@property
|
||||
def is_attached(self):
|
||||
return libdfhack.Context_isAttached(self._c_ptr) > 0
|
||||
|
||||
@property
|
||||
def is_suspended(self):
|
||||
return libdfhack.Context_isSuspended(self._c_ptr) > 0
|
||||
|
||||
@property
|
||||
def materials(self):
|
||||
import materials
|
||||
if self._mat_obj is None:
|
||||
self._mat_obj = materials.Materials(libdfhack.Context_getMaterials(self._c_ptr))
|
||||
|
||||
return self._mat_obj
|
||||
|
||||
@property
|
||||
def maps(self):
|
||||
import maps
|
||||
if self._map_obj is None:
|
||||
self._map_obj = maps.Maps(libdfhack.Context_getMaps(self._c_ptr))
|
||||
|
||||
return self._map_obj
|
||||
|
||||
@property
|
||||
def vegetation(self):
|
||||
import vegetation
|
||||
if self._veg_obj is None:
|
||||
self._veg_obj = vegetation.Vegetation(libdfhack.Context_getVegetation(self._c_ptr))
|
||||
|
||||
return self._veg_obj
|
||||
|
||||
@property
|
||||
def buildings(self):
|
||||
import buildings
|
||||
if self._build_obj is None:
|
||||
self._build_obj = buildings.Buildings(libdfhack.Context_getBuildings(self._c_ptr))
|
||||
|
||||
return self._build_obj
|
||||
|
||||
@property
|
||||
def creatures(self):
|
||||
import creatures
|
||||
if self._creature_obj is None:
|
||||
self._creature_obj = creatures.Creatures(libdfhack.Context_getCreatures(self._c_ptr))
|
||||
|
||||
return self._creature_obj
|
||||
|
||||
@property
|
||||
def gui(self):
|
||||
import gui
|
||||
if self._gui_obj is None:
|
||||
self._gui_obj = gui.Gui(libdfhack.Context_getGui(self._c_ptr))
|
||||
|
||||
return self._gui_obj
|
||||
|
||||
@property
|
||||
def items(self):
|
||||
import items
|
||||
if self._item_obj is None:
|
||||
self._item_obj = items.Items(libdfhack.Context_getItems(self._c_ptr))
|
||||
|
||||
return self._item_obj
|
||||
|
||||
@property
|
||||
def translation(self):
|
||||
import translation
|
||||
if self._tran_obj is None:
|
||||
self._tran_obj = translation.Translation(libdfhack.Context_getTranslation(self._c_ptr))
|
||||
|
||||
return self._tran_obj
|
||||
|
||||
@property
|
||||
def world(self):
|
||||
import world
|
||||
if self._world_obj is None:
|
||||
self._world_obj = world.World(libdfhack.Context_getWorld(self._c_ptr))
|
||||
|
||||
return self._world_obj
|
||||
|
||||
@property
|
||||
def window_io(self):
|
||||
import window_io
|
||||
if self._window_io_obj is None:
|
||||
self._window_io_obj = window_io.WindowIO(libdfhack.Context_getWindowIO(self._c_ptr))
|
||||
|
||||
return self._window_io_obj
|
@ -1,73 +0,0 @@
|
||||
from ctypes import *
|
||||
from dftypes import libdfhack, Creature, Material
|
||||
import util
|
||||
|
||||
libdfhack.Creatures_WriteLabors.argtypes = [ c_void_p, c_uint, POINTER(c_ubyte) ]
|
||||
|
||||
libdfhack.Creatures_ReadJob.restype = POINTER(Material)
|
||||
libdfhack.Creatures_ReadInventoryIdx.restype = POINTER(c_uint)
|
||||
libdfhack.Creatures_ReadInventoryPtr.restype = POINTER(c_uint)
|
||||
|
||||
class Creatures(object):
|
||||
def __init__(self, ptr):
|
||||
print ptr
|
||||
self._c_ptr = ptr
|
||||
|
||||
self._d_race_index = None
|
||||
self._d_civ_id = None
|
||||
|
||||
def start(self):
|
||||
n = c_uint(0)
|
||||
|
||||
if libdfhack.Creatures_Start(self._c_ptr, byref(n)) > 0:
|
||||
return int(n.value)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def finish(self):
|
||||
return libdfhack.Creatures_Finish(self._c_ptr) > 0
|
||||
|
||||
def read_creature(self, index):
|
||||
c = Creature()
|
||||
|
||||
if libdfhack.Creatures_ReadCreature(self._c_ptr, c_int(index), byref(c)) > 0:
|
||||
return c
|
||||
else:
|
||||
return None
|
||||
|
||||
def read_creature_in_box(self, index, pos1, pos2):
|
||||
c = Creature()
|
||||
|
||||
x1, y1, z1 = c_uint(pos1[0]), c_uint(pos1[1]), c_uint(pos1[2])
|
||||
x2, y2, z2 = c_uint(pos2[0]), c_uint(pos2[1]), c_uint(pos2[2])
|
||||
|
||||
retval = libdfhack.Creatures_ReadCreatureInBox(self._c_ptr, byref(c), x1, y1, z1, x2, y2, z2)
|
||||
|
||||
return (retval, c)
|
||||
|
||||
def write_labors(self, index, labors):
|
||||
return libdfhack.Creatures_WriteLabors(self._c_ptr, c_uint(index), labors) > 0
|
||||
|
||||
def read_job(self, creature):
|
||||
job_ptr = libdfhack.Creatures_ReadJob(self._c_ptr, byref(creature))
|
||||
jobs = None
|
||||
|
||||
if id(job_ptr) in dftypes.pointer_dict:
|
||||
jobs = dftypes.pointer_dict[id(job_ptr)][1]
|
||||
del dftypes.pointer_dict[id(job_ptr)]
|
||||
|
||||
return jobs
|
||||
|
||||
@property
|
||||
def dwarf_race_index(self):
|
||||
if self._d_race_index is None:
|
||||
self._d_race_index =libdfhack.Creatures_GetDwarfRaceIndex(self._c_ptr)
|
||||
|
||||
return self._d_race_index
|
||||
|
||||
@property
|
||||
def dwarf_civ_id(self):
|
||||
if self._d_civ_id is None:
|
||||
self._d_civ_id = libdfhack.Creatures_GetDwarfCivId(self._c_ptr)
|
||||
|
||||
return self._d_civ_id
|
@ -1,152 +0,0 @@
|
||||
from ctypes import *
|
||||
from pydftypes import *
|
||||
|
||||
|
||||
libdfhack.API_Alloc.restype = c_void_p
|
||||
libdfhack.API_Free.argtypes = [ c_void_p ]
|
||||
|
||||
libdfhack.API_getMemoryInfo.restype = c_void_p
|
||||
libdfhack.API_getProcess.restype = c_void_p
|
||||
libdfhack.API_getWindow.restype = c_void_p
|
||||
|
||||
libdfhack.API_getCreatures.restype = c_void_p
|
||||
libdfhack.API_getMaps.restype = c_void_p
|
||||
libdfhack.API_getGui.restype = c_void_p
|
||||
libdfhack.API_getMaterials.restype = c_void_p
|
||||
libdfhack.API_getTranslation.restype = c_void_p
|
||||
libdfhack.API_getVegetation.restype = c_void_p
|
||||
libdfhack.API_getBuildings.restype = c_void_p
|
||||
libdfhack.API_getConstructions.restype = c_void_p
|
||||
libdfhack.API_getItems.restype = c_void_p
|
||||
|
||||
class API(object):
|
||||
def __init__(self, memory_path):
|
||||
self._api_ptr = libdfhack.API_Alloc(create_string_buffer(memory_path))
|
||||
|
||||
self._mat_obj = None
|
||||
self._map_obj = None
|
||||
self._veg_obj = None
|
||||
self._build_obj = None
|
||||
self._con_obj = None
|
||||
self._gui_obj = None
|
||||
self._tran_obj = None
|
||||
self._item_obj = None
|
||||
self._creature_obj = None
|
||||
|
||||
def __del__(self):
|
||||
libdfhack.API_Free(self._api_ptr)
|
||||
|
||||
def attach(self):
|
||||
return libdfhack.API_Attach(self._api_ptr) > 0
|
||||
|
||||
def detach(self):
|
||||
return libdfhack.API_Detach(self._api_ptr) > 0
|
||||
|
||||
def suspend(self):
|
||||
return libdfhack.API_Suspend(self._api_ptr) > 0
|
||||
|
||||
def resume(self):
|
||||
return libdfhack.API_Resume(self._api_ptr) > 0
|
||||
|
||||
def force_resume(self):
|
||||
return libdfhack.API_ForceResume(self._api_ptr) > 0
|
||||
|
||||
def async_suspend(self):
|
||||
return libdfhack.API_AsyncSuspend(self._api_ptr) > 0
|
||||
|
||||
@property
|
||||
def is_attached(self):
|
||||
return libdfhack.API_isAttached(self._api_ptr) > 0
|
||||
|
||||
@property
|
||||
def is_suspended(self):
|
||||
return libdfhack.API_isSuspended(self._api_ptr) > 0
|
||||
|
||||
@property
|
||||
def materials(self):
|
||||
import materials
|
||||
if self._mat_obj is None:
|
||||
self._mat_obj = materials.Materials(libdfhack.API_getMaterials(self._api_ptr))
|
||||
|
||||
return self._mat_obj
|
||||
|
||||
@property
|
||||
def maps(self):
|
||||
import maps
|
||||
if self._map_obj is None:
|
||||
self._map_obj = maps.Maps(libdfhack.API_getMaps(self._api_ptr))
|
||||
|
||||
return self._map_obj
|
||||
|
||||
@property
|
||||
def vegetation(self):
|
||||
import vegetation
|
||||
if self._veg_obj is None:
|
||||
self._veg_obj = vegetation.Vegetation(libdfhack.API_getVegetation(self._api_ptr))
|
||||
|
||||
return self._veg_obj
|
||||
|
||||
@property
|
||||
def buildings(self):
|
||||
import buildings
|
||||
if self._build_obj is None:
|
||||
self._build_obj = buildings.Buildings(libdfhack.API_getBuildings(self._api_ptr))
|
||||
|
||||
return self._build_obj
|
||||
|
||||
@property
|
||||
def creatures(self):
|
||||
import creatures
|
||||
if self._creature_obj is None:
|
||||
self._creature_obj = creatures.Creatures(libdfhack.API_getCreatures(self._api_ptr))
|
||||
|
||||
return self._creature_obj
|
||||
|
||||
@property
|
||||
def gui(self):
|
||||
import gui
|
||||
if self._gui_obj is None:
|
||||
self._gui_obj = gui.Gui(libdfhack.API_getGui(self._api_ptr))
|
||||
|
||||
return self._gui_obj
|
||||
|
||||
@property
|
||||
def items(self):
|
||||
import items
|
||||
if self._item_obj is None:
|
||||
self._item_obj = items.Items(libdfhack.API_getItems(self._api_ptr))
|
||||
|
||||
return self._item_obj
|
||||
|
||||
@property
|
||||
def translation(self):
|
||||
import translation
|
||||
if self._tran_obj is None:
|
||||
self._tran_obj = translation.Translation(libdfhack.API_getTranslation(self._api_ptr))
|
||||
|
||||
return self._tran_obj
|
||||
|
||||
def reveal():
|
||||
df = API("Memory.xml")
|
||||
df.attach()
|
||||
|
||||
m = df.maps
|
||||
|
||||
m.start()
|
||||
|
||||
m_x, m_y, m_z = m.size
|
||||
|
||||
for x in xrange(m_x):
|
||||
for y in xrange(m_y):
|
||||
for z in xrange(m_z):
|
||||
if m.is_valid_block(x, y, z):
|
||||
d = m.read_designations(x, y, z)
|
||||
|
||||
for i in d:
|
||||
for j in i:
|
||||
j.bits.hidden = 0
|
||||
|
||||
m.write_designations(x, y, z, d)
|
||||
|
||||
m.finish()
|
||||
df.detach()
|
@ -1,637 +0,0 @@
|
||||
from ctypes import *
|
||||
from flags import *
|
||||
from enum import *
|
||||
import util
|
||||
from util import *
|
||||
|
||||
libdfhack = cdll.libdfhack
|
||||
|
||||
def _register_callback(name, func):
|
||||
ptr = c_void_p.in_dll(libdfhack, name)
|
||||
ptr.value = cast(func, c_void_p).value
|
||||
|
||||
_register_callback("alloc_byte_buffer_callback", alloc_byte_buffer)
|
||||
_register_callback("alloc_ubyte_buffer_callback", alloc_ubyte_buffer)
|
||||
_register_callback("alloc_short_buffer_callback", alloc_short_buffer)
|
||||
_register_callback("alloc_ushort_buffer_callback", alloc_ushort_buffer)
|
||||
_register_callback("alloc_int_buffer_callback", alloc_int_buffer)
|
||||
_register_callback("alloc_uint_buffer_callback", alloc_uint_buffer)
|
||||
_register_callback("alloc_char_buffer_callback", alloc_char_buffer)
|
||||
|
||||
_arr_create_func = CFUNCTYPE(c_void_p, c_int)
|
||||
_dfhack_string = (c_char * 128)
|
||||
|
||||
TileTypes40d = ((c_int * 16) * 16)
|
||||
BiomeIndices40d = c_ubyte * 16
|
||||
Temperatures = ((c_ushort * 16) * 16)
|
||||
Designations40d = ((DesignationFlags * 16) * 16)
|
||||
Occupancies40d = ((OccupancyFlags * 16) * 16)
|
||||
|
||||
def wall_terrain_check(terrain):
|
||||
return libdfhack.DFHack_isWallTerrain(terrain) > 0
|
||||
|
||||
def floor_terrain_check(terrain):
|
||||
return libdfhack.DFHack_isFloorTerrain(terrain) > 0
|
||||
|
||||
def ramp_terrain_check(terrain):
|
||||
return libdfhack.DFHack_isRampTerrain(terrain) > 0
|
||||
|
||||
def stair_terrain_check(terrain):
|
||||
return libdfhack.DFHack_isStairTerrain(terrain) > 0
|
||||
|
||||
def open_terrain_check(terrain):
|
||||
return libdfhack.DFHack_isOpenTerrain(terrain) > 0
|
||||
|
||||
def get_vegetation_type(terrain):
|
||||
return libdfhack.DFHack_getVegetationType(terrain)
|
||||
|
||||
class Position2D(Structure):
|
||||
_fields_ = [("x", c_ushort),
|
||||
("y", c_ushort)]
|
||||
|
||||
class Position3D(Structure):
|
||||
_fields_ = [("x", c_ushort),
|
||||
("y", c_ushort),
|
||||
("z", c_uint)]
|
||||
|
||||
class PlaneCoord(Union):
|
||||
_fields_ = [("xyz", Position3D),
|
||||
("dim", Position2D),
|
||||
("comparate", c_ulong)]
|
||||
|
||||
def __cmp__(self, other):
|
||||
if isinstance(other, PlaneCoord):
|
||||
return self.comparate - other.comparate
|
||||
else:
|
||||
raise TypeError("argument must be of type %s" % type(self))
|
||||
|
||||
class Feature(Structure):
|
||||
_fields_ = [("type", FeatureType),
|
||||
("main_material", c_short),
|
||||
("sub_material", c_short),
|
||||
("discovered", c_byte),
|
||||
("origin", c_uint)]
|
||||
|
||||
class FeatureMapNode(Structure):
|
||||
_fields_ = [("coordinate", PlaneCoord),
|
||||
("features", POINTER(Feature)),
|
||||
("feature_length", c_uint)]
|
||||
|
||||
def _alloc_featuremap_buffer_callback(ptr, fmap_list, count):
|
||||
arr_list = []
|
||||
arr = (FeatureMapNode * count)()
|
||||
|
||||
for i, v in enumerate(arr):
|
||||
f_count = int(fmap_list[i])
|
||||
f_arr = (Feature * f_count)()
|
||||
|
||||
f_p = cast(f_arr, POINTER(Feature))
|
||||
v.features = f_p
|
||||
|
||||
arr_list.extend((f_arr, f_p))
|
||||
|
||||
p = cast(arr, POINTER(FeatureMapNode))
|
||||
ptr[0] = p
|
||||
|
||||
pointer_dict[addressof(arr)] = (ptr, arr, p, arr_list)
|
||||
|
||||
return 1
|
||||
|
||||
_alloc_featuremap_buffer_functype = CFUNCTYPE(c_int, POINTER(POINTER(FeatureMapNode)), uint_ptr, c_uint)
|
||||
_alloc_featuremap_buffer_func = _alloc_featuremap_buffer_functype(_alloc_featuremap_buffer_callback)
|
||||
_register_callback("alloc_featuremap_buffer_callback", _alloc_featuremap_buffer_func)
|
||||
|
||||
class Vein(Structure):
|
||||
_fields_ = [("vtable", c_uint),
|
||||
("type", c_int),
|
||||
("assignment", c_short * 16),
|
||||
("flags", c_uint),
|
||||
("address_of", c_uint)]
|
||||
|
||||
_vein_ptr = POINTER(Vein)
|
||||
|
||||
def _alloc_vein_buffer_callback(ptr, count):
|
||||
return util._allocate_array(ptr, Vein, count)
|
||||
|
||||
_vein_functype = CFUNCTYPE(c_int, POINTER(_vein_ptr), c_uint)
|
||||
_vein_func = _vein_functype(_alloc_vein_buffer_callback)
|
||||
_register_callback("alloc_vein_buffer_callback", _vein_func)
|
||||
|
||||
class FrozenLiquidVein(Structure):
|
||||
_fields_ = [("vtable", c_uint),
|
||||
("tiles", TileTypes40d),
|
||||
("address_of", c_uint)]
|
||||
|
||||
_frozenvein_ptr = POINTER(FrozenLiquidVein)
|
||||
|
||||
def _alloc_frozenliquidvein_buffer_callback(ptr, count):
|
||||
return util._allocate_array(ptr, FrozenLiquidVein, count)
|
||||
|
||||
_frozenliquidvein_functype = CFUNCTYPE(c_int, POINTER(_frozenvein_ptr), c_uint)
|
||||
_frozenliquidvein_func = _frozenliquidvein_functype(_alloc_frozenliquidvein_buffer_callback)
|
||||
_register_callback("alloc_frozenliquidvein_buffer_callback", _frozenliquidvein_func)
|
||||
|
||||
class SpatterVein(Structure):
|
||||
_fields_ = [("vtable", c_uint),
|
||||
("mat1", c_ushort),
|
||||
("unk1", c_ushort),
|
||||
("mat2", c_uint),
|
||||
("mat3", c_ushort),
|
||||
("intensity", ((c_ubyte * 16) * 16)),
|
||||
("address_of", c_uint)]
|
||||
|
||||
_spattervein_ptr = POINTER(SpatterVein)
|
||||
|
||||
def _alloc_spattervein_buffer_callback(ptr, count):
|
||||
return util._allocate_array(ptr, SpatterVein, count)
|
||||
|
||||
_spattervein_functype = CFUNCTYPE(c_int, POINTER(_spattervein_ptr), c_uint)
|
||||
_spattervein_func = _spattervein_functype(_alloc_spattervein_buffer_callback)
|
||||
_register_callback("alloc_spattervein_buffer_callback", _spattervein_func)
|
||||
|
||||
class GrassVein(Structure):
|
||||
_fields_ = [("vtable", c_uint),
|
||||
("material", c_uint),
|
||||
("intensity", ((c_ubyte * 16) * 16)),
|
||||
("address_of", c_uint)]
|
||||
|
||||
_grassvein_ptr = POINTER(GrassVein)
|
||||
|
||||
def _alloc_grassvein_buffer_callback(ptr, count):
|
||||
return util._allocate_array(ptr, GrassVein, count)
|
||||
|
||||
_grassvein_functype = CFUNCTYPE(c_int, POINTER(_grassvein_ptr), c_uint)
|
||||
_grassvein_func = _grassvein_functype(_alloc_grassvein_buffer_callback)
|
||||
_register_callback("alloc_grassvein_buffer_callback", _grassvein_func)
|
||||
|
||||
class WorldConstruction(Structure):
|
||||
_fields_ = [("vtable", c_uint),
|
||||
("material", c_uint),
|
||||
("assignment", c_ushort * 16),
|
||||
("address_of", c_uint)]
|
||||
|
||||
_worldconstruction_ptr = POINTER(WorldConstruction)
|
||||
|
||||
def _alloc_worldconstruction_buffer_callback(ptr, count):
|
||||
return util._allocate_array(ptr, WorldConstruction, count)
|
||||
|
||||
_worldconstruction_functype = CFUNCTYPE(c_int, POINTER(_worldconstruction_ptr), c_uint)
|
||||
_worldconstruction_func = _worldconstruction_functype(_alloc_worldconstruction_buffer_callback)
|
||||
_register_callback("alloc_worldconstruction_buffer_callback", _worldconstruction_func)
|
||||
|
||||
class MapBlock40d(Structure):
|
||||
_fields_ = [("tiletypes", TileTypes40d),
|
||||
("designation", Designations40d),
|
||||
("occupancy", Occupancies40d),
|
||||
("biome_indices", BiomeIndices40d),
|
||||
("origin", c_uint),
|
||||
("blockflags", BlockFlags),
|
||||
("global_feature", c_short),
|
||||
("local_feature", c_short)]
|
||||
|
||||
|
||||
class ViewScreen(Structure):
|
||||
_fields_ = [("type", c_int)]
|
||||
|
||||
class Matgloss(Structure):
|
||||
_fields_ = [("id", _dfhack_string),
|
||||
("fore", c_byte),
|
||||
("back", c_byte),
|
||||
("bright", c_byte),
|
||||
("name", _dfhack_string)]
|
||||
|
||||
_matgloss_ptr = POINTER(Matgloss)
|
||||
|
||||
def _alloc_matgloss_buffer_callback(ptr, count):
|
||||
return util._allocate_array(ptr, Matgloss, count)
|
||||
|
||||
_matgloss_functype = CFUNCTYPE(c_int, POINTER(_matgloss_ptr), c_uint)
|
||||
_matgloss_func = _matgloss_functype(_alloc_matgloss_buffer_callback)
|
||||
_register_callback("alloc_matgloss_buffer_callback", _matgloss_func)
|
||||
|
||||
class MatglossPair(Structure):
|
||||
_fields_ = [("type", c_short),
|
||||
("index", c_int)]
|
||||
|
||||
class DescriptorColor(Structure):
|
||||
_fields_ = [("id", _dfhack_string),
|
||||
("r", c_float),
|
||||
("v", c_float),
|
||||
("b", c_float),
|
||||
("name", _dfhack_string)]
|
||||
|
||||
def _alloc_descriptor_buffer_callback(ptr, count):
|
||||
return util._allocate_array(ptr, DescriptorColor, count)
|
||||
|
||||
_descriptor_functype = CFUNCTYPE(c_int, POINTER(POINTER(DescriptorColor)), c_uint)
|
||||
_descriptor_func = _descriptor_functype(_alloc_descriptor_buffer_callback)
|
||||
_register_callback("alloc_descriptor_buffer_callback", _descriptor_func)
|
||||
|
||||
class MatglossPlant(Structure):
|
||||
_fields_ = [("id", _dfhack_string),
|
||||
("fore", c_ubyte),
|
||||
("back", c_ubyte),
|
||||
("bright", c_ubyte),
|
||||
("name", _dfhack_string),
|
||||
("drink_name", _dfhack_string),
|
||||
("food_name", _dfhack_string),
|
||||
("extract_name", _dfhack_string)]
|
||||
|
||||
class MatglossOther(Structure):
|
||||
_fields_ = [("rawname", c_char * 128)]
|
||||
|
||||
def _alloc_matgloss_other_buffer_callback(ptr, count):
|
||||
return util._allocate_array(ptr, MatglossOther, count)
|
||||
|
||||
_matgloss_other_functype = CFUNCTYPE(c_int, POINTER(POINTER(MatglossOther)), c_uint)
|
||||
_matgloss_other_func = _matgloss_other_functype(_alloc_matgloss_other_buffer_callback)
|
||||
_register_callback("alloc_matgloss_other_buffer_callback", _matgloss_other_func)
|
||||
|
||||
class Building(Structure):
|
||||
_fields_ = [("origin", c_uint),
|
||||
("vtable", c_uint),
|
||||
("x1", c_uint),
|
||||
("y1", c_uint),
|
||||
("x2", c_uint),
|
||||
("y2", c_uint),
|
||||
("z", c_uint),
|
||||
("material", MatglossPair),
|
||||
("type", c_uint)]
|
||||
|
||||
class CustomWorkshop(Structure):
|
||||
_fields_ = [("index", c_uint),
|
||||
("name", c_char * 256)]
|
||||
|
||||
def _alloc_custom_workshop_buffer_callback(ptr, count):
|
||||
return util._allocate_array(ptr, CustomWorkshop, count)
|
||||
|
||||
_custom_workshop_functype = CFUNCTYPE(c_int, POINTER(POINTER(CustomWorkshop)), c_uint)
|
||||
_custom_workshop_func = _custom_workshop_functype(_alloc_custom_workshop_buffer_callback)
|
||||
_register_callback("alloc_customWorkshop_buffer_callback", _custom_workshop_func)
|
||||
|
||||
class Construction(Structure):
|
||||
_fields_ = [("x", c_ushort),
|
||||
("y", c_ushort),
|
||||
("z", c_ushort),
|
||||
("form", c_ushort),
|
||||
("unk_8", c_ushort),
|
||||
("mat_type", c_ushort),
|
||||
("mat_idx", c_uint),
|
||||
("unk3", c_ushort),
|
||||
("unk4", c_ushort),
|
||||
("unk5", c_ushort),
|
||||
("unk6", c_uint),
|
||||
("origin", c_uint)]
|
||||
|
||||
class Tree(Structure):
|
||||
_fields_ = [("type", c_ushort),
|
||||
("material", c_ushort),
|
||||
("x", c_ushort),
|
||||
("y", c_ushort),
|
||||
("z", c_ushort),
|
||||
("address", c_uint)]
|
||||
|
||||
def __str__(self):
|
||||
water = ""
|
||||
tree_type = "tree"
|
||||
|
||||
if self.type == 1 or self.type == 3:
|
||||
water = "near-water"
|
||||
if self.type == 2 or self.type == 3:
|
||||
tree_type = "shrub"
|
||||
|
||||
s = "%d:%d = %s %s\nAddress: 0x%x\n" % (self.type, self.material, water, tree_type, self.address)
|
||||
|
||||
return s
|
||||
|
||||
def _alloc_tree_buffer_callback(ptr, count):
|
||||
return util._allocate_array(ptr, Tree, count)
|
||||
|
||||
_alloc_tree_buffer_functype = CFUNCTYPE(c_int, POINTER(POINTER(Tree)), c_uint)
|
||||
_alloc_tree_buffer_func = _alloc_tree_buffer_functype(_alloc_tree_buffer_callback)
|
||||
_register_callback("alloc_tree_buffer_callback", _alloc_tree_buffer_func)
|
||||
|
||||
class Material(Structure):
|
||||
_fields_ = [("itemType", c_short),
|
||||
("subType", c_short),
|
||||
("subIndex", c_short),
|
||||
("index", c_int),
|
||||
("flags", c_uint)]
|
||||
|
||||
def _alloc_material_buffer_callback(ptr, count):
|
||||
return util._allocate_array(ptr, Material, count)
|
||||
|
||||
_material_functype = CFUNCTYPE(c_int, POINTER(POINTER(Material)), c_uint)
|
||||
_material_func = _material_functype(_alloc_material_buffer_callback)
|
||||
_register_callback("alloc_material_buffer_callback", _material_func)
|
||||
|
||||
class Skill(Structure):
|
||||
_fields_ = [("id", c_uint),
|
||||
("experience", c_uint),
|
||||
("rating", c_uint)]
|
||||
|
||||
class Job(Structure):
|
||||
_fields_ = [("active", c_byte),
|
||||
("jobId", c_uint),
|
||||
("jobType", c_ubyte),
|
||||
("occupationPtr", c_uint)]
|
||||
|
||||
class Like(Structure):
|
||||
_fields_ = [("type", c_short),
|
||||
("itemClass", c_short),
|
||||
("itemIndex", c_short),
|
||||
("material", MatglossPair),
|
||||
("active", c_byte)]
|
||||
|
||||
class Attribute(Structure):
|
||||
_fields_ = [("level", c_uint),
|
||||
("field_4", c_uint),
|
||||
("field_8", c_uint),
|
||||
("field_C", c_uint),
|
||||
("leveldiff", c_uint),
|
||||
("field_14", c_uint),
|
||||
("field_18", c_uint)]
|
||||
|
||||
class Name(Structure):
|
||||
_fields_ = [("first_name", _dfhack_string),
|
||||
("nickname", _dfhack_string),
|
||||
("words", (c_int * 7)),
|
||||
("parts_of_speech", (c_ushort * 7)),
|
||||
("language", c_uint),
|
||||
("has_name", c_byte)]
|
||||
|
||||
class Note(Structure):
|
||||
_fields_ = [("symbol", c_char),
|
||||
("foreground", c_ushort),
|
||||
("background", c_ushort),
|
||||
("name", _dfhack_string),
|
||||
("x", c_ushort),
|
||||
("y", c_ushort),
|
||||
("z", c_ushort)]
|
||||
|
||||
class Settlement(Structure):
|
||||
_fields_ = [("origin", c_uint),
|
||||
("name", Name),
|
||||
("world_x", c_short),
|
||||
("world_y", c_short),
|
||||
("local_x1", c_short),
|
||||
("local_x2", c_short),
|
||||
("local_y1", c_short),
|
||||
("local_y2", c_short)]
|
||||
|
||||
_NUM_CREATURE_TRAITS = 30
|
||||
_NUM_CREATURE_LABORS = 102
|
||||
|
||||
class Soul(Structure):
|
||||
_fields_ = [("numSkills", c_ubyte),
|
||||
("skills", (Skill * 256)),
|
||||
("traits", (c_ushort * _NUM_CREATURE_TRAITS)),
|
||||
("analytical_ability", Attribute),
|
||||
("focus", Attribute),
|
||||
("willpower", Attribute),
|
||||
("creativity", Attribute),
|
||||
("intuition", Attribute),
|
||||
("patience", Attribute),
|
||||
("memory", Attribute),
|
||||
("linguistic_ability", Attribute),
|
||||
("spatial_sense", Attribute),
|
||||
("musicality", Attribute),
|
||||
("kinesthetic_sense", Attribute),
|
||||
("empathy", Attribute),
|
||||
("social_awareness", Attribute)]
|
||||
|
||||
_MAX_COLORS = 15
|
||||
|
||||
class Creature(Structure):
|
||||
_fields_ = [("origin", c_uint),
|
||||
("x", c_ushort),
|
||||
("y", c_ushort),
|
||||
("z", c_ushort),
|
||||
("race", c_uint),
|
||||
("civ", c_int),
|
||||
("flags1", CreatureFlags1),
|
||||
("flags2", CreatureFlags2),
|
||||
("name", Name),
|
||||
("mood", c_short),
|
||||
("mood_skill", c_short),
|
||||
("artifact_name", Name),
|
||||
("profession", c_ubyte),
|
||||
("custom_profession", _dfhack_string),
|
||||
("labors", (c_ubyte * _NUM_CREATURE_LABORS)),
|
||||
("current_job", Job),
|
||||
("happiness", c_uint),
|
||||
("id", c_uint),
|
||||
("strength", Attribute),
|
||||
("agility", Attribute),
|
||||
("toughness", Attribute),
|
||||
("endurance", Attribute),
|
||||
("recuperation", Attribute),
|
||||
("disease_resistance", Attribute),
|
||||
("squad_leader_id", c_int),
|
||||
("sex", c_ubyte),
|
||||
("caste", c_ushort),
|
||||
("pregnancy_timer", c_uint),
|
||||
("has_default_soul", c_byte),
|
||||
("defaultSoul", Soul),
|
||||
("nbcolors", c_uint),
|
||||
("color", (c_uint * _MAX_COLORS)),
|
||||
("birth_year", c_int),
|
||||
("birth_time", c_uint)]
|
||||
|
||||
class CreatureExtract(Structure):
|
||||
_fields_ = [("rawname", _dfhack_string)]
|
||||
|
||||
class BodyPart(Structure):
|
||||
_fields_ = [("id", _dfhack_string),
|
||||
("category", _dfhack_string),
|
||||
("single", _dfhack_string),
|
||||
("plural", _dfhack_string)]
|
||||
|
||||
_bodypart_ptr = POINTER(BodyPart)
|
||||
|
||||
class ColorModifier(Structure):
|
||||
_fields_ = [("part", _dfhack_string),
|
||||
("colorlist", POINTER(c_uint)),
|
||||
("colorlistLength", c_uint),
|
||||
("startdate", c_uint),
|
||||
("enddate", c_uint)]
|
||||
|
||||
def __init__(self):
|
||||
self.colorlistLength = 0
|
||||
|
||||
_colormodifier_ptr = POINTER(ColorModifier)
|
||||
|
||||
class CreatureCaste(Structure):
|
||||
_fields_ = [("rawname", _dfhack_string),
|
||||
("singular", _dfhack_string),
|
||||
("plural", _dfhack_string),
|
||||
("adjective", _dfhack_string),
|
||||
("color_modifier", _colormodifier_ptr),
|
||||
("color_modifier_length", c_uint),
|
||||
("bodypart", _bodypart_ptr),
|
||||
("bodypart_length", c_uint),
|
||||
("strength", Attribute),
|
||||
("agility", Attribute),
|
||||
("toughness", Attribute),
|
||||
("endurance", Attribute),
|
||||
("recuperation", Attribute),
|
||||
("disease_resistance", Attribute),
|
||||
("analytical_ability", Attribute),
|
||||
("focus", Attribute),
|
||||
("willpower", Attribute),
|
||||
("creativity", Attribute),
|
||||
("intuition", Attribute),
|
||||
("patience", Attribute),
|
||||
("memory", Attribute),
|
||||
("linguistic_ability", Attribute),
|
||||
("spatial_sense", Attribute),
|
||||
("musicality", Attribute),
|
||||
("kinesthetic_sense", Attribute)]
|
||||
|
||||
_creaturecaste_ptr = POINTER(CreatureCaste)
|
||||
|
||||
class TileColor(Structure):
|
||||
_fields_ = [("fore", c_ushort),
|
||||
("back", c_ushort),
|
||||
("bright", c_ushort)]
|
||||
|
||||
class ColorDescriptor(Structure):
|
||||
_fields_ = [("colorlistLength", c_uint)]
|
||||
|
||||
class CasteDescriptor(Structure):
|
||||
_fields_ = [("color_descriptors", POINTER(ColorDescriptor)),
|
||||
("colorModifierLength", c_uint),
|
||||
("bodypartLength", c_uint)]
|
||||
|
||||
class CreatureTypeDescriptor(Structure):
|
||||
_fields_ = [("caste_descriptors", POINTER(CasteDescriptor)),
|
||||
("castesCount", c_uint),
|
||||
("extractCount", c_uint)]
|
||||
|
||||
class CreatureType(Structure):
|
||||
_fields_ = [("rawname", _dfhack_string),
|
||||
("castes", _creaturecaste_ptr),
|
||||
("castes_count", c_uint),
|
||||
("extract", POINTER(CreatureExtract)),
|
||||
("extract_count", c_uint),
|
||||
("tile_character", c_ubyte),
|
||||
("tilecolor", TileColor)]
|
||||
|
||||
_creaturetype_ptr = POINTER(CreatureType)
|
||||
|
||||
def _alloc_creaturetype_buffer(ptr, descriptors, count):
|
||||
arr_list = []
|
||||
c_arr = (CreatureType * count)()
|
||||
|
||||
for i, v in enumerate(c_arr):
|
||||
v.castesCount = descriptors[i].castesCount
|
||||
v_caste_arr = (CreatureCaste * v.castesCount)()
|
||||
|
||||
for j, v_c in enumerate(v_caste_arr):
|
||||
caste_descriptor = descriptors[i].caste_descriptors[j]
|
||||
|
||||
v_c.colorModifierLength = caste_descriptor.colorModifierLength
|
||||
c_color_arr = (ColorModifier * v_c.colorModifierLength)()
|
||||
|
||||
for k, c_c in enumerate(c_color_arr):
|
||||
color_descriptor = caste_descriptor.color_descriptors[k]
|
||||
|
||||
c_c.colorlistLength = color_descriptor.colorlistLength
|
||||
|
||||
c_color_list_arr = (c_uint * c_c.colorlistLength)()
|
||||
|
||||
p = cast(c_color_list_arr, POINTER(c_uint))
|
||||
|
||||
c_c.colorlist = p
|
||||
|
||||
arr_list.extend((c_color_list_arr, p))
|
||||
|
||||
c_p = cast(c_color_arr, POINTER(ColorModifier))
|
||||
v_c.colorModifier = c_p
|
||||
|
||||
v_c.bodypartLength = caste_descriptor.bodypartLength
|
||||
c_bodypart_arr = (BodyPart * v_c.bodypartLength)()
|
||||
|
||||
b_p = cast(c_bodypart_arr, POINTER(BodyPart))
|
||||
v_c.bodypart = b_p
|
||||
|
||||
arr_list.extend((c_color_arr, c_p, c_bodypart_arr, b_p))
|
||||
|
||||
v.extractCount = descriptors[i].extractCount
|
||||
v_extract_arr = (CreatureExtract * v.extractCount)()
|
||||
|
||||
caste_p = cast(v_caste_arr, POINTER(CreatureCaste))
|
||||
v.castes = caste_p
|
||||
|
||||
extract_p = cast(v_extract_arr, POINTER(CreatureExtract))
|
||||
v.extract = extract_p
|
||||
|
||||
arr_list.extend((v_caste_arr, caste_p, v_extract_arr, extract_p))
|
||||
|
||||
p = cast(c_arr, _creaturetype_ptr)
|
||||
ptr[0] = p
|
||||
|
||||
pointer_dict[addressof(c_arr)] = (ptr, c_arr, p, arr_list)
|
||||
|
||||
return 1
|
||||
|
||||
_alloc_creaturetype_buffer_functype = CFUNCTYPE(c_int, POINTER(_creaturetype_ptr), POINTER(CreatureTypeDescriptor), c_uint)
|
||||
_alloc_creaturetype_buffer_func = _alloc_creaturetype_buffer_functype(_alloc_creaturetype_buffer)
|
||||
_register_callback("alloc_creaturetype_buffer_callback", _alloc_creaturetype_buffer_func)
|
||||
|
||||
class GameModes(Structure):
|
||||
_fields_ = [("control_mode", c_ubyte),
|
||||
("game_mode", c_ubyte)]
|
||||
|
||||
class Hotkey(Structure):
|
||||
_fields_ = [("name", (c_char * 10)),
|
||||
("mode", c_short),
|
||||
("x", c_int),
|
||||
("y", c_int),
|
||||
("z", c_int)]
|
||||
|
||||
_hotkey_ptr = POINTER(Hotkey)
|
||||
|
||||
def _alloc_hotkey_buffer_callback(ptr, count):
|
||||
print "hotkey alloc: %d" % count
|
||||
return util._allocate_array(ptr, Hotkey, count)
|
||||
|
||||
_hotkey_functype = CFUNCTYPE(c_int, POINTER(_hotkey_ptr), c_uint)
|
||||
_hotkey_func = _hotkey_functype(_alloc_hotkey_buffer_callback)
|
||||
_register_callback("alloc_hotkey_buffer_callback", _hotkey_func)
|
||||
|
||||
class MemRange(Structure):
|
||||
_fields_ = [("start", c_ulong),
|
||||
("end", c_ulong),
|
||||
("name", (c_char * 1024)),
|
||||
("read", c_uint, 1),
|
||||
("write", c_uint, 1),
|
||||
("execute", c_uint, 1),
|
||||
("shared", c_uint, 1),
|
||||
("valid", c_ubyte),
|
||||
("buffer", POINTER(c_ubyte))]
|
||||
|
||||
_memrange_ptr = POINTER(MemRange)
|
||||
|
||||
def _alloc_memrange_buffer(ptr, descriptors, count):
|
||||
arr_list = []
|
||||
m_arr = (MemRange * count)()
|
||||
|
||||
for i, v in enumerate(m_arr):
|
||||
buf_arr = (c_ubyte * int(descriptors[i]))()
|
||||
buf_ptr = cast(buf_arr, POINTER(c_ubyte))
|
||||
|
||||
v.buffer = buf_ptr
|
||||
|
||||
arr_list.extend((buf_arr, buf_ptr))
|
||||
|
||||
p = cast(m_arr, _memrange_ptr)
|
||||
ptr[0] = p
|
||||
|
||||
pointer_dict[addressof(m_arr)] = (ptr, m_arr, p, arr_list)
|
||||
|
||||
return 1
|
||||
|
||||
_alloc_memrange_buffer_functype = CFUNCTYPE(c_int, POINTER(_memrange_ptr), POINTER(c_uint), c_uint)
|
||||
_alloc_memrange_buffer_func = _alloc_memrange_buffer_functype(_alloc_memrange_buffer)
|
||||
_register_callback("alloc_memrange_buffer_callback", _alloc_memrange_buffer_func)
|
@ -1,156 +0,0 @@
|
||||
#found this in the cookbook: http://code.activestate.com/recipes/576415/
|
||||
|
||||
from ctypes import c_uint
|
||||
|
||||
class C_EnumerationType(type(c_uint)):
|
||||
def __new__(metacls, name, bases, dictionary):
|
||||
if not "_members_" in dictionary:
|
||||
_members_ = {}
|
||||
|
||||
for key, value in dictionary.iteritems():
|
||||
if not key.startswith("_"):
|
||||
_members_[key] = value
|
||||
|
||||
dictionary["_members_"] = _members_
|
||||
|
||||
cls = type(c_uint).__new__(metacls, name, bases, dictionary)
|
||||
|
||||
for key, value in cls._members_.iteritems():
|
||||
globals()[key] = value
|
||||
|
||||
return cls
|
||||
|
||||
def __contains__(self, value):
|
||||
return value in self._members_.values()
|
||||
|
||||
def __repr__(self):
|
||||
return "<Enumeration %s>" % self.__name__
|
||||
|
||||
class C_Enumeration(c_uint):
|
||||
__metaclass__ = C_EnumerationType
|
||||
_members_ = {}
|
||||
|
||||
def __init__(self, value):
|
||||
for key, value in self._members_.iteritems():
|
||||
if v == value:
|
||||
self.name = key
|
||||
break
|
||||
else:
|
||||
raise ValueError("No enumeration member with value %r" % value)
|
||||
|
||||
c_uint.__init__(self, value)
|
||||
|
||||
def __repr__(self):
|
||||
return "<member %s=%d of %r>" % (self.name, self.value, self.__class__)
|
||||
|
||||
@classmethod
|
||||
def from_param(cls, param):
|
||||
if isinstance(param, C_Enumeration):
|
||||
if param.__class__ != cls:
|
||||
raise ValueError("Cannot mix enumeration members")
|
||||
else:
|
||||
return param
|
||||
else:
|
||||
return cls(param)
|
||||
|
||||
FeatureType = C_EnumerationType("FeatureType",
|
||||
(c_uint,),
|
||||
{"Other" : 0,
|
||||
"Adamantine_Tube" : 1,
|
||||
"Underworld" : 2,
|
||||
"Hell_Temple" : 3})
|
||||
|
||||
BiomeOffset = C_EnumerationType("BiomeOffset",
|
||||
(c_uint,),
|
||||
{"NorthWest" : 0,
|
||||
"North" : 1,
|
||||
"NorthEast" : 2,
|
||||
"West" : 3,
|
||||
"Here" : 4,
|
||||
"East" : 5,
|
||||
"SouthWest" : 6,
|
||||
"South" : 7,
|
||||
"SouthEast" : 8,
|
||||
"BiomeCount" : 9})
|
||||
|
||||
TrafficType = C_EnumerationType("TrafficType",
|
||||
(c_uint,),
|
||||
{"Normal" : 0,
|
||||
"Low" : 1,
|
||||
"High" : 2,
|
||||
"Restricted" : 3})
|
||||
|
||||
DesignationType = C_EnumerationType("DesignationType",
|
||||
(c_uint,),
|
||||
{"No" : 0,
|
||||
"Default" : 1,
|
||||
"UD_Stair" : 2,
|
||||
"Channel" : 3,
|
||||
"Ramp" : 4,
|
||||
"D_Stair" : 5,
|
||||
"U_Stair" : 6,
|
||||
"Whatever" : 7})
|
||||
|
||||
LiquidType = C_EnumerationType("LiquidType",
|
||||
(c_uint,),
|
||||
{"Water" : 0,
|
||||
"Magma" : 1})
|
||||
|
||||
#this list must stay in the same order as the one in dfhack/library/include/dfhack/modules/WindowIO.h!
|
||||
_keys = ["ENTER",
|
||||
"SPACE",
|
||||
"BACK_SPACE",
|
||||
"TAB",
|
||||
"CAPS_LOCK",
|
||||
"LEFT_SHIFT",
|
||||
"RIGHT_SHIFT",
|
||||
"LEFT_CONTROL",
|
||||
"RIGHT_CONTROL",
|
||||
"ALT",
|
||||
"WAIT",
|
||||
"ESCAPE",
|
||||
"UP",
|
||||
"DOWN",
|
||||
"LEFT",
|
||||
"RIGHT",
|
||||
"F1",
|
||||
"F2",
|
||||
"F3",
|
||||
"F4",
|
||||
"F5",
|
||||
"F6",
|
||||
"F7",
|
||||
"F8",
|
||||
"F9",
|
||||
"F10",
|
||||
"F11",
|
||||
"F12",
|
||||
"PAGE_UP",
|
||||
"PAGE_DOWN",
|
||||
"INSERT",
|
||||
"DFK_DELETE",
|
||||
"HOME",
|
||||
"END",
|
||||
"KEYPAD_DIVIDE",
|
||||
"KEYPAD_MULTIPLY",
|
||||
"KEYPAD_SUBTRACT",
|
||||
"KEYPAD_ADD,"
|
||||
"KEYPAD_ENTER",
|
||||
"KEYPAD_0",
|
||||
"KEYPAD_1",
|
||||
"KEYPAD_2",
|
||||
"KEYPAD_3",
|
||||
"KEYPAD_4",
|
||||
"KEYPAD_5",
|
||||
"KEYPAD_6",
|
||||
"KEYPAD_7",
|
||||
"KEYPAD_8",
|
||||
"KEYPAD_9",
|
||||
"KEYPAD_DECIMAL_POINT",
|
||||
"NUM_SPECIALS"]
|
||||
|
||||
_key_dict = dict([(k, i) for i, k in enumerate(_keys)])
|
||||
|
||||
KeyType = C_EnumerationType("KeyType",
|
||||
(c_uint,),
|
||||
_key_dict)
|
@ -1,201 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from ctypes import Structure, Union, c_uint
|
||||
from enum import *
|
||||
|
||||
class DesignationStruct(Structure):
|
||||
_fields_ = [("flow_size", c_uint, 3),
|
||||
("pile", c_uint, 1),
|
||||
("dig", DesignationType, 3),
|
||||
("smooth", c_uint, 2),
|
||||
("hidden", c_uint, 1),
|
||||
("geolayer_index", c_uint, 4),
|
||||
("light", c_uint, 1),
|
||||
("subterranean", c_uint, 1),
|
||||
("skyview", c_uint, 1),
|
||||
("biome", c_uint, 4),
|
||||
("liquid_type", c_uint, 1),
|
||||
("water_table", c_uint, 1),
|
||||
("rained", c_uint, 1),
|
||||
("traffic", c_uint, 2),
|
||||
("flow_forbid", c_uint, 1),
|
||||
("liquid_static", c_uint, 1),
|
||||
("feature_local", c_uint, 1),
|
||||
("feature_global", c_uint, 1),
|
||||
("water_stagnant", c_uint, 1),
|
||||
("water_salt", c_uint, 1)]
|
||||
|
||||
class DesignationFlags(Union):
|
||||
_fields_ = [("whole", c_uint, 32),
|
||||
("bits", DesignationStruct)]
|
||||
|
||||
def __init__(self, initial = 0):
|
||||
self.whole = initial
|
||||
|
||||
def __int__(self):
|
||||
return self.whole
|
||||
|
||||
class OccupancyStruct(Structure):
|
||||
_fields_ = [("building", c_uint, 3),
|
||||
("unit", c_uint, 1),
|
||||
("unit_grounded", c_uint, 1),
|
||||
("item", c_uint, 1),
|
||||
("splatter", c_uint, 26)]
|
||||
|
||||
class OccupancyFlags(Union):
|
||||
_fields_ = [("whole", c_uint, 32),
|
||||
("bits", OccupancyStruct)]
|
||||
|
||||
def __init__(self, initial = 0):
|
||||
self.whole = initial
|
||||
|
||||
def __int__(self):
|
||||
return self.whole
|
||||
|
||||
class CreatureStruct1(Structure):
|
||||
_fields_ = [("move_state", c_uint, 1),
|
||||
("dead", c_uint, 1),
|
||||
("has_mood", c_uint, 1),
|
||||
("had_mood", c_uint, 1),
|
||||
("marauder", c_uint, 1),
|
||||
("drowning", c_uint, 1),
|
||||
("merchant", c_uint, 1),
|
||||
("forest", c_uint, 1),
|
||||
("left", c_uint, 1),
|
||||
("rider", c_uint, 1),
|
||||
("incoming", c_uint, 1),
|
||||
("diplomat", c_uint, 1),
|
||||
("zombie", c_uint, 1),
|
||||
("skeleton", c_uint, 1),
|
||||
("can_swap", c_uint, 1),
|
||||
("on_ground", c_uint, 1),
|
||||
("projectile", c_uint, 1),
|
||||
("active_invader", c_uint, 1),
|
||||
("hidden_in_ambush", c_uint, 1),
|
||||
("invader_origin", c_uint, 1),
|
||||
("coward", c_uint, 1),
|
||||
("hidden_ambusher", c_uint, 1),
|
||||
("invades", c_uint, 1),
|
||||
("check_flows", c_uint, 1),
|
||||
("ridden", c_uint, 1),
|
||||
("caged", c_uint, 1),
|
||||
("tame", c_uint, 1),
|
||||
("chained", c_uint, 1),
|
||||
("royal_guard", c_uint, 1),
|
||||
("fortress_guard", c_uint, 1),
|
||||
("suppress_wield", c_uint, 1),
|
||||
("important_historical_figure", c_uint, 1)]
|
||||
|
||||
class CreatureFlags1(Union):
|
||||
_fields_ = [("whole", c_uint, 32),
|
||||
("bits", CreatureStruct1)]
|
||||
|
||||
def __init__(self, initial = 0):
|
||||
self.whole = initial
|
||||
|
||||
def __int__(self):
|
||||
return self.whole
|
||||
|
||||
class CreatureStruct2(Structure):
|
||||
_fields_ = [("swimming", c_uint, 1),
|
||||
("sparring", c_uint, 1),
|
||||
("no_notify", c_uint, 1),
|
||||
("unused", c_uint, 1),
|
||||
("calculated_nerves", c_uint, 1),
|
||||
("calculated_bodyparts", c_uint, 1),
|
||||
("important_historical_figure", c_uint, 1),
|
||||
("killed", c_uint, 1),
|
||||
("cleanup_1", c_uint, 1),
|
||||
("cleanup_2", c_uint, 1),
|
||||
("cleanup_3", c_uint, 1),
|
||||
("for_trade", c_uint, 1),
|
||||
("trade_resolved", c_uint, 1),
|
||||
("has_breaks", c_uint, 1),
|
||||
("gutted", c_uint, 1),
|
||||
("circulatory_spray", c_uint, 1),
|
||||
("locked_in_for_trading", c_uint, 1),
|
||||
("slaughter", c_uint, 1),
|
||||
("underworld", c_uint, 1),
|
||||
("resident", c_uint, 1),
|
||||
("cleanup_4", c_uint, 1),
|
||||
("calculated_insulation", c_uint, 1),
|
||||
("visitor_uninvited", c_uint, 1),
|
||||
("visitor", c_uint, 1),
|
||||
("calculated_inventory", c_uint, 1),
|
||||
("vision_good", c_uint, 1),
|
||||
("vision_damaged", c_uint, 1),
|
||||
("vision_missing", c_uint, 1),
|
||||
("breathing_good", c_uint, 1),
|
||||
("breathing_problem", c_uint, 1),
|
||||
("roaming_wilderness_population_source", c_uint, 1),
|
||||
("roaming_wilderness_population_source_not_a_map_feature", c_uint, 1)]
|
||||
|
||||
class CreatureFlags2(Union):
|
||||
_fields_ = [("whole", c_uint, 32),
|
||||
("bits", CreatureStruct2)]
|
||||
|
||||
def __init__(self, initial = 0):
|
||||
self.whole = initial
|
||||
|
||||
def __int__(self):
|
||||
return self.whole
|
||||
|
||||
class ItemStruct(Structure):
|
||||
_fields_ = [("on_ground", c_uint, 1),
|
||||
("in_job", c_uint, 1),
|
||||
("in_inventory", c_uint, 1),
|
||||
("u_ngrd1", c_uint, 1),
|
||||
("in_workshop", c_uint, 1),
|
||||
("u_ngrd2", c_uint, 1),
|
||||
("u_ngrd3", c_uint, 1),
|
||||
("rotten", c_uint, 1),
|
||||
("unk1", c_uint, 1),
|
||||
("u_ngrd4", c_uint, 1),
|
||||
("unk2", c_uint, 1),
|
||||
("u_ngrd5", c_uint, 1),
|
||||
("unk3", c_uint, 1),
|
||||
("u_ngrd6", c_uint, 1),
|
||||
("narrow", c_uint, 1),
|
||||
("u_ngrd7", c_uint, 1),
|
||||
("worn", c_uint, 1),
|
||||
("unk4", c_uint, 1),
|
||||
("u_ngrd8", c_uint, 1),
|
||||
("forbid", c_uint, 1),
|
||||
("unk5", c_uint, 1),
|
||||
("dump", c_uint, 1),
|
||||
("on_fire", c_uint, 1),
|
||||
("melt", c_uint, 1),
|
||||
("hidden", c_uint, 1),
|
||||
("u_ngrd9", c_uint, 1),
|
||||
("unk6", c_uint, 1),
|
||||
("unk7", c_uint, 1),
|
||||
("unk8", c_uint, 1),
|
||||
("unk9", c_uint, 1),
|
||||
("unk10", c_uint, 1),
|
||||
("unk11", c_uint, 1)]
|
||||
|
||||
class ItemFlags(Union):
|
||||
_fields_ = [("whole", c_uint, 32),
|
||||
("bits", ItemStruct)]
|
||||
|
||||
def __init__(self, initial = 0):
|
||||
self.whole = initial
|
||||
|
||||
def __int__(self):
|
||||
return self.whole
|
||||
|
||||
class BlockFlagStruct(Structure):
|
||||
_fields_ = [("designated", c_uint, 1),
|
||||
("unk_1", c_uint, 1),
|
||||
("liquid_1", c_uint, 1),
|
||||
("liquid_2", c_uint, 1),
|
||||
("unk_2", c_uint, 28)]
|
||||
|
||||
class BlockFlags(Union):
|
||||
_fields_ = [("whole", c_uint, 32),
|
||||
("bits", BlockFlagStruct)]
|
||||
|
||||
def __init__(self, inital = 0):
|
||||
self.whole = initial
|
||||
|
||||
def __int__(self):
|
||||
return self.whole
|
@ -1,73 +0,0 @@
|
||||
from ctypes import c_void_p, c_int, c_uint, byref
|
||||
from dftypes import libdfhack, ViewScreen, Hotkey
|
||||
from util import check_pointer_cache
|
||||
|
||||
libdfhack.Gui_getViewCoords.argtypes = [ c_void_p, POINTER(c_int), POINTER(c_int), POINTER(c_int) ]
|
||||
libdfhack.Gui_setViewCoords.argtypes = [ c_void_p, c_int, c_int, c_int ]
|
||||
|
||||
libdfhack.Gui_getCursorCoords.argtypes = [ c_void_p, POINTER(c_int), POINTER(c_int), POINTER(c_int) ]
|
||||
libdfhack.Gui_setCursorCoords.argtypes = [ c_void_p, c_int, c_int, c_int ]
|
||||
|
||||
libdfhack.Gui_getWindowSize.argtypes = [ c_void_p, POINTER(c_int), POINTER(c_int) ]
|
||||
|
||||
libdfhack.Gui_ReadViewScreen.argtypes = [ c_void_p, c_void_p ]
|
||||
|
||||
libdfhack.Gui_ReadHotkeys.restype = c_void_p
|
||||
|
||||
libdfhack.Gui_getScreenTiles.argtypes = [ c_void_p, c_int, c_int ]
|
||||
libdfhack.Gui_getScreenTiles.restype = c_void_p
|
||||
|
||||
class Gui(object):
|
||||
def __init__(self, ptr):
|
||||
self._gui_ptr = ptr
|
||||
|
||||
def start(self):
|
||||
return libdfhack.Gui_Start(self._gui_ptr) > 0
|
||||
|
||||
def finish(self):
|
||||
return libdfhack.Gui_Finish(self._gui_ptr) > 0
|
||||
|
||||
def read_view_screen(self):
|
||||
s = ViewScreen()
|
||||
|
||||
if libdfhack.Gui_ReadViewScreen(self._gui_ptr, byref(s)) > 0:
|
||||
return s
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_view_coords(self):
|
||||
x, y, z = (0, 0, 0)
|
||||
|
||||
if libdfhack.Gui_getViewCoords(self._gui_ptr, byref(x), byref(y), byref(z)) > 0:
|
||||
return (x, y, z)
|
||||
else:
|
||||
return (-1, -1, -1)
|
||||
|
||||
def set_view_coords(self, x, y, z):
|
||||
libdfhack.Gui_setViewCoords(self._gui_ptr, x, y, z)
|
||||
|
||||
def get_cursor_coords(self):
|
||||
x, y, z = (0, 0, 0)
|
||||
|
||||
if libdfhack.Gui_getCursorCoords(self._gui_ptr, byref(x), byref(y), byref(z)) > 0:
|
||||
return (x, y, z)
|
||||
else:
|
||||
return (-1, -1, -1)
|
||||
|
||||
def set_cursor_coords(self, x, y, z):
|
||||
libdfhack.Gui_setCursorCoords(self._gui_ptr, x, y, z)
|
||||
|
||||
def read_hotkeys(self):
|
||||
return check_pointer_cache(libdfhack.Gui_ReadHotkeys(self._gui_ptr))
|
||||
|
||||
def get_screen_tiles(self, width, height):
|
||||
return check_pointer_cache(libdfhack.Gui_getScreenTiles(self._gui_ptr, width, height))
|
||||
|
||||
@property
|
||||
def window_size(self):
|
||||
width, height = (0, 0)
|
||||
|
||||
if libdfhack.Gui_getWindowSize(self._gui_ptr, byref(width), byref(height)) > 0:
|
||||
return (width, height)
|
||||
else:
|
||||
return (-1, -1)
|
@ -1,33 +0,0 @@
|
||||
from ctypes import *
|
||||
from dftypes import *
|
||||
|
||||
libdfhack.Items_getItemDescription.argtypes = [ c_void_p, c_uint, c_void_ptr, _arr_create_func ]
|
||||
libdfhack.Items_getItemDescription.restype = c_char_p
|
||||
libdfhack.Items_getItemClass.argtypes = [ c_void_p, c_int, _arr_create_func ]
|
||||
libdfhack.Item_getItemClass.restype = c_char_p
|
||||
|
||||
class Items(object):
|
||||
def __init__(self, ptr):
|
||||
self._i_ptr = ptr
|
||||
|
||||
def get_item_description(self, itemptr, materials):
|
||||
def get_callback(count):
|
||||
item_string = create_string_buffer(count)
|
||||
|
||||
return byref(item_string)
|
||||
|
||||
item_string = None
|
||||
callback = _arr_create_func(get_callback)
|
||||
|
||||
return libdfhack.Items_getItemDescription(self._i_ptr, itemptr, materials, callback)
|
||||
|
||||
def get_item_class(self, index):
|
||||
def get_callback(count):
|
||||
item_string = create_string_buffer(count)
|
||||
|
||||
return byref(item_string)
|
||||
|
||||
item_string = None
|
||||
callback = _arr_create_func(get_callback)
|
||||
|
||||
return libdfhack.Items_getItemClass(self._i_ptr, index, callback)
|
@ -1,291 +0,0 @@
|
||||
from ctypes import *
|
||||
from dftypes import *
|
||||
from util import _uintify, int_ptr, uint_ptr, check_pointer_cache
|
||||
|
||||
_MAX_DIM = 0x300
|
||||
_MAX_DIM_SQR = _MAX_DIM * _MAX_DIM
|
||||
|
||||
libdfhack.Maps_getSize.argtypes = [ c_void_p, uint_ptr, uint_ptr, uint_ptr ]
|
||||
libdfhack.Maps_getPosition.argtypes = [ c_void_p, int_ptr, int_ptr, int_ptr ]
|
||||
|
||||
libdfhack.Maps_ReadTileTypes.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(TileTypes40d) ]
|
||||
libdfhack.Maps_WriteTileTypes.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(TileTypes40d) ]
|
||||
libdfhack.Maps_ReadDesignations.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(Designations40d) ]
|
||||
libdfhack.Maps_WriteDesignations.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(Designations40d) ]
|
||||
libdfhack.Maps_ReadTemperatures.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(Temperatures) ]
|
||||
libdfhack.Maps_WriteTemperatures.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(Temperatures) ]
|
||||
libdfhack.Maps_ReadOccupancy.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(Occupancies40d) ]
|
||||
libdfhack.Maps_WriteOccupancy.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(Occupancies40d) ]
|
||||
libdfhack.Maps_ReadRegionOffsets.argtypes = [ c_void_p, c_uint, c_uint, c_uint, POINTER(BiomeIndices40d) ]
|
||||
|
||||
libdfhack.Maps_ReadVegetation.restype = c_void_p
|
||||
|
||||
libdfhack.Maps_ReadStandardVeins.argtypes = [ c_void_p, c_uint, c_uint, c_uint ]
|
||||
libdfhack.Maps_ReadFrozenVeins.argtypes = [ c_void_p, c_uint, c_uint, c_uint ]
|
||||
libdfhack.Maps_ReadSpatterVeins.argtypes = [ c_void_p, c_uint, c_uint, c_uint ]
|
||||
libdfhack.Maps_ReadGrassVeins.argtypes = [ c_void_p, c_uint, c_uint, c_uint ]
|
||||
libdfhack.Maps_ReadWorldConstructions.argtypes = [ c_void_p, c_uint, c_uint, c_uint ]
|
||||
|
||||
libdfhack.Maps_ReadStandardVeins.restype = c_void_p
|
||||
libdfhack.Maps_ReadFrozenVeins.restype = c_void_p
|
||||
libdfhack.Maps_ReadSpatterVeins.restype = c_void_p
|
||||
libdfhack.Maps_ReadGrassVeins.restype = c_void_p
|
||||
libdfhack.Maps_ReadWorldConstructions.restype = c_void_p
|
||||
|
||||
libdfhack.Maps_ReadLocalFeatures.restype = c_void_p
|
||||
|
||||
class Maps(object):
|
||||
def __init__(self, ptr):
|
||||
self._map_ptr = ptr
|
||||
|
||||
def start(self):
|
||||
return libdfhack.Maps_Start(self._map_ptr) > 0
|
||||
|
||||
def finish(self):
|
||||
return libdfhack.Maps_Finish(self._map_ptr) > 0
|
||||
|
||||
def is_valid_block(self, x, y, z):
|
||||
return libdfhack.Maps_isValidBlock(self._map_ptr, *_uintify(x, y, z)) > 0
|
||||
|
||||
def read_tile_types(self, x, y, z):
|
||||
tt = TileTypes40d()
|
||||
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
if libdfhack.Maps_ReadTileTypes(self._map_ptr, ux, uy, uz, tt) > 0:
|
||||
return tt
|
||||
else:
|
||||
return None
|
||||
|
||||
def write_tile_types(self, x, y, z, tt):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return libdfhack.Maps_WriteTileTypes(self._map_ptr, ux, uy, uz, tt) > 0
|
||||
|
||||
def read_designations(self, x, y, z):
|
||||
d = Designations40d()
|
||||
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
if libdfhack.Maps_ReadDesignations(self._map_ptr, ux, uy, uz, byref(d)) > 0:
|
||||
return d
|
||||
else:
|
||||
return None
|
||||
|
||||
def write_designations(self, x, y, z, d):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return libdfhack.Maps_WriteDesignations(self._map_ptr, ux, uy, uz, byref(d)) > 0
|
||||
|
||||
def read_temperatures(self, x, y, z):
|
||||
t = Temperatures()
|
||||
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
if libdfhack.Maps_ReadDesignations(self._map_ptr, ux, uy, uz, t) > 0:
|
||||
return t
|
||||
else:
|
||||
return None
|
||||
|
||||
def write_temperatures(self, x, y, z, t):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return libdfhack.Maps_WriteDesignations(self._map_ptr, ux, uy, uz, t) > 0
|
||||
|
||||
def read_occupancy(self, x, y, z):
|
||||
o = Occupancies40d()
|
||||
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
if libdfhack.Maps_ReadDesignations(self._map_ptr, ux, uy, uz, o) > 0:
|
||||
return o
|
||||
else:
|
||||
return None
|
||||
|
||||
def write_occupancy(self, x, y, z, o):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return libdfhack.Maps_WriteDesignations(self._map_ptr, ux, uy, uz, byref(o)) > 0
|
||||
|
||||
def read_dirty_bit(self, x, y, z):
|
||||
bit = c_int(0)
|
||||
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
if libdfhack.Maps_ReadDirtyBit(self._map_ptr, ux, uy, uz, byref(bit)) > 0:
|
||||
if bit > 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return None
|
||||
|
||||
def write_dirty_bit(self, x, y, z, dirty):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return libdfhack.Maps_WriteDirtyBit(self._map_ptr, ux, uy, uz, c_int(dirty)) > 0
|
||||
|
||||
def read_features(self, x, y, z):
|
||||
lf = c_short()
|
||||
gf = c_short()
|
||||
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
libdfhack.Maps_ReadFeatures(self._map_ptr, ux, uy, uz, byref(lf), byref(fg))
|
||||
|
||||
return (lf, gf)
|
||||
|
||||
def write_local_feature(self, x, y, z, local_feature = -1):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return libdfhack.Maps_WriteLocalFeature(self._map_ptr, ux, uy, uz, c_short(local_feature)) > 0
|
||||
|
||||
def write_global_feature(self, x, y, z, global_feature = -1):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return libdfhack.Maps_WriteGlobalFeature(self._map_ptr, ux, uy, uz, c_short(global_feature)) > 0
|
||||
|
||||
def read_block_flags(self, x, y, z):
|
||||
bf = BlockFlags()
|
||||
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
if libdfhack.Maps_ReadBlockFlags(self._map_ptr, ux, uy, uz, byref(bf)) > 0:
|
||||
return bf
|
||||
else:
|
||||
return None
|
||||
|
||||
def write_block_flags(self, x, y, z, block_flags):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return libdfhack.Maps_WriteBlockFlags(self._map_ptr, ux, uy, uz, block_flags) > 0
|
||||
|
||||
def read_region_offsets(self, x, y, z):
|
||||
bi = BiomeIndices40d()
|
||||
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
if libdfhack.Maps_ReadRegionOffsets(self._map_ptr, ux, uy, uz, byref(bi)) > 0:
|
||||
return bi
|
||||
else:
|
||||
return None
|
||||
|
||||
def read_veins(self, x, y, z):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return check_pointer_cache(libdfhack.Maps_ReadStandardVeins(self._map_ptr, ux, uy, uz))
|
||||
|
||||
def read_frozen_veins(self, x, y, z):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return check_pointer_cache(libdfhack.Maps_ReadFrozenVeins(self._map_ptr, ux, uy, uz))
|
||||
|
||||
def read_spatter_veins(self, x, y, z):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return check_pointer_cache(libdfhack.Maps_ReadSpatterVeins(self._map_ptr, ux, uy, uz))
|
||||
|
||||
def read_grass_veins(self, x, y, z):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return check_pointer_cache(libdfhack.Maps_ReadGrassVeins(self._map_ptr, ux, uy, uz))
|
||||
|
||||
def read_world_constructions(self, x, y, z):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return check_pointer_cache(libdfhack.Maps_ReadWorldConstructions(self._map_ptr, ux, uy, uz))
|
||||
|
||||
def read_vegetation(self, x, y, z):
|
||||
ux, uy, uz = _uintify(x, y, z)
|
||||
|
||||
return check_pointer_cache(libdfhack.Maps_ReadVegetation(self._map_ptr, ux, uy, uz))
|
||||
|
||||
def read_local_features(self):
|
||||
f = libdfhack.Maps_ReadLocalFeatures(self._map_ptr)
|
||||
feature_dict = {}
|
||||
f_arr = check_pointer_cache(f, False)
|
||||
|
||||
if f_arr is not None:
|
||||
for node in f_arr:
|
||||
c = node.coordinate.xyz
|
||||
coord = MapPoint(c.x, c.y, c.z)
|
||||
f_list = [node.features[i] for i in xrange(node.feature_length)]
|
||||
feature_dict[coord] = f_list
|
||||
|
||||
return feature_dict
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
x, y, z = (c_uint(0), c_uint(0), c_uint(0))
|
||||
|
||||
retval = libdfhack.Maps_getSize(self._map_ptr, byref(x), byref(y), byref(z))
|
||||
|
||||
return (int(x.value), int(y.value), int(z.value))
|
||||
|
||||
@property
|
||||
def position(self):
|
||||
x, y, z = (c_int(0), c_int(0), c_int(0))
|
||||
|
||||
libdfhack.Maps_getPosition(self._map_ptr, byref(x), byref(y), byref(z))
|
||||
|
||||
return (int(x.value), int(y.value), int(z.value))
|
||||
|
||||
class MapPoint(object):
|
||||
__slots__ = ["_x", "_y", "_z", "_cmp_val"]
|
||||
|
||||
def __init__(self, x = 0, y = 0, z = 0):
|
||||
self._x, self._y, self._z = x, y, z
|
||||
|
||||
self._cmp_val = self._get_cmp_value()
|
||||
|
||||
def _val_set(self, which, val):
|
||||
if which == 0:
|
||||
self._x = val
|
||||
elif which == 1:
|
||||
self._y = val
|
||||
elif which == 2:
|
||||
self._z = val
|
||||
|
||||
self._cmp_val = self._get_cmp_value()
|
||||
|
||||
x = property(fget = lambda self: self._x, fset = lambda self, v: self._val_set(0, v))
|
||||
y = property(fget = lambda self: self._y, fset = lambda self, v: self._val_set(1, v))
|
||||
z = property(fget = lambda self: self._z, fset = lambda self, v: self._val_set(2, v))
|
||||
|
||||
def _get_cmp_value(self):
|
||||
return (self.z * _MAX_DIM_SQR) + (self.y * _MAX_DIM) + self.x
|
||||
|
||||
#comparison operators
|
||||
def __eq__(self, other):
|
||||
return self.x == other.x and self.y == other.y and self.z == other.z
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._cmp_val < other._cmp_val
|
||||
|
||||
def __le__(self, other):
|
||||
return self < other or self == other
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._cmp_val > other._cmp_val
|
||||
|
||||
def __ge__(self, other):
|
||||
return self > other or self == other
|
||||
|
||||
#arithmetic operators
|
||||
def __add__(self, num):
|
||||
return MapPoint(self.x, self.y, self.z + num)
|
||||
|
||||
def __sub__(self, num):
|
||||
return MapPoint(self.x, self.y, self.z - num)
|
||||
|
||||
def __div__(self, num):
|
||||
return MapPoint(self.x / num, self.y / num, self.z)
|
||||
|
||||
def __mul__(self, num):
|
||||
return MapPoint(self.x * num, self.y * num, self.z)
|
||||
|
||||
def __mod__(self, num):
|
||||
return MapPoint(self.x % num, self.y % num, self.z)
|
@ -1,166 +0,0 @@
|
||||
from ctypes import *
|
||||
import dftypes
|
||||
from dftypes import libdfhack, Matgloss, CreatureType, DescriptorColor, MatglossOther
|
||||
from util import check_pointer_cache
|
||||
|
||||
libdfhack.Materials_getInorganic.restype = c_void_p
|
||||
libdfhack.Materials_getOrganic.restype = c_void_p
|
||||
libdfhack.Materials_getTree.restype = c_void_p
|
||||
libdfhack.Materials_getPlant.restype = c_void_p
|
||||
libdfhack.Materials_getRace.restype = c_void_p
|
||||
libdfhack.Materials_getRaceEx.restype = c_void_p
|
||||
libdfhack.Materials_getColor.restype = c_void_p
|
||||
libdfhack.Materials_getOther.restype = c_void_p
|
||||
libdfhack.Materials_getAllDesc.restype = c_void_p
|
||||
|
||||
class Materials(object):
|
||||
def __init__(self, ptr):
|
||||
self._mat_ptr = ptr
|
||||
|
||||
self.inorganic = None
|
||||
self.organic = None
|
||||
self.tree = None
|
||||
self.plant = None
|
||||
self.race = None
|
||||
self.race_ex = None
|
||||
self.color = None
|
||||
self.other = None
|
||||
|
||||
def _get_inorganic(self):
|
||||
self.inorganic = check_pointer_cache(libdfhack.Materials_getInorganic(self._mat_ptr))
|
||||
|
||||
def _get_organic(self):
|
||||
self.organic = check_pointer_cache(libdfhack.Materials_getOrganic(self._mat_ptr))
|
||||
|
||||
def _get_tree(self):
|
||||
self.tree = check_pointer_cache(libdfhack.Materials_getTree(self._mat_ptr))
|
||||
|
||||
def _get_plant(self):
|
||||
self.plant = check_pointer_cache(libdfhack.Materials_getPlant(self._mat_ptr))
|
||||
|
||||
def _get_race(self):
|
||||
self.race = check_pointer_cache(libdfhack.Materials_getRace(self._mat_ptr))
|
||||
|
||||
def _get_race_ex(self):
|
||||
self.race_ex = check_pointer_cache(libdfhack.Materials_getRaceEx(self._mat_ptr))
|
||||
|
||||
def _get_color(self):
|
||||
self.color = check_pointer_cache(libdfhack.Materials_getColor(self._mat_ptr))
|
||||
|
||||
def _get_other(self):
|
||||
self.other = check_pointer_cache(libdfhack.Materials_getOther(self._mat_ptr))
|
||||
|
||||
def _get_all(self):
|
||||
self._get_inorganic()
|
||||
self._get_organic()
|
||||
self._get_tree()
|
||||
self._get_plant()
|
||||
self._get_race()
|
||||
self._get_race_ex()
|
||||
self._get_color()
|
||||
self._get_other()
|
||||
def _clear_all(self):
|
||||
self.inorganic = None
|
||||
self.organic = None
|
||||
self.tree = None
|
||||
self.plant = None
|
||||
self.race = None
|
||||
self.race_ex = None
|
||||
self.color = None
|
||||
self.other = None
|
||||
|
||||
def read_inorganic(self):
|
||||
result = libdfhack.Materials_ReadInorganicMaterials(self._mat_ptr) > 0
|
||||
|
||||
if result == True:
|
||||
self._get_inorganic()
|
||||
else:
|
||||
self.inorganic = None
|
||||
|
||||
return result
|
||||
|
||||
def read_organic(self):
|
||||
result = libdfhack.Materials_ReadOrganicMaterials(self._mat_ptr) > 0
|
||||
|
||||
if result == True:
|
||||
self._get_organic()
|
||||
else:
|
||||
self.organic = None
|
||||
|
||||
return result
|
||||
|
||||
def read_tree(self):
|
||||
result = libdfhack.Materials_ReadWoodMaterials(self._mat_ptr) > 0
|
||||
|
||||
if result == True:
|
||||
self._get_tree()
|
||||
else:
|
||||
self.tree = None
|
||||
|
||||
return result
|
||||
|
||||
def read_plant(self):
|
||||
result = libdfhack.Materials_ReadPlantMaterials(self._mat_ptr) > 0
|
||||
|
||||
if result == True:
|
||||
self._get_plant()
|
||||
else:
|
||||
self.plant = None
|
||||
|
||||
return result
|
||||
|
||||
def read_creature_types(self):
|
||||
result = libdfhack.Materials_ReadCreatureTypes(self._mat_ptr) > 0
|
||||
|
||||
if result == True:
|
||||
self._get_race()
|
||||
else:
|
||||
self.race = None
|
||||
|
||||
return result
|
||||
|
||||
def read_creature_types_ex(self):
|
||||
result = libdfhack.Materials_ReadCreatureTypesEx(self._mat_ptr) > 0
|
||||
|
||||
if result == True:
|
||||
self._get_race_ex()
|
||||
else:
|
||||
self.race_ex = None
|
||||
|
||||
return result
|
||||
|
||||
def read_descriptor_colors(self):
|
||||
result = libdfhack.Materials_ReadDescriptorColors(self._mat_ptr) > 0
|
||||
|
||||
if result == True:
|
||||
self._get_color()
|
||||
else:
|
||||
self.color = None
|
||||
|
||||
return result
|
||||
|
||||
def read_others(self):
|
||||
result = libdfhack.Materials_ReadOthers(self._mat_ptr) > 0
|
||||
|
||||
if result == True:
|
||||
self._get_other()
|
||||
else:
|
||||
self.other = None
|
||||
|
||||
return result
|
||||
|
||||
def read_all(self):
|
||||
result = libdfhack.Materials_ReadAllMaterials(self._mat_ptr) > 0
|
||||
|
||||
if result == True:
|
||||
self._get_all()
|
||||
else:
|
||||
self._clear_all()
|
||||
|
||||
return result
|
||||
|
||||
def get_type(self, material):
|
||||
return libdfhack.Materials_getType(self._mat_ptr, byref(material))
|
||||
|
||||
def get_description(self, material):
|
||||
return libdfhack.Materials_getDescription(self._mat_ptr, byref(material))
|
@ -1,135 +0,0 @@
|
||||
from ctypes import *
|
||||
from dftypes import libdfhack
|
||||
from util import check_pointer_cache
|
||||
|
||||
libdfhack.Process_readQuad.argtypes = [ c_void_p, c_uint, POINTER(c_ulong) ]
|
||||
libdfhack.Process_writeQuad.argtypes = [ c_void_p, c_uint, c_ulong ]
|
||||
|
||||
libdfhack.Process_readDWord.argtypes = [ c_void_p, c_uint, POINTER(c_uint) ]
|
||||
libdfhack.Process_writeDWord.argtypes = [ c_void_p, c_uint, c_uint ]
|
||||
|
||||
libdfhack.Process_readWord.argtypes = [ c_void_p, c_uint, POINTER(c_ushort) ]
|
||||
libdfhack.Process_writeWord.argtypes = [ c_void_p, c_uint, c_ushort ]
|
||||
|
||||
libdfhack.Process_readByte.argtypes = [ c_void_p, c_uint, POINTER(c_ubyte) ]
|
||||
libdfhack.Process_writeByte.argtypes = [ c_void_p, c_uint, c_ubyte ]
|
||||
|
||||
libdfhack.Process_readFloat.argtypes = [ c_void_p, c_uint, POINTER(c_float) ]
|
||||
|
||||
libdfhack.Process_read.argtypes = [ c_void_p, c_uint, c_uint ]
|
||||
libdfhack.Process_read.restype = c_void_p
|
||||
|
||||
libdfhack.Process_write.argtypes = [ c_void_p, c_uint, c_uint, POINTER(c_ubyte) ]
|
||||
|
||||
libdfhack.Process_getThreadIDs.restype = c_void_p
|
||||
|
||||
class Process(object):
|
||||
def __init__(self, ptr):
|
||||
self._p_ptr = ptr
|
||||
|
||||
def attach(self):
|
||||
return libdfhack.Process_attach(self._p_ptr) > 0
|
||||
|
||||
def detach(self):
|
||||
return libdfhack.Process_detach(self._p_ptr) > 0
|
||||
|
||||
def suspend(self):
|
||||
return libdfhack.Process_suspend(self._p_ptr) > 0
|
||||
|
||||
def async_suspend(self):
|
||||
return libdfhack.Process_asyncSuspend(self._p_ptr) > 0
|
||||
|
||||
def resume(self):
|
||||
return libdfhack.Process_resume(self._p_ptr) > 0
|
||||
|
||||
def force_resume(self):
|
||||
return libdfhack.Process_forceresume(self._p_ptr) > 0
|
||||
|
||||
def read_quad(self, address):
|
||||
q = c_ulong(0)
|
||||
|
||||
if libdfhack.Process_readQuad(self._p_ptr, address, byref(q)) > 0:
|
||||
return long(q.value)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def write_quad(self, address, value):
|
||||
return libdfhack.Process_writeQuad(self._p_ptr, address, value) > 0
|
||||
|
||||
def read_dword(self, address):
|
||||
d = c_uint(0)
|
||||
|
||||
if libdfhack.Process_readDWord(self._p_ptr, address, byref(d)) > 0:
|
||||
return int(d.value)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def write_dword(self, address, value):
|
||||
return libdfhack.Process_writeDWord(self._p_ptr, address, value) > 0
|
||||
|
||||
def read_word(self, address):
|
||||
s = c_ushort(0)
|
||||
|
||||
if libdfhack.Process_readWord(self._p_ptr, address, byref(s)) > 0:
|
||||
return int(s.value)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def write_word(self, address, value):
|
||||
return libdfhack.Process_writeWord(self._p_ptr, address, value) > 0
|
||||
|
||||
def read_byte(self, address):
|
||||
b = c_ubyte(0)
|
||||
|
||||
if libdfhack.Process_readByte(self._p_ptr, address, byref(b)) > 0:
|
||||
return int(b.value)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def write_byte(self, address, value):
|
||||
return libdfhack.Process_writeByte(self._p_ptr, address, value) > 0
|
||||
|
||||
def read_float(self, address):
|
||||
f = c_float(0)
|
||||
|
||||
if libdfhack.Process_readFloat(self._p_ptr, address, byref(f)) > 0:
|
||||
return float(f.value)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def read(self, address, length):
|
||||
return check_pointer_cache(libdfhack.Process_read(self._p_ptr, address, length))
|
||||
|
||||
def write(self, address, length, buffer):
|
||||
libdfhack.Process_write(self._p_ptr, address, length, byref(buffer))
|
||||
|
||||
def get_thread_ids(self):
|
||||
return check_pointer_cache(libdfhack.Process_getThreadIDs(self._p_ptr))
|
||||
|
||||
def set_and_wait(self, state):
|
||||
return libdfhack.Process_SetAndWait(self._p_ptr, state) > 0
|
||||
|
||||
@property
|
||||
def is_suspended(self):
|
||||
return libdfhack.Process_isSuspended(self._p_ptr) > 0
|
||||
|
||||
@property
|
||||
def is_attached(self):
|
||||
return libdfhack.Process_isAttached(self._p_ptr) > 0
|
||||
|
||||
@property
|
||||
def is_identified(self):
|
||||
return libdfhack.Process_isIdentified(self._p_ptr) > 0
|
||||
|
||||
@property
|
||||
def is_snapshot(self):
|
||||
return libdfhack.Process_isSnapshot(self._p_ptr) > 0
|
||||
|
||||
@property
|
||||
def pid(self):
|
||||
p = c_int(0)
|
||||
|
||||
if libdfhack.Process_getPID(self._p_ptr, byref(p)) > 0:
|
||||
return int(p.value)
|
||||
else:
|
||||
return -1
|
@ -1,88 +0,0 @@
|
||||
from ctypes import *
|
||||
|
||||
int_ptr = POINTER(c_int)
|
||||
uint_ptr = POINTER(c_uint)
|
||||
|
||||
short_ptr = POINTER(c_short)
|
||||
ushort_ptr = POINTER(c_ushort)
|
||||
|
||||
byte_ptr = POINTER(c_byte)
|
||||
ubyte_ptr = POINTER(c_ubyte)
|
||||
|
||||
pointer_dict = {}
|
||||
|
||||
def check_pointer_cache(address, return_as_list = True):
|
||||
arr = None
|
||||
|
||||
if address in pointer_dict:
|
||||
arr = pointer_dict[address][1]
|
||||
del pointer_dict[address]
|
||||
|
||||
if return_as_list == True:
|
||||
arr = [i for i in arr]
|
||||
|
||||
return arr
|
||||
|
||||
def _uintify(x, y, z):
|
||||
return (c_uint(x), c_uint(y), c_uint(z))
|
||||
|
||||
def _allocate_array(ptr, t_type, count):
|
||||
arr = (t_type * count)()
|
||||
|
||||
p = cast(arr, POINTER(t_type))
|
||||
|
||||
ptr[0] = p
|
||||
|
||||
pointer_dict[addressof(arr)] = (ptr, arr, p)
|
||||
|
||||
return 1
|
||||
|
||||
def _alloc_int_buffer(ptr, count):
|
||||
return _allocate_array(ptr, c_int, count)
|
||||
|
||||
_int_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_int)), c_uint)
|
||||
alloc_int_buffer = _int_functype(_alloc_int_buffer)
|
||||
|
||||
def _alloc_uint_buffer(ptr, count):
|
||||
return _allocate_array(ptr, c_uint, count)
|
||||
|
||||
_uint_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_uint)), c_uint)
|
||||
alloc_uint_buffer = _uint_functype(_alloc_uint_buffer)
|
||||
|
||||
def _alloc_short_buffer(ptr, count):
|
||||
return _allocate_array(ptr, c_short, count)
|
||||
|
||||
_short_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_short)), c_uint)
|
||||
alloc_short_buffer = _short_functype(_alloc_short_buffer)
|
||||
|
||||
def _alloc_ushort_buffer(ptr, count):
|
||||
return _allocate_array(ptr, c_ushort, count)
|
||||
|
||||
_ushort_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_ushort)), c_uint)
|
||||
alloc_ushort_buffer = _ushort_functype(_alloc_ushort_buffer)
|
||||
|
||||
def _alloc_byte_buffer(ptr, count):
|
||||
return _allocate_array(ptr, c_byte, count)
|
||||
|
||||
_byte_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_byte)), c_uint)
|
||||
alloc_byte_buffer = _byte_functype(_alloc_byte_buffer)
|
||||
|
||||
def _alloc_ubyte_buffer(ptr, count):
|
||||
return _allocate_array(ptr, c_ubyte, count)
|
||||
|
||||
_ubyte_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_ubyte)), c_uint)
|
||||
alloc_ubyte_buffer = _ubyte_functype(_alloc_ubyte_buffer)
|
||||
|
||||
def _alloc_char_buffer(ptr, count):
|
||||
c = create_string_buffer(count)
|
||||
|
||||
p = cast(c, POINTER(c_char))
|
||||
|
||||
ptr[0] = p
|
||||
|
||||
pointer_dict[id(ptr[0])] = (ptr, c, p)
|
||||
|
||||
return 1
|
||||
|
||||
_char_functype = CFUNCTYPE(c_int, POINTER(POINTER(c_char)), c_uint)
|
||||
alloc_char_buffer = _char_functype(_alloc_char_buffer)
|
@ -1,25 +0,0 @@
|
||||
from ctypes import *
|
||||
from dftypes import libdfhack, Tree
|
||||
|
||||
class Vegetation(object):
|
||||
def __init__(self, ptr):
|
||||
self._v_ptr = ptr
|
||||
|
||||
def start(self):
|
||||
n = c_uint(0)
|
||||
|
||||
if libdfhack.Vegetation_Start(self._v_ptr, byref(n)) > 0:
|
||||
return int(n.value)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def finish(self):
|
||||
return libdfhack.Vegetation_Finish(self._v_ptr) > 0
|
||||
|
||||
def read(self, index):
|
||||
t = Tree()
|
||||
|
||||
if libdfhack.Vegetation_Read(self._v_ptr, c_uint(index), byref(t)) > 0:
|
||||
return t
|
||||
else:
|
||||
return None
|
@ -1,26 +0,0 @@
|
||||
from ctypes import *
|
||||
from dftypes import libdfhack
|
||||
|
||||
libdfhack.WindowIO_TypeStr.argtypes = [ c_void_p, c_char_p, c_uint, c_byte ]
|
||||
libdfhack.WindowIO_TypeSpecial.argtypes = [ c_void_p, c_uint, c_uint, c_uint, c_uint ]
|
||||
|
||||
class WindowIO(object):
|
||||
def __init__(self, ptr):
|
||||
self._window_io_ptr = ptr
|
||||
|
||||
def type_str(self, s, delay = 0, use_shift = False):
|
||||
c_shift = c_byte(0)
|
||||
c_delay = c_uint(delay)
|
||||
c_s = c_char_p(s)
|
||||
|
||||
if use_shift is True:
|
||||
c_shift = c_byte(1)
|
||||
|
||||
return libdfhack.WindowIO_TypeStr(self._window_io_ptr, c_s, c_delay, c_shift) > 0
|
||||
|
||||
def type_special(self, command, count = 1, delay = 0):
|
||||
c_command = c_uint(command)
|
||||
c_count = c_uint(count)
|
||||
c_delay = c_uint(delay)
|
||||
|
||||
return libdfhack.WindowIO_TypeSpecial(self._window_io_ptr, c_command, c_count, c_delay) > 0
|
@ -1,80 +0,0 @@
|
||||
from ctypes import *
|
||||
from dftypes import libdfhack, GameModes
|
||||
from util import _uintify, uint_ptr
|
||||
|
||||
libdfhack.World_ReadGameMode.argtypes = [ c_void_p, POINTER(GameModes) ]
|
||||
|
||||
class World(object):
|
||||
def __init__(self, ptr):
|
||||
self._world_ptr = ptr
|
||||
|
||||
def start(self):
|
||||
return libdfhack.World_Start(self._world_ptr) > 0
|
||||
|
||||
def finish(self):
|
||||
return libdfhack.World_Finish(self._world_ptr) > 0
|
||||
|
||||
def read_pause_state(self):
|
||||
return libdfhack.World_ReadPauseState(self._world_ptr) > 0
|
||||
|
||||
def set_pause_state(self, pause_state):
|
||||
p = c_byte(0)
|
||||
|
||||
if pause_state is not None and pause_state is not False:
|
||||
p.value = 1
|
||||
|
||||
return libdfhack.World_SetPauseState(self._world_ptr, p) > 0
|
||||
|
||||
def read_current_tick(self):
|
||||
tick = c_uint(0)
|
||||
|
||||
if libdfhack.World_ReadCurrentTick(self._world_ptr, byref(tick)) > 0:
|
||||
return int(tick)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def read_current_year(self):
|
||||
year = c_uint(0)
|
||||
|
||||
if libdfhack.World_ReadCurrentYear(self._world_ptr, byref(year)) > 0:
|
||||
return int(year)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def read_current_month(self):
|
||||
month = c_uint(0)
|
||||
|
||||
if libdfhack.World_ReadCurrentMonth(self._world_ptr, byref(month)) > 0:
|
||||
return int(month)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def read_current_day(self):
|
||||
day = c_uint(0)
|
||||
|
||||
if libdfhack.World_ReadCurrentDay(self._world_ptr, byref(day)) > 0:
|
||||
return int(day)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def read_current_weather(self):
|
||||
weather = c_ubyte(0)
|
||||
|
||||
if libdfhack.World_ReadCurrentWeather(self._world_ptr, byref(weather)) > 0:
|
||||
return int(weather)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def write_current_weather(self, weather):
|
||||
return libdfhack.World_WriteCurrentWeather(self._world_ptr, c_ubyte(weather))
|
||||
|
||||
def read_game_mode(self):
|
||||
game_modes = GameModes()
|
||||
|
||||
if libdfhack.World_ReadGameMode(self._world_ptr, byref(game_modes)) > 0:
|
||||
return game_modes
|
||||
else:
|
||||
return None
|
||||
|
||||
def write_game_mode(self, game_mode):
|
||||
return libdfhack.World_WriteGameMode(self._world_ptr, game_modes) > 0
|
@ -1,3 +0,0 @@
|
||||
[Project]
|
||||
Manager=KDevCMakeManager
|
||||
Name=dfhack
|
@ -0,0 +1,751 @@
|
||||
/*
|
||||
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 "dfhack/Console.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#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>
|
||||
#include <dfhack/FakeSDL.h>
|
||||
using namespace DFHack;
|
||||
|
||||
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 std::stringbuf
|
||||
{
|
||||
public:
|
||||
Private()
|
||||
{
|
||||
dfout_C = NULL;
|
||||
rawmode = false;
|
||||
supported_terminal = false;
|
||||
state = con_unclaimed;
|
||||
};
|
||||
virtual ~Private()
|
||||
{
|
||||
//sync();
|
||||
}
|
||||
protected:
|
||||
int sync()
|
||||
{
|
||||
print(str().c_str());
|
||||
str(std::string()); // Clear the string buffer
|
||||
return 0;
|
||||
}
|
||||
public:
|
||||
/// Print a formatted string, like printf
|
||||
int print(const char * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
int ret = vprint( format, args );
|
||||
va_end( args );
|
||||
return ret;
|
||||
}
|
||||
int vprint(const char * format, va_list vl)
|
||||
{
|
||||
if(state == con_lineedit)
|
||||
{
|
||||
disable_raw();
|
||||
fprintf(dfout_C,"\x1b[1G");
|
||||
fprintf(dfout_C,"\x1b[0K");
|
||||
int ret = vfprintf( dfout_C, format, vl );
|
||||
enable_raw();
|
||||
prompt_refresh();
|
||||
return ret;
|
||||
}
|
||||
else return vfprintf( dfout_C, format, vl );
|
||||
}
|
||||
int vprinterr(const char * format, va_list vl)
|
||||
{
|
||||
if(state == con_lineedit)
|
||||
{
|
||||
disable_raw();
|
||||
color(Console::COLOR_LIGHTRED);
|
||||
fprintf(dfout_C,"\x1b[1G");
|
||||
fprintf(dfout_C,"\x1b[0K");
|
||||
int ret = vfprintf( dfout_C, format, vl );
|
||||
reset_color();
|
||||
enable_raw();
|
||||
prompt_refresh();
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
color(Console::COLOR_LIGHTRED);
|
||||
int ret = vfprintf( dfout_C, format, vl );
|
||||
reset_color();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/// Print a formatted string, like printf, in red
|
||||
int printerr(const char * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
int ret = vprinterr( format, args );
|
||||
va_end( args );
|
||||
return ret;
|
||||
}
|
||||
/// 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)
|
||||
{
|
||||
print("\033[%d;%dH", y,x);
|
||||
}
|
||||
/// 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, SDL::Mutex * lock)
|
||||
{
|
||||
output.clear();
|
||||
this->prompt = prompt;
|
||||
if (!supported_terminal)
|
||||
{
|
||||
print(prompt.c_str());
|
||||
fflush(dfout_C);
|
||||
// FIXME: what do we do here???
|
||||
//SDL_mutexV(lock);
|
||||
std::getline(std::cin, output);
|
||||
//SDL_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);
|
||||
state = con_unclaimed;
|
||||
disable_raw();
|
||||
print("\n");
|
||||
if(count != -1)
|
||||
{
|
||||
output = raw_buffer;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
/// add a command to the history
|
||||
void history_add(const std::string& command)
|
||||
{
|
||||
// if current command = last in history -> do not add. Always add if history is empty.
|
||||
if(!history.empty() && history.front() == command)
|
||||
return;
|
||||
history.push_front(command);
|
||||
if(history.size() > 100)
|
||||
history.pop_back();
|
||||
}
|
||||
/// clear the command history
|
||||
void history_clear();
|
||||
|
||||
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)
|
||||
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
// 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(SDL::Mutex * lock)
|
||||
{
|
||||
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)
|
||||
{
|
||||
char c;
|
||||
int nread;
|
||||
char seq[2], seq2;
|
||||
SDL_mutexV(lock);
|
||||
nread = ::read(fd,&c,1);
|
||||
SDL_mutexP(lock);
|
||||
if (nread <= 0) return raw_buffer.size();
|
||||
|
||||
/* 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.pop_front();
|
||||
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
|
||||
SDL_mutexV(lock);
|
||||
if (::read(fd,seq,2) == -1)
|
||||
{
|
||||
SDL_mutexP(lock);
|
||||
break;
|
||||
}
|
||||
SDL_mutexP(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 (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 (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
|
||||
SDL_mutexV(lock);
|
||||
if (::read(fd,&seq2,1) == -1)
|
||||
{
|
||||
SDL_mutexP(lock);
|
||||
break;
|
||||
}
|
||||
SDL_mutexP(lock);
|
||||
if (seq[1] == '3' && seq2 == '~' )
|
||||
{
|
||||
// delete
|
||||
if (raw_buffer.size() > 0 && raw_cursor < raw_buffer.size())
|
||||
{
|
||||
raw_buffer.erase(raw_cursor,1);
|
||||
prompt_refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (raw_buffer.size() == raw_cursor)
|
||||
{
|
||||
raw_buffer.append(1,c);
|
||||
raw_cursor++;
|
||||
if (plen+raw_buffer.size() < 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;
|
||||
std::deque <std::string> history;
|
||||
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;
|
||||
std::string prompt; // current prompt string
|
||||
std::string raw_buffer; // current raw mode buffer
|
||||
int raw_cursor; // cursor position in the buffer
|
||||
};
|
||||
}
|
||||
|
||||
Console::Console():std::ostream(0), std::ios(0)
|
||||
{
|
||||
d = 0;
|
||||
inited = false;
|
||||
// we can't create the mutex at this time. the SDL functions aren't hooked yet.
|
||||
wlock = 0;
|
||||
}
|
||||
Console::~Console()
|
||||
{
|
||||
if(inited)
|
||||
shutdown();
|
||||
if(wlock)
|
||||
SDL_DestroyMutex(wlock);
|
||||
if(d)
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool Console::init(void)
|
||||
{
|
||||
d = new Private();
|
||||
// make our own weird streams so our IO isn't redirected
|
||||
d->dfout_C = fopen("/dev/tty", "w");
|
||||
wlock = SDL_CreateMutex();
|
||||
rdbuf(d);
|
||||
std::cin.tie(this);
|
||||
clear();
|
||||
d->supported_terminal = !isUnsupportedTerm() && isatty(STDIN_FILENO);
|
||||
inited = true;
|
||||
}
|
||||
|
||||
bool Console::shutdown(void)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(d->rawmode)
|
||||
d->disable_raw();
|
||||
print("\n");
|
||||
inited = false;
|
||||
SDL_mutexV(wlock);
|
||||
return true;
|
||||
}
|
||||
|
||||
int Console::print( const char* format, ... )
|
||||
{
|
||||
va_list args;
|
||||
SDL_mutexP(wlock);
|
||||
int ret;
|
||||
if(!inited) ret = -1;
|
||||
else
|
||||
{
|
||||
va_start( args, format );
|
||||
ret = d->vprint(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
SDL_mutexV(wlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Console::printerr( const char* format, ... )
|
||||
{
|
||||
va_list args;
|
||||
SDL_mutexP(wlock);
|
||||
int ret;
|
||||
if(!inited) ret = -1;
|
||||
else
|
||||
{
|
||||
va_start( args, format );
|
||||
ret = d->vprinterr(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
SDL_mutexV(wlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Console::get_columns(void)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
int ret = -1;
|
||||
if(inited)
|
||||
ret = d->get_columns();
|
||||
SDL_mutexV(wlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Console::get_rows(void)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
int ret = -1;
|
||||
if(inited)
|
||||
ret = d->get_rows();
|
||||
SDL_mutexV(wlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Console::clear()
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(inited)
|
||||
d->clear();
|
||||
SDL_mutexV(wlock);
|
||||
}
|
||||
|
||||
void Console::gotoxy(int x, int y)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(inited)
|
||||
d->gotoxy(x,y);
|
||||
SDL_mutexV(wlock);
|
||||
}
|
||||
|
||||
void Console::color(color_value index)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(inited)
|
||||
d->color(index);
|
||||
SDL_mutexV(wlock);
|
||||
}
|
||||
|
||||
void Console::reset_color( void )
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(inited)
|
||||
d->reset_color();
|
||||
SDL_mutexV(wlock);
|
||||
}
|
||||
|
||||
void Console::cursor(bool enable)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(inited)
|
||||
d->cursor(enable);
|
||||
SDL_mutexV(wlock);
|
||||
}
|
||||
|
||||
// push to front, remove from back if we are above maximum. ignore immediate duplicates
|
||||
void Console::history_add(const std::string & command)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(inited)
|
||||
d->history_add(command);
|
||||
SDL_mutexV(wlock);
|
||||
}
|
||||
|
||||
int Console::lineedit(const std::string & prompt, std::string & output)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
int ret = -2;
|
||||
if(inited)
|
||||
ret = d->lineedit(prompt,output,wlock);
|
||||
SDL_mutexV(wlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Console::msleep (unsigned int msec)
|
||||
{
|
||||
if (msec > 1000) sleep(msec/1000000);
|
||||
usleep((msec % 1000000) * 1000);
|
||||
}
|
@ -0,0 +1,588 @@
|
||||
/*
|
||||
https://github.com/peterix/dfhack
|
||||
Copyright (c) 2011 Petr Mrázek <peterix@gmail.com>
|
||||
|
||||
A thread-safe logging console with a line editor for windows.
|
||||
|
||||
Based on linenoise win32 port,
|
||||
copyright 2010, Jon Griffiths <jon_p_griffiths at yahoo dot com>.
|
||||
All rights reserved.
|
||||
Based on linenoise, copyright 2010, Salvatore Sanfilippo <antirez at gmail dot com>.
|
||||
The original linenoise can be found at: http://github.com/antirez/linenoise
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Redis nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <conio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <process.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <string>
|
||||
|
||||
#include "dfhack/Console.h"
|
||||
#include "dfhack/FakeSDL.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <deque>
|
||||
using namespace DFHack;
|
||||
|
||||
// FIXME: maybe make configurable with an ini option?
|
||||
#define MAX_CONSOLE_LINES 999;
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
class Private : public std::stringbuf
|
||||
{
|
||||
public:
|
||||
Private() : basic_stringbuf<char>::basic_stringbuf()
|
||||
{
|
||||
dfout_C = 0;
|
||||
rawmode = 0;
|
||||
console_in = 0;
|
||||
console_out = 0;
|
||||
ConsoleWindow = 0;
|
||||
default_attributes = 0;
|
||||
state = con_unclaimed;
|
||||
raw_cursor = 0;
|
||||
};
|
||||
virtual ~Private()
|
||||
{
|
||||
//sync();
|
||||
}
|
||||
protected:
|
||||
int sync()
|
||||
{
|
||||
print (str().c_str());
|
||||
// Clear the string buffer
|
||||
str(std::string());
|
||||
return 0;
|
||||
}
|
||||
public:
|
||||
/// Print a formatted string, like printf
|
||||
int print(const char * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
int ret = vprint( format, args );
|
||||
va_end( args );
|
||||
return ret;
|
||||
}
|
||||
int vprint(const char * format, va_list vl)
|
||||
{
|
||||
if(state == con_lineedit)
|
||||
{
|
||||
clearline();
|
||||
int ret = vfprintf( dfout_C, format, vl );
|
||||
prompt_refresh();
|
||||
return ret;
|
||||
}
|
||||
else return vfprintf( dfout_C, format, vl );
|
||||
}
|
||||
int vprinterr(const char * format, va_list vl)
|
||||
{
|
||||
if(state == con_lineedit)
|
||||
{
|
||||
color(Console::COLOR_LIGHTRED);
|
||||
clearline();
|
||||
int ret = vfprintf( dfout_C, format, vl );
|
||||
reset_color();
|
||||
prompt_refresh();
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
color(Console::COLOR_LIGHTRED);
|
||||
int ret = vfprintf( dfout_C, format, vl );
|
||||
reset_color();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/// Print a formatted string, like printf, in red
|
||||
int printerr(const char * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
int ret = vprinterr( format, args );
|
||||
va_end( args );
|
||||
return ret;
|
||||
}
|
||||
int get_columns(void)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
|
||||
GetConsoleScreenBufferInfo(console_out, &inf);
|
||||
return (size_t)inf.dwSize.X;
|
||||
}
|
||||
int get_rows(void)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
|
||||
GetConsoleScreenBufferInfo(console_out, &inf);
|
||||
return (size_t)inf.dwSize.Y;
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
system("cls");
|
||||
}
|
||||
void clearline()
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
|
||||
GetConsoleScreenBufferInfo(console_out, &inf);
|
||||
// Blank to EOL
|
||||
char* tmp = (char*)malloc(inf.dwSize.X);
|
||||
memset(tmp, ' ', inf.dwSize.X);
|
||||
output(tmp, inf.dwSize.X, 0, inf.dwCursorPosition.Y);
|
||||
free(tmp);
|
||||
COORD coord = {0, inf.dwCursorPosition.Y}; // Windows uses 0-based coordinates
|
||||
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
|
||||
}
|
||||
void gotoxy(int x, int y)
|
||||
{
|
||||
COORD coord = {x-1, y-1}; // Windows uses 0-based coordinates
|
||||
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
|
||||
}
|
||||
|
||||
void color(int index)
|
||||
{
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(hConsole, index);
|
||||
}
|
||||
|
||||
void reset_color( void )
|
||||
{
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(hConsole, default_attributes);
|
||||
}
|
||||
|
||||
void cursor(bool enable)
|
||||
{
|
||||
if(enable)
|
||||
{
|
||||
HANDLE hConsoleOutput;
|
||||
CONSOLE_CURSOR_INFO structCursorInfo;
|
||||
hConsoleOutput = GetStdHandle( STD_OUTPUT_HANDLE );
|
||||
GetConsoleCursorInfo( hConsoleOutput, &structCursorInfo ); // Get current cursor size
|
||||
structCursorInfo.bVisible = TRUE;
|
||||
SetConsoleCursorInfo( hConsoleOutput, &structCursorInfo );
|
||||
}
|
||||
else
|
||||
{
|
||||
HANDLE hConsoleOutput;
|
||||
CONSOLE_CURSOR_INFO structCursorInfo;
|
||||
hConsoleOutput = GetStdHandle( STD_OUTPUT_HANDLE );
|
||||
GetConsoleCursorInfo( hConsoleOutput, &structCursorInfo ); // Get current cursor size
|
||||
structCursorInfo.bVisible = FALSE;
|
||||
SetConsoleCursorInfo( hConsoleOutput, &structCursorInfo );
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void prompt_refresh()
|
||||
{
|
||||
size_t cols = get_columns();
|
||||
size_t plen = prompt.size();
|
||||
const char * buf = raw_buffer.c_str();
|
||||
size_t len = raw_buffer.size();
|
||||
|
||||
while ((plen + raw_cursor) >= cols)
|
||||
{
|
||||
buf++;
|
||||
len--;
|
||||
raw_cursor--;
|
||||
}
|
||||
while (plen + len > cols)
|
||||
{
|
||||
len--;
|
||||
}
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
|
||||
GetConsoleScreenBufferInfo(console_out, &inf);
|
||||
output(prompt.c_str(), plen, 0, inf.dwCursorPosition.Y);
|
||||
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));
|
||||
output(tmp, inf.dwSize.X - (plen + len), len + plen, inf.dwCursorPosition.Y);
|
||||
free(tmp);
|
||||
}
|
||||
inf.dwCursorPosition.X = (SHORT)(raw_cursor + plen);
|
||||
SetConsoleCursorPosition(console_out, inf.dwCursorPosition);
|
||||
}
|
||||
|
||||
int prompt_loop(SDL::Mutex * lock)
|
||||
{
|
||||
raw_buffer.clear(); // make sure the buffer is empty!
|
||||
size_t plen = prompt.size();
|
||||
raw_cursor = 0;
|
||||
int history_index = 0;
|
||||
// The latest history entry is always our current buffer, that
|
||||
// initially is just an empty string.
|
||||
const std::string empty;
|
||||
history_add(empty);
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO inf = { 0 };
|
||||
GetConsoleScreenBufferInfo(console_out, &inf);
|
||||
size_t cols = inf.dwSize.X;
|
||||
output(prompt.c_str(), plen, 0, inf.dwCursorPosition.Y);
|
||||
inf.dwCursorPosition.X = (SHORT)plen;
|
||||
SetConsoleCursorPosition(console_out, inf.dwCursorPosition);
|
||||
|
||||
while (1)
|
||||
{
|
||||
INPUT_RECORD rec;
|
||||
DWORD count;
|
||||
SDL_mutexV(lock);
|
||||
ReadConsoleInputA(console_in, &rec, 1, &count);
|
||||
SDL_mutexP(lock);
|
||||
if (rec.EventType != KEY_EVENT || !rec.Event.KeyEvent.bKeyDown)
|
||||
continue;
|
||||
switch (rec.Event.KeyEvent.wVirtualKeyCode)
|
||||
{
|
||||
case VK_RETURN: // enter
|
||||
history.pop_front();
|
||||
return raw_buffer.size();
|
||||
case VK_BACK: // backspace
|
||||
if (raw_cursor > 0 && raw_buffer.size() > 0)
|
||||
{
|
||||
raw_buffer.erase(raw_cursor-1,1);
|
||||
raw_cursor--;
|
||||
prompt_refresh();
|
||||
}
|
||||
break;
|
||||
case VK_LEFT: // left arrow
|
||||
if (raw_cursor > 0)
|
||||
{
|
||||
raw_cursor--;
|
||||
prompt_refresh();
|
||||
}
|
||||
break;
|
||||
case VK_RIGHT: // right arrow
|
||||
if (raw_cursor != raw_buffer.size())
|
||||
{
|
||||
raw_cursor++;
|
||||
prompt_refresh();
|
||||
}
|
||||
break;
|
||||
case VK_UP:
|
||||
case VK_DOWN:
|
||||
// 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 += (rec.Event.KeyEvent.wVirtualKeyCode == VK_UP) ? 1 : -1;
|
||||
if (history_index < 0)
|
||||
{
|
||||
history_index = 0;
|
||||
break;
|
||||
}
|
||||
else if (history_index >= history.size())
|
||||
{
|
||||
history_index = history.size()-1;
|
||||
break;
|
||||
}
|
||||
raw_buffer = history[history_index];
|
||||
raw_cursor = raw_buffer.size();
|
||||
prompt_refresh();
|
||||
}
|
||||
break;
|
||||
case VK_DELETE:
|
||||
// delete
|
||||
if (raw_buffer.size() > 0 && raw_cursor < raw_buffer.size())
|
||||
{
|
||||
raw_buffer.erase(raw_cursor,1);
|
||||
prompt_refresh();
|
||||
}
|
||||
break;
|
||||
case VK_HOME:
|
||||
raw_cursor = 0;
|
||||
prompt_refresh();
|
||||
break;
|
||||
case VK_END:
|
||||
raw_cursor = raw_buffer.size();
|
||||
prompt_refresh();
|
||||
break;
|
||||
default:
|
||||
if (rec.Event.KeyEvent.uChar.AsciiChar < ' ' ||
|
||||
rec.Event.KeyEvent.uChar.AsciiChar > '~')
|
||||
continue;
|
||||
if (raw_buffer.size() == raw_cursor)
|
||||
raw_buffer.append(1,rec.Event.KeyEvent.uChar.AsciiChar);
|
||||
else
|
||||
raw_buffer.insert(raw_cursor,1,rec.Event.KeyEvent.uChar.AsciiChar);
|
||||
raw_cursor++;
|
||||
prompt_refresh();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
int lineedit(const std::string & prompt, std::string & output, SDL::Mutex*lock)
|
||||
{
|
||||
output.clear();
|
||||
int count;
|
||||
state = con_lineedit;
|
||||
this->prompt = prompt;
|
||||
count = prompt_loop(lock);
|
||||
if(count != -1)
|
||||
output = raw_buffer;
|
||||
state = con_unclaimed;
|
||||
print("\n");
|
||||
return count;
|
||||
}
|
||||
|
||||
// push to front, remove from back if we are above maximum. ignore immediate duplicates
|
||||
void history_add(const std::string & command)
|
||||
{
|
||||
// if current command = last in history -> do not add. Always add if history is empty.
|
||||
if(!history.empty() && history.front() == command)
|
||||
return;
|
||||
history.push_front(command);
|
||||
if(history.size() > 100)
|
||||
history.pop_back();
|
||||
}
|
||||
|
||||
FILE * dfout_C;
|
||||
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;
|
||||
// current state
|
||||
enum console_state
|
||||
{
|
||||
con_unclaimed,
|
||||
con_lineedit
|
||||
} state;
|
||||
std::string prompt; // current prompt string
|
||||
std::string raw_buffer; // current raw mode buffer
|
||||
int raw_cursor; // cursor position in the buffer
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Console::Console():std::ostream(0), std::ios(0)
|
||||
{
|
||||
d = 0;
|
||||
wlock = 0;
|
||||
inited = false;
|
||||
}
|
||||
|
||||
Console::~Console()
|
||||
{
|
||||
}
|
||||
|
||||
bool Console::init(void)
|
||||
{
|
||||
d = new Private();
|
||||
int hConHandle;
|
||||
long lStdHandle;
|
||||
CONSOLE_SCREEN_BUFFER_INFO coninfo;
|
||||
FILE *fp;
|
||||
DWORD oldMode, newMode;
|
||||
|
||||
// Allocate a console!
|
||||
AllocConsole();
|
||||
d->ConsoleWindow = GetConsoleWindow();
|
||||
wlock = SDL_CreateMutex();
|
||||
HMENU hm = GetSystemMenu(d->ConsoleWindow,false);
|
||||
DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND);
|
||||
|
||||
// set the screen buffer to be big enough to let us scroll text
|
||||
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
|
||||
d->default_attributes = coninfo.wAttributes;
|
||||
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);
|
||||
|
||||
// redirect unbuffered STDOUT to the console
|
||||
d->console_out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
lStdHandle = (long)d->console_out;
|
||||
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
|
||||
d->dfout_C = _fdopen( hConHandle, "w" );
|
||||
setvbuf( d->dfout_C, NULL, _IONBF, 0 );
|
||||
|
||||
// redirect unbuffered STDIN to the console
|
||||
d->console_in = GetStdHandle(STD_INPUT_HANDLE);
|
||||
lStdHandle = (long)d->console_in;
|
||||
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
|
||||
fp = _fdopen( hConHandle, "r" );
|
||||
*stdin = *fp;
|
||||
setvbuf( stdin, NULL, _IONBF, 0 );
|
||||
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),&oldMode);
|
||||
newMode = oldMode | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
|
||||
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),newMode);
|
||||
SetConsoleCtrlHandler(NULL,true);
|
||||
std::ios::sync_with_stdio();
|
||||
|
||||
// make our own weird streams so our IO isn't redirected
|
||||
rdbuf(d);
|
||||
std::cin.tie(this);
|
||||
clear();
|
||||
inited = true;
|
||||
return true;
|
||||
}
|
||||
// FIXME: looks awfully empty, doesn't it?
|
||||
bool Console::shutdown(void)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
FreeConsole();
|
||||
inited = false;
|
||||
SDL_mutexV(wlock);
|
||||
return true;
|
||||
}
|
||||
int Console::print( const char* format, ... )
|
||||
{
|
||||
va_list args;
|
||||
SDL_mutexP(wlock);
|
||||
int ret;
|
||||
if(!inited) ret = -1;
|
||||
else
|
||||
{
|
||||
va_start( args, format );
|
||||
ret = d->vprint(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
SDL_mutexV(wlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Console::printerr( const char* format, ... )
|
||||
{
|
||||
va_list args;
|
||||
SDL_mutexP(wlock);
|
||||
int ret;
|
||||
if(!inited) ret = -1;
|
||||
else
|
||||
{
|
||||
va_start( args, format );
|
||||
ret = d->vprinterr(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
SDL_mutexV(wlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Console::get_columns(void)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
int ret = -1;
|
||||
if(inited)
|
||||
ret = d->get_columns();
|
||||
SDL_mutexV(wlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Console::get_rows(void)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
int ret = -1;
|
||||
if(inited)
|
||||
ret = d->get_rows();
|
||||
SDL_mutexV(wlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Console::clear()
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(inited)
|
||||
d->clear();
|
||||
SDL_mutexV(wlock);
|
||||
}
|
||||
|
||||
void Console::gotoxy(int x, int y)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(inited)
|
||||
d->gotoxy(x,y);
|
||||
SDL_mutexV(wlock);
|
||||
}
|
||||
|
||||
void Console::color(color_value index)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(inited)
|
||||
d->color(index);
|
||||
SDL_mutexV(wlock);
|
||||
}
|
||||
|
||||
void Console::reset_color( void )
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(inited)
|
||||
d->reset_color();
|
||||
SDL_mutexV(wlock);
|
||||
}
|
||||
|
||||
void Console::cursor(bool enable)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(inited)
|
||||
d->cursor(enable);
|
||||
SDL_mutexV(wlock);
|
||||
}
|
||||
|
||||
// push to front, remove from back if we are above maximum. ignore immediate duplicates
|
||||
void Console::history_add(const std::string & command)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
if(inited)
|
||||
d->history_add(command);
|
||||
SDL_mutexV(wlock);
|
||||
}
|
||||
|
||||
int Console::lineedit(const std::string & prompt, std::string & output)
|
||||
{
|
||||
SDL_mutexP(wlock);
|
||||
int ret = -2;
|
||||
if(inited)
|
||||
ret = d->lineedit(prompt,output,wlock);
|
||||
SDL_mutexV(wlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Console::msleep (unsigned int msec)
|
||||
{
|
||||
Sleep(msec);
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
#include "Internal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
using namespace std;
|
||||
|
||||
#include "private/ContextShared.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFProcess.h"
|
||||
#include "dfhack/DFModule.h"
|
||||
using namespace DFHack;
|
||||
|
||||
DFContextShared::DFContextShared()
|
||||
{
|
||||
// init modules
|
||||
allModules.clear();
|
||||
memset(&(s_mods), 0, sizeof(s_mods));
|
||||
namesInited = false;
|
||||
namesFailed = false;
|
||||
}
|
||||
|
||||
DFContextShared::~DFContextShared()
|
||||
{
|
||||
// invalidate all modules
|
||||
for(unsigned int i = 0 ; i < allModules.size(); i++)
|
||||
{
|
||||
delete allModules[i];
|
||||
}
|
||||
allModules.clear();
|
||||
}
|
||||
|
||||
bool DFContextShared::InitReadNames()
|
||||
{
|
||||
try
|
||||
{
|
||||
OffsetGroup * OG = offset_descriptor->getGroup("name");
|
||||
name_firstname_offset = OG->getOffset("first");
|
||||
name_nickname_offset = OG->getOffset("nick");
|
||||
name_words_offset = OG->getOffset("second_words");
|
||||
name_parts_offset = OG->getOffset("parts_of_speech");
|
||||
name_language_offset = OG->getOffset("language");
|
||||
name_set_offset = OG->getOffset("has_name");
|
||||
}
|
||||
catch(exception &)
|
||||
{
|
||||
namesFailed = true;
|
||||
return false;
|
||||
}
|
||||
namesInited = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DFContextShared::readName(t_name & name, uint32_t address)
|
||||
{
|
||||
if(namesFailed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(!namesInited)
|
||||
{
|
||||
if(!InitReadNames()) return;
|
||||
}
|
||||
p->readSTLString(address + name_firstname_offset , name.first_name, 128);
|
||||
p->readSTLString(address + name_nickname_offset , name.nickname, 128);
|
||||
p->read(address + name_words_offset, 7*4, (uint8_t *)name.words);
|
||||
p->read(address + name_parts_offset, 7*2, (uint8_t *)name.parts_of_speech);
|
||||
name.language = p->readDWord(address + name_language_offset);
|
||||
name.has_name = p->readByte(address + name_set_offset);
|
||||
}
|
||||
|
||||
void DFContextShared::copyName(uint32_t address, uint32_t target)
|
||||
{
|
||||
uint8_t buf[28];
|
||||
|
||||
if (address == target)
|
||||
return;
|
||||
|
||||
p->copySTLString(address + name_firstname_offset, target + name_firstname_offset);
|
||||
p->copySTLString(address + name_nickname_offset, target + name_nickname_offset);
|
||||
p->read(address + name_words_offset, 7*4, buf);
|
||||
p->write(target + name_words_offset, 7*4, buf);
|
||||
p->read(address + name_parts_offset, 7*2, buf);
|
||||
p->write(target + name_parts_offset, 7*2, buf);
|
||||
p->writeDWord(target + name_language_offset, p->readDWord(address + name_language_offset));
|
||||
p->writeByte(target + name_set_offset, p->readByte(address + name_set_offset));
|
||||
}
|
@ -0,0 +1,599 @@
|
||||
/*
|
||||
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 <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
#include "dfhack/Error.h"
|
||||
#include "dfhack/Process.h"
|
||||
#include "dfhack/Core.h"
|
||||
#include "dfhack/Console.h"
|
||||
#include "dfhack/Module.h"
|
||||
#include "dfhack/VersionInfoFactory.h"
|
||||
#include "dfhack/PluginManager.h"
|
||||
#include "ModuleFactory.h"
|
||||
#include "dfhack/modules/Gui.h"
|
||||
#include "dfhack/modules/World.h"
|
||||
|
||||
#include "dfhack/SDL_fakes/events.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iomanip>
|
||||
#include <stdlib.h>
|
||||
using namespace DFHack;
|
||||
|
||||
struct Core::Cond
|
||||
{
|
||||
Cond()
|
||||
{
|
||||
predicate = false;
|
||||
wakeup = SDL_CreateCond();
|
||||
}
|
||||
~Cond()
|
||||
{
|
||||
SDL_DestroyCond(wakeup);
|
||||
}
|
||||
bool Lock(SDL::Mutex * m)
|
||||
{
|
||||
while(!predicate)
|
||||
{
|
||||
SDL_CondWait(wakeup,m);
|
||||
}
|
||||
predicate = false;
|
||||
return true;
|
||||
}
|
||||
bool Unlock()
|
||||
{
|
||||
predicate = true;
|
||||
SDL_CondSignal(wakeup);
|
||||
return true;
|
||||
}
|
||||
SDL::Cond * wakeup;
|
||||
bool predicate;
|
||||
};
|
||||
|
||||
void cheap_tokenise(string const& input, vector<string> &output)
|
||||
{
|
||||
istringstream str(input);
|
||||
istream_iterator<string> cur(str), end;
|
||||
output.assign(cur, end);
|
||||
}
|
||||
|
||||
struct IODATA
|
||||
{
|
||||
Core * core;
|
||||
PluginManager * plug_mgr;
|
||||
};
|
||||
|
||||
// A thread function... for handling hotkeys. This is needed because
|
||||
// all the plugin commands are expected to be run from foreign threads.
|
||||
// Running them from one of the main DF threads will result in deadlock!
|
||||
int fHKthread(void * iodata)
|
||||
{
|
||||
Core * core = ((IODATA*) iodata)->core;
|
||||
PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr;
|
||||
if(plug_mgr == 0 || core == 0)
|
||||
{
|
||||
cerr << "Hotkey thread has croaked." << endl;
|
||||
return 0;
|
||||
}
|
||||
while(1)
|
||||
{
|
||||
std::string stuff = core->getHotkeyCmd(); // waits on mutex!
|
||||
if(!stuff.empty())
|
||||
{
|
||||
vector <string> crap;
|
||||
plug_mgr->InvokeCommand(stuff, crap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A thread function... for the interactive console.
|
||||
int fIOthread(void * iodata)
|
||||
{
|
||||
IODATA * iod = ((IODATA*) iodata);
|
||||
Core * core = iod->core;
|
||||
PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr;
|
||||
Console & con = core->con;
|
||||
if(plug_mgr == 0 || core == 0)
|
||||
{
|
||||
con.printerr("Something horrible happened in Core's constructor...\n");
|
||||
return 0;
|
||||
}
|
||||
con.print("DFHack is ready. Have a nice day!\n"
|
||||
"Type in '?' or 'help' for general help, 'ls' to see all commands.\n");
|
||||
int clueless_counter = 0;
|
||||
while (true)
|
||||
{
|
||||
string command = "";
|
||||
int ret = con.lineedit("[DFHack]# ",command);
|
||||
if(ret == -2)
|
||||
{
|
||||
cerr << "Console is shutting down properly." << endl;
|
||||
return 0;
|
||||
}
|
||||
else if(ret == -1)
|
||||
{
|
||||
cerr << "Console caught an unspecified error." << endl;
|
||||
continue;
|
||||
}
|
||||
else if(ret)
|
||||
{
|
||||
// a proper, non-empty command was entered
|
||||
con.history_add(command);
|
||||
}
|
||||
// cut the input into parts
|
||||
vector <string> parts;
|
||||
cheap_tokenise(command,parts);
|
||||
if(parts.size() == 0)
|
||||
{
|
||||
clueless_counter ++;
|
||||
continue;
|
||||
}
|
||||
string first = parts[0];
|
||||
parts.erase(parts.begin());
|
||||
// let's see what we actually got
|
||||
if(first=="help" || first == "?")
|
||||
{
|
||||
if(!parts.size())
|
||||
{
|
||||
con.print("This is the DFHack console. You can type commands in and manage DFHack plugins from it.\n"
|
||||
"Some basic editing capabilities are included (single-line text editing).\n"
|
||||
"The console also has a command history - you can navigate it with Up and Down keys.\n"
|
||||
"On Windows, you may have to resize your console window. The appropriate menu is accessible\n"
|
||||
"by clicking on the program icon in the top bar of the window.\n\n"
|
||||
"Basic commands:\n"
|
||||
" help|? - This text.\n"
|
||||
" ls|dir [PLUGIN] - List available commands. Optionally for single plugin.\n"
|
||||
" cls - Clear the console.\n"
|
||||
" fpause - Force DF to pause.\n"
|
||||
" die - Force DF to close immediately\n"
|
||||
"Plugin management (useful for developers):\n"
|
||||
//" belongs COMMAND - Tell which plugin a command belongs to.\n"
|
||||
" plug [PLUGIN|v] - List plugin state and description.\n"
|
||||
" load PLUGIN|all - Load a plugin by name or load all possible plugins.\n"
|
||||
" unload PLUGIN|all - Unload a plugin or all loaded plugins.\n"
|
||||
" reload PLUGIN|all - Reload a plugin or all loaded plugins.\n"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
con.printerr("not implemented yet\n");
|
||||
}
|
||||
}
|
||||
else if( first == "load" )
|
||||
{
|
||||
if(parts.size())
|
||||
{
|
||||
string & plugname = parts[0];
|
||||
if(plugname == "all")
|
||||
{
|
||||
for(int i = 0; i < plug_mgr->size();i++)
|
||||
{
|
||||
Plugin * plug = (plug_mgr->operator[](i));
|
||||
plug->load();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Plugin * plug = plug_mgr->getPluginByName(plugname);
|
||||
if(!plug) con.printerr("No such plugin\n");
|
||||
plug->load();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( first == "reload" )
|
||||
{
|
||||
if(parts.size())
|
||||
{
|
||||
string & plugname = parts[0];
|
||||
if(plugname == "all")
|
||||
{
|
||||
for(int i = 0; i < plug_mgr->size();i++)
|
||||
{
|
||||
Plugin * plug = (plug_mgr->operator[](i));
|
||||
plug->reload();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Plugin * plug = plug_mgr->getPluginByName(plugname);
|
||||
if(!plug) con.printerr("No such plugin\n");
|
||||
plug->reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( first == "unload" )
|
||||
{
|
||||
if(parts.size())
|
||||
{
|
||||
string & plugname = parts[0];
|
||||
if(plugname == "all")
|
||||
{
|
||||
for(int i = 0; i < plug_mgr->size();i++)
|
||||
{
|
||||
Plugin * plug = (plug_mgr->operator[](i));
|
||||
plug->unload();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Plugin * plug = plug_mgr->getPluginByName(plugname);
|
||||
if(!plug) con.printerr("No such plugin\n");
|
||||
plug->unload();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(first == "ls" || first == "dir")
|
||||
{
|
||||
if(parts.size())
|
||||
{
|
||||
string & plugname = parts[0];
|
||||
const Plugin * plug = plug_mgr->getPluginByName(plugname);
|
||||
if(!plug)
|
||||
{
|
||||
con.printerr("There's no plugin called %s!\n",plugname.c_str());
|
||||
}
|
||||
else for (int j = 0; j < plug->size();j++)
|
||||
{
|
||||
const PluginCommand & pcmd = (plug->operator[](j));
|
||||
con.print(" %-22s - %s\n",pcmd.name.c_str(), pcmd.description.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
con.print(
|
||||
"builtin:\n"
|
||||
" help|? - This text or help specific to a plugin.\n"
|
||||
" ls [PLUGIN] - List available commands. Optionally for single plugin.\n"
|
||||
" cls - Clear the console.\n"
|
||||
" fpause - Force DF to pause.\n"
|
||||
" die - Force DF to close immediately\n"
|
||||
" belongs COMMAND - Tell which plugin a command belongs to.\n"
|
||||
" plug [PLUGIN|v] - List plugin state and detailed description.\n"
|
||||
" load PLUGIN|all - Load a plugin by name or load all possible plugins.\n"
|
||||
" unload PLUGIN|all - Unload a plugin or all loaded plugins.\n"
|
||||
" reload PLUGIN|all - Reload a plugin or all loaded plugins.\n"
|
||||
"\n"
|
||||
"plugins:\n"
|
||||
);
|
||||
for(int i = 0; i < plug_mgr->size();i++)
|
||||
{
|
||||
const Plugin * plug = (plug_mgr->operator[](i));
|
||||
if(!plug->size())
|
||||
continue;
|
||||
for (int j = 0; j < plug->size();j++)
|
||||
{
|
||||
const PluginCommand & pcmd = (plug->operator[](j));
|
||||
con.print(" %-22s- %s\n",pcmd.name.c_str(), pcmd.description.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(first == "plug")
|
||||
{
|
||||
for(int i = 0; i < plug_mgr->size();i++)
|
||||
{
|
||||
const Plugin * plug = (plug_mgr->operator[](i));
|
||||
if(!plug->size())
|
||||
continue;
|
||||
con.print("%s\n", plug->getName().c_str());
|
||||
}
|
||||
}
|
||||
else if(first == "fpause")
|
||||
{
|
||||
World * w = core->getWorld();
|
||||
w->SetPauseState(true);
|
||||
con.print("The game was forced to pause!");
|
||||
}
|
||||
else if(first == "cls")
|
||||
{
|
||||
con.clear();
|
||||
}
|
||||
else if(first == "die")
|
||||
{
|
||||
_exit(666);
|
||||
}
|
||||
else
|
||||
{
|
||||
vector <string> parts;
|
||||
cheap_tokenise(command,parts);
|
||||
if(parts.size() == 0)
|
||||
{
|
||||
clueless_counter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
string first = parts[0];
|
||||
parts.erase(parts.begin());
|
||||
command_result res = plug_mgr->InvokeCommand(first, parts);
|
||||
if(res == CR_NOT_IMPLEMENTED)
|
||||
{
|
||||
con.printerr("Invalid command.\n");
|
||||
clueless_counter ++;
|
||||
}
|
||||
/*
|
||||
else if(res == CR_FAILURE)
|
||||
{
|
||||
con.printerr("ERROR!\n");
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
if(clueless_counter == 3)
|
||||
{
|
||||
con.print("Do 'help' or '?' for the list of available commands.\n");
|
||||
clueless_counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Core::Core()
|
||||
{
|
||||
// init the console. This must be always the first step!
|
||||
plug_mgr = 0;
|
||||
vif = 0;
|
||||
p = 0;
|
||||
errorstate = false;
|
||||
vinfo = 0;
|
||||
started = false;
|
||||
memset(&(s_mods), 0, sizeof(s_mods));
|
||||
|
||||
// create mutex for syncing with interactive tasks
|
||||
AccessMutex = 0;
|
||||
core_cond = 0;
|
||||
// set up hotkey capture
|
||||
memset(hotkey_states,0,sizeof(hotkey_states));
|
||||
hotkey_set = false;
|
||||
HotkeyMutex = 0;
|
||||
HotkeyCond = 0;
|
||||
};
|
||||
|
||||
bool Core::Init()
|
||||
{
|
||||
// init the console. This must be always the first step!
|
||||
con.init();
|
||||
// find out what we are...
|
||||
vif = new DFHack::VersionInfoFactory("Memory.xml");
|
||||
p = new DFHack::Process(vif);
|
||||
if (!p->isIdentified())
|
||||
{
|
||||
con.printerr("Couldn't identify this version of DF.\n");
|
||||
errorstate = true;
|
||||
delete p;
|
||||
p = NULL;
|
||||
return false;
|
||||
}
|
||||
vinfo = p->getDescriptor();
|
||||
|
||||
// create mutex for syncing with interactive tasks
|
||||
AccessMutex = SDL_CreateMutex();
|
||||
if(!AccessMutex)
|
||||
{
|
||||
con.printerr("Mutex creation failed\n");
|
||||
errorstate = true;
|
||||
return false;
|
||||
}
|
||||
core_cond = new Core::Cond();
|
||||
// create plugin manager
|
||||
plug_mgr = new PluginManager(this);
|
||||
if(!plug_mgr)
|
||||
{
|
||||
con.printerr("Failed to create the Plugin Manager.\n");
|
||||
errorstate = true;
|
||||
return false;
|
||||
}
|
||||
// look for all plugins,
|
||||
// create IO thread
|
||||
IODATA *temp = new IODATA;
|
||||
temp->core = this;
|
||||
temp->plug_mgr = plug_mgr;
|
||||
SDL::Thread * IO = SDL_CreateThread(fIOthread, (void *) temp);
|
||||
// set up hotkey capture
|
||||
HotkeyMutex = SDL_CreateMutex();
|
||||
HotkeyCond = SDL_CreateCond();
|
||||
SDL::Thread * HK = SDL_CreateThread(fHKthread, (void *) temp);
|
||||
started = true;
|
||||
return true;
|
||||
}
|
||||
/// sets the current hotkey command
|
||||
bool Core::setHotkeyCmd( std::string cmd )
|
||||
{
|
||||
// access command
|
||||
SDL_mutexP(HotkeyMutex);
|
||||
{
|
||||
hotkey_set = true;
|
||||
hotkey_cmd = cmd;
|
||||
SDL_CondSignal(HotkeyCond);
|
||||
}
|
||||
SDL_mutexV(HotkeyMutex);
|
||||
return true;
|
||||
}
|
||||
/// removes the hotkey command and gives it to the caller thread
|
||||
std::string Core::getHotkeyCmd( void )
|
||||
{
|
||||
string returner;
|
||||
SDL_mutexP(HotkeyMutex);
|
||||
while ( ! hotkey_set )
|
||||
{
|
||||
SDL_CondWait(HotkeyCond, HotkeyMutex);
|
||||
}
|
||||
hotkey_set = false;
|
||||
returner = hotkey_cmd;
|
||||
hotkey_cmd.clear();
|
||||
SDL_mutexV(HotkeyMutex);
|
||||
return returner;
|
||||
}
|
||||
|
||||
|
||||
void Core::Suspend()
|
||||
{
|
||||
Core::Cond * nc = new Core::Cond();
|
||||
// put the condition on a stack
|
||||
SDL_mutexP(StackMutex);
|
||||
suspended_tools.push(nc);
|
||||
SDL_mutexV(StackMutex);
|
||||
// wait until Core::Update() wakes up the tool
|
||||
SDL_mutexP(AccessMutex);
|
||||
nc->Lock(AccessMutex);
|
||||
SDL_mutexV(AccessMutex);
|
||||
}
|
||||
|
||||
void Core::Resume()
|
||||
{
|
||||
SDL_mutexP(AccessMutex);
|
||||
core_cond->Unlock();
|
||||
SDL_mutexV(AccessMutex);
|
||||
}
|
||||
|
||||
// should always be from simulation thread!
|
||||
int Core::Update()
|
||||
{
|
||||
if(!started) Init();
|
||||
if(errorstate)
|
||||
return -1;
|
||||
|
||||
// notify all the plugins that a game tick is finished
|
||||
plug_mgr->OnUpdate();
|
||||
// wake waiting tools
|
||||
// do not allow more tools to join in while we process stuff here
|
||||
SDL_mutexP(StackMutex);
|
||||
while (!suspended_tools.empty())
|
||||
{
|
||||
Core::Cond * nc = suspended_tools.top();
|
||||
suspended_tools.pop();
|
||||
SDL_mutexP(AccessMutex);
|
||||
// wake tool
|
||||
nc->Unlock();
|
||||
// wait for tool to wake us
|
||||
core_cond->Lock(AccessMutex);
|
||||
SDL_mutexV(AccessMutex);
|
||||
// destroy condition
|
||||
delete nc;
|
||||
}
|
||||
SDL_mutexV(StackMutex);
|
||||
return 0;
|
||||
};
|
||||
|
||||
// FIXME: needs to terminate the IO threads and properly dismantle all the machinery involved.
|
||||
int Core::Shutdown ( void )
|
||||
{
|
||||
errorstate = 1;
|
||||
if(plug_mgr)
|
||||
{
|
||||
delete plug_mgr;
|
||||
plug_mgr = 0;
|
||||
}
|
||||
// invalidate all modules
|
||||
for(unsigned int i = 0 ; i < allModules.size(); i++)
|
||||
{
|
||||
delete allModules[i];
|
||||
}
|
||||
allModules.clear();
|
||||
memset(&(s_mods), 0, sizeof(s_mods));
|
||||
con.shutdown();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Core::SDL_Event(SDL::Event* ev, int orig_return)
|
||||
{
|
||||
// do NOT process events before we are ready.
|
||||
if(!started) return orig_return;
|
||||
if(!ev)
|
||||
return orig_return;
|
||||
if(ev && ev->type == SDL::ET_KEYDOWN || ev->type == SDL::ET_KEYUP)
|
||||
{
|
||||
SDL::KeyboardEvent * ke = (SDL::KeyboardEvent *)ev;
|
||||
bool shift = ke->ksym.mod & SDL::KMOD_SHIFT;
|
||||
// consuming F1 .. F8
|
||||
int idx = ke->ksym.sym - SDL::K_F1;
|
||||
if(idx < 0 || idx > 7)
|
||||
return orig_return;
|
||||
idx += 8*shift;
|
||||
// now we have the real index...
|
||||
if(ke->state == SDL::BTN_PRESSED && !hotkey_states[idx])
|
||||
{
|
||||
hotkey_states[idx] = 1;
|
||||
Gui * g = getGui();
|
||||
if(g->hotkeys && g->df_interface && g->df_menu_state)
|
||||
{
|
||||
t_viewscreen * ws = g->GetCurrentScreen();
|
||||
// FIXME: put hardcoded values into memory.xml
|
||||
if(ws->getClassName() == "viewscreen_dwarfmodest" && *g->df_menu_state == 0x23)
|
||||
return orig_return;
|
||||
else
|
||||
{
|
||||
t_hotkey & hotkey = (*g->hotkeys)[idx];
|
||||
setHotkeyCmd(hotkey.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(ke->state == SDL::BTN_RELEASED)
|
||||
{
|
||||
hotkey_states[idx] = 0;
|
||||
}
|
||||
}
|
||||
return orig_return;
|
||||
// do stuff with the events...
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
M O D U L E S
|
||||
*******************************************************************************/
|
||||
|
||||
#define MODULE_GETTER(TYPE) \
|
||||
TYPE * Core::get##TYPE() \
|
||||
{ \
|
||||
if(errorstate) return NULL;\
|
||||
if(!s_mods.p##TYPE)\
|
||||
{\
|
||||
Module * mod = create##TYPE();\
|
||||
s_mods.p##TYPE = (TYPE *) mod;\
|
||||
allModules.push_back(mod);\
|
||||
}\
|
||||
return s_mods.p##TYPE;\
|
||||
}
|
||||
|
||||
MODULE_GETTER(Creatures);
|
||||
MODULE_GETTER(Engravings);
|
||||
MODULE_GETTER(Maps);
|
||||
MODULE_GETTER(Gui);
|
||||
MODULE_GETTER(World);
|
||||
MODULE_GETTER(Materials);
|
||||
MODULE_GETTER(Items);
|
||||
MODULE_GETTER(Translation);
|
||||
MODULE_GETTER(Vegetation);
|
||||
MODULE_GETTER(Buildings);
|
||||
MODULE_GETTER(Constructions);
|
||||
MODULE_GETTER(Vermin);
|
||||
MODULE_GETTER(Notes);
|
@ -1,177 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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 <string>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
using namespace std;
|
||||
|
||||
#include "dfhack/DFProcess.h"
|
||||
#include "dfhack/DFProcessEnumerator.h"
|
||||
#include "dfhack/DFContext.h"
|
||||
#include "dfhack/DFError.h"
|
||||
#include "dfhack/DFModule.h"
|
||||
|
||||
#include "private/ContextShared.h"
|
||||
#include "private/ModuleFactory.h"
|
||||
|
||||
using namespace DFHack;
|
||||
|
||||
Context::Context (Process* p) : d (new DFContextShared())
|
||||
{
|
||||
d->p = p;
|
||||
d->offset_descriptor = p->getDescriptor();
|
||||
d->shm_start = 0;
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
Detach();
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool Context::isValid()
|
||||
{
|
||||
//FIXME: check for error states here
|
||||
if(d->p->isIdentified())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Context::Attach()
|
||||
{
|
||||
if (!d->p->attach())
|
||||
{
|
||||
//throw Error::CantAttach();
|
||||
return false;
|
||||
}
|
||||
d->shm_start = d->p->getSHMStart();
|
||||
// process is attached, everything went just fine... hopefully
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Context::Detach()
|
||||
{
|
||||
if (!d->p->detach())
|
||||
{
|
||||
cerr << "Context::Detach failed!" << endl;
|
||||
return false;
|
||||
}
|
||||
d->shm_start = 0;
|
||||
// invalidate all modules
|
||||
for(unsigned int i = 0 ; i < d->allModules.size(); i++)
|
||||
{
|
||||
delete d->allModules[i];
|
||||
}
|
||||
d->allModules.clear();
|
||||
memset(&(d->s_mods), 0, sizeof(d->s_mods));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Context::isAttached()
|
||||
{
|
||||
return d->p->isAttached();
|
||||
}
|
||||
|
||||
bool Context::Suspend()
|
||||
{
|
||||
return d->p->suspend();
|
||||
}
|
||||
bool Context::AsyncSuspend()
|
||||
{
|
||||
return d->p->asyncSuspend();
|
||||
}
|
||||
|
||||
bool Context::Resume()
|
||||
{
|
||||
for(unsigned int i = 0 ; i < d->allModules.size(); i++)
|
||||
{
|
||||
d->allModules[i]->OnResume();
|
||||
}
|
||||
return d->p->resume();
|
||||
}
|
||||
bool Context::ForceResume()
|
||||
{
|
||||
for(unsigned int i = 0 ; i < d->allModules.size(); i++)
|
||||
{
|
||||
d->allModules[i]->OnResume();
|
||||
}
|
||||
return d->p->forceresume();
|
||||
}
|
||||
bool Context::isSuspended()
|
||||
{
|
||||
return d->p->isSuspended();
|
||||
}
|
||||
|
||||
void Context::ReadRaw (const uint32_t offset, const uint32_t size, uint8_t *target)
|
||||
{
|
||||
d->p->read (offset, size, target);
|
||||
}
|
||||
|
||||
void Context::WriteRaw (const uint32_t offset, const uint32_t size, uint8_t *source)
|
||||
{
|
||||
d->p->write (offset, size, source);
|
||||
}
|
||||
|
||||
VersionInfo *Context::getMemoryInfo()
|
||||
{
|
||||
return d->offset_descriptor;
|
||||
}
|
||||
|
||||
Process * Context::getProcess()
|
||||
{
|
||||
return d->p;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
M O D U L E S
|
||||
*******************************************************************************/
|
||||
|
||||
#define MODULE_GETTER(TYPE) \
|
||||
TYPE * Context::get##TYPE() \
|
||||
{ \
|
||||
if(!d->s_mods.p##TYPE)\
|
||||
{\
|
||||
Module * mod = create##TYPE(d);\
|
||||
d->s_mods.p##TYPE = (TYPE *) mod;\
|
||||
d->allModules.push_back(mod);\
|
||||
}\
|
||||
return d->s_mods.p##TYPE;\
|
||||
}
|
||||
|
||||
MODULE_GETTER(Creatures);
|
||||
MODULE_GETTER(Engravings);
|
||||
MODULE_GETTER(Maps);
|
||||
MODULE_GETTER(Gui);
|
||||
MODULE_GETTER(WindowIO);
|
||||
MODULE_GETTER(World);
|
||||
MODULE_GETTER(Materials);
|
||||
MODULE_GETTER(Items);
|
||||
MODULE_GETTER(Translation);
|
||||
MODULE_GETTER(Vegetation);
|
||||
MODULE_GETTER(Buildings);
|
||||
MODULE_GETTER(Constructions);
|
@ -1,246 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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 <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
#include "dfhack/VersionInfoFactory.h"
|
||||
#include "dfhack/DFProcess.h"
|
||||
#include "dfhack/DFProcessEnumerator.h"
|
||||
#include "dfhack/DFError.h"
|
||||
|
||||
#include "dfhack/DFContext.h"
|
||||
#include "dfhack/DFContextManager.h"
|
||||
#include "private/ContextShared.h"
|
||||
|
||||
using namespace DFHack;
|
||||
namespace DFHack
|
||||
{
|
||||
class ContextManager::Private
|
||||
{
|
||||
public:
|
||||
Private(){};
|
||||
~Private(){};
|
||||
string xml; // path to xml
|
||||
vector <Context *> contexts;
|
||||
ProcessEnumerator * pEnum;
|
||||
};
|
||||
}
|
||||
class DFHack::BadContexts::Private
|
||||
{
|
||||
public:
|
||||
Private(){};
|
||||
vector <Context *> bad;
|
||||
};
|
||||
|
||||
|
||||
BadContexts::BadContexts():d(new Private()){}
|
||||
|
||||
BadContexts::~BadContexts()
|
||||
{
|
||||
clear();
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool BadContexts::Contains(Process* p)
|
||||
{
|
||||
for(unsigned int i = 0; i < d->bad.size(); i++)
|
||||
{
|
||||
if((d->bad[i])->getProcess() == p)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BadContexts::Contains(Context* c)
|
||||
{
|
||||
for(unsigned int i = 0; i < d->bad.size(); i++)
|
||||
{
|
||||
if(d->bad[i] == c)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t BadContexts::size()
|
||||
{
|
||||
return d->bad.size();
|
||||
}
|
||||
|
||||
void BadContexts::clear()
|
||||
{
|
||||
for(unsigned int i = 0; i < d->bad.size(); i++)
|
||||
{
|
||||
// delete both Process and Context!
|
||||
// process has to be deleted after context, because Context does some
|
||||
// cleanup on delete (detach, etc.)
|
||||
Process * to_kill = d->bad[i]->getProcess();
|
||||
delete d->bad[i];
|
||||
delete to_kill;
|
||||
}
|
||||
d->bad.clear();
|
||||
}
|
||||
|
||||
void BadContexts::push_back(Context* c)
|
||||
{
|
||||
if(c)
|
||||
d->bad.push_back(c);
|
||||
}
|
||||
|
||||
Context * BadContexts::operator[](uint32_t index)
|
||||
{
|
||||
if(index < d->bad.size())
|
||||
return d->bad[index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
ContextManager::ContextManager (const string path_to_xml) : d (new Private())
|
||||
{
|
||||
d->xml = MEMXML_DATA_PATH;
|
||||
d->xml += "/";
|
||||
d->xml += path_to_xml;
|
||||
d->pEnum = new ProcessEnumerator(d->xml);
|
||||
}
|
||||
|
||||
ContextManager::~ContextManager()
|
||||
{
|
||||
purge();
|
||||
// process enumerator has to be destroyed after we detach from processes
|
||||
// because it tracks and destroys them
|
||||
if(d->pEnum)
|
||||
{
|
||||
delete d->pEnum;
|
||||
d->pEnum = 0;
|
||||
}
|
||||
delete d;
|
||||
}
|
||||
|
||||
uint32_t ContextManager::Refresh( BadContexts* bad_contexts )
|
||||
{
|
||||
// handle expired processes, remove stale Contexts
|
||||
{
|
||||
BadProcesses expired;
|
||||
// get new list od living and expired Process objects
|
||||
d->pEnum->Refresh(&expired);
|
||||
|
||||
// scan expired, kill contexts if necessary
|
||||
vector <Context*>::iterator it = d->contexts.begin();;
|
||||
while(it != d->contexts.end())
|
||||
{
|
||||
Process * test = (*it)->getProcess();
|
||||
if(expired.Contains(test))
|
||||
{
|
||||
// ok. we have an expired context here.
|
||||
if(!bad_contexts)
|
||||
{
|
||||
// with nowhere to put the context, we have to destroy it
|
||||
delete *it;
|
||||
// stop tracking it and advance the iterator
|
||||
it = d->contexts.erase(it);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we stuff the context into bad_contexts
|
||||
bad_contexts->push_back(*it);
|
||||
// stop tracking it and advance the iterator
|
||||
it = d->contexts.erase(it);
|
||||
// remove process from the 'expired' container, it is tracked by bad_contexts now
|
||||
// (which is responsible for freeing it).
|
||||
expired.excise(test);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else it++; // not expired, just advance to next one
|
||||
}
|
||||
// no expired contexts are in the d->contexts vector now
|
||||
// all processes remaining in 'expired' are now destroyed along with it
|
||||
}
|
||||
int numProcesses = d->pEnum->size();
|
||||
int numContexts = d->contexts.size();
|
||||
vector <Context *> newContexts;
|
||||
// enumerate valid processes
|
||||
for(int i = 0; i < numProcesses; i++)
|
||||
{
|
||||
Process * test = d->pEnum->operator[](i);
|
||||
bool exists = false;
|
||||
// scan context vector for this process
|
||||
for(int j = 0; j < numContexts; j++)
|
||||
{
|
||||
if((d->contexts[j])->getProcess() == test)
|
||||
{
|
||||
// already have that one, skip
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
if(!exists)
|
||||
{
|
||||
// new process needs a new context
|
||||
Context * c = new Context(d->pEnum->operator[](i));
|
||||
newContexts.push_back(c);
|
||||
}
|
||||
}
|
||||
d->contexts.insert(d->contexts.end(), newContexts.begin(), newContexts.end());
|
||||
return d->contexts.size();
|
||||
}
|
||||
|
||||
uint32_t ContextManager::size()
|
||||
{
|
||||
return d->contexts.size();
|
||||
}
|
||||
|
||||
Context * ContextManager::operator[](uint32_t index)
|
||||
{
|
||||
if (index < d->contexts.size())
|
||||
return d->contexts[index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
Context * ContextManager::getSingleContext()
|
||||
{
|
||||
if(!d->contexts.size())
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
for(unsigned int i = 0; i < d->contexts.size();i++)
|
||||
{
|
||||
if(d->contexts[i]->isValid())
|
||||
{
|
||||
return d->contexts[i];
|
||||
}
|
||||
}
|
||||
throw DFHack::Error::NoProcess();
|
||||
}
|
||||
|
||||
void ContextManager::purge(void)
|
||||
{
|
||||
for(unsigned int i = 0; i < d->contexts.size();i++)
|
||||
delete d->contexts[i];
|
||||
d->contexts.clear();
|
||||
d->pEnum->purge();
|
||||
}
|
@ -1,366 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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 "dfhack/DFPragma.h"
|
||||
#include "dfhack/DFExport.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
#include "dfhack/DFIntegers.h"
|
||||
#include "dfhack/DFContextManager.h"
|
||||
#include "dfhack/DFContext.h"
|
||||
|
||||
|
||||
using namespace DFHack;
|
||||
|
||||
#include "dfhack-c/DFContext_C.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHackObject* ContextManager_Alloc(const char* path_to_xml)
|
||||
{
|
||||
DFHack::ContextManager* contextMgr = new DFHack::ContextManager(std::string(path_to_xml));
|
||||
return (DFHackObject*)contextMgr;
|
||||
}
|
||||
|
||||
//FIXME: X:\dfhack\DFHackContext_C.cpp:56: warning: deleting `DFHackObject* ' is undefined
|
||||
//DC: Yeah, I forgot that trying to delete a void pointer might be a bad idea. This works now.
|
||||
void ContextManager_Free(DFHackObject* contextMgr)
|
||||
{
|
||||
if(contextMgr != NULL)
|
||||
{
|
||||
DFHack::ContextManager* a = (DFHack::ContextManager*)contextMgr;
|
||||
delete a;
|
||||
|
||||
contextMgr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ContextManager_Refresh(DFHackObject* contextMgr)
|
||||
{
|
||||
if(contextMgr != NULL)
|
||||
{
|
||||
return ((DFHack::ContextManager*)contextMgr)->Refresh();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ContextManager_size(DFHackObject* contextMgr, uint32_t* size)
|
||||
{
|
||||
if(contextMgr != NULL)
|
||||
{
|
||||
uint32_t result = ((DFHack::ContextManager*)contextMgr)->size();
|
||||
|
||||
*size = result;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ContextManager_purge(DFHackObject* contextMgr)
|
||||
{
|
||||
if(contextMgr != NULL)
|
||||
{
|
||||
((DFHack::ContextManager*)contextMgr)->purge();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
DFHackObject* ContextManager_getContext(DFHackObject* contextMgr, uint32_t index)
|
||||
{
|
||||
if(contextMgr != NULL)
|
||||
{
|
||||
DFHack::ContextManager* mgr = ((DFHack::ContextManager*)contextMgr);
|
||||
|
||||
if(index >= mgr->size())
|
||||
return NULL;
|
||||
|
||||
return (DFHackObject*)((DFHack::Context*)((*mgr)[index]));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* ContextManager_getSingleContext(DFHackObject* contextMgr)
|
||||
{
|
||||
if(contextMgr != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::ContextManager*)contextMgr)->getSingleContext();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Context_Free(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
DFHack::Context* c = (DFHack::Context*)context;
|
||||
delete c;
|
||||
|
||||
context = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int Context_Attach(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->Attach();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_Detach(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->Detach();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_isAttached(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->isAttached();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_Suspend(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->Suspend();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_Resume(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->Resume();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_isSuspended(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->isSuspended();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_ForceResume(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->ForceResume();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_AsyncSuspend(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->AsyncSuspend();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//module getters
|
||||
|
||||
DFHackObject* Context_getMemoryInfo(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getMemoryInfo();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getProcess(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getProcess();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getCreatures(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getCreatures();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getMaps(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getMaps();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getGui(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getGui();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getMaterials(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getMaterials();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getTranslation(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getTranslation();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getVegetation(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getVegetation();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getBuildings(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getBuildings();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getConstructions(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getConstructions();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getItems(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getItems();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getWorld(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getWorld();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getWindowIO(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getWindowIO();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Context_ReadRaw(DFHackObject* context, const uint32_t offset, const uint32_t size, uint8_t* target)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
((DFHack::Context*)context)->ReadRaw(offset, size, target);
|
||||
}
|
||||
}
|
||||
|
||||
void Context_WriteRaw(DFHackObject* context, const uint32_t offset, const uint32_t size, uint8_t* source)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
((DFHack::Context*)context)->WriteRaw(offset, size, source);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,488 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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 "PlatformInternal.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
using namespace std;
|
||||
|
||||
#include "SHMProcess.h"
|
||||
#include "ProcessFactory.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
#include "shms.h"
|
||||
#include "mod-core.h"
|
||||
|
||||
using namespace DFHack;
|
||||
|
||||
Process* DFHack::createSHMProcess(uint32_t pid, VersionInfoFactory * factory)
|
||||
{
|
||||
return new SHMProcess(pid, factory);
|
||||
}
|
||||
|
||||
SHMProcess::SHMProcess(uint32_t PID, VersionInfoFactory * factory)
|
||||
: d(new Private(this))
|
||||
{
|
||||
d->process_ID = PID;
|
||||
// attach the SHM
|
||||
if(!attach())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Test bridge version, get PID, sync Yield
|
||||
bool bridgeOK;
|
||||
if(!d->Aux_Core_Attach(bridgeOK,d->process_ID))
|
||||
{
|
||||
detach();
|
||||
throw Error::SHMAttachFailure();
|
||||
}
|
||||
else if(!bridgeOK)
|
||||
{
|
||||
detach();
|
||||
throw Error::SHMVersionMismatch();
|
||||
}
|
||||
|
||||
// try to identify the DF version (md5 the binary, compare with known versions)
|
||||
d->validate(factory);
|
||||
// at this point, DF is attached and suspended, make it run
|
||||
detach();
|
||||
}
|
||||
|
||||
SHMProcess::~SHMProcess()
|
||||
{
|
||||
if(d->attached)
|
||||
{
|
||||
detach();
|
||||
}
|
||||
// destroy data model. this is assigned by processmanager
|
||||
if(d->memdescriptor)
|
||||
delete d->memdescriptor;
|
||||
delete d;
|
||||
}
|
||||
|
||||
VersionInfo * SHMProcess::getDescriptor()
|
||||
{
|
||||
return d->memdescriptor;
|
||||
}
|
||||
|
||||
int SHMProcess::getPID()
|
||||
{
|
||||
return d->process_ID;
|
||||
}
|
||||
|
||||
|
||||
bool SHMProcess::isSuspended()
|
||||
{
|
||||
return d->locked;
|
||||
}
|
||||
bool SHMProcess::isAttached()
|
||||
{
|
||||
return d->attached;
|
||||
}
|
||||
|
||||
bool SHMProcess::isIdentified()
|
||||
{
|
||||
return d->identified;
|
||||
}
|
||||
|
||||
bool SHMProcess::suspend()
|
||||
{
|
||||
if(!d->attached)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(d->locked)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//cerr << "suspend" << endl;// FIXME: throw
|
||||
// FIXME: this should be controlled on the server side
|
||||
// FIXME: IF server got CORE_RUN in this frame, interpret CORE_SUSPEND as CORE_STEP
|
||||
// did we just resume a moment ago?
|
||||
if(D_SHMCMD == CORE_RUN)
|
||||
{
|
||||
//fprintf(stderr,"%d invokes step\n",attachmentIdx);
|
||||
// wait for the next window
|
||||
/*
|
||||
if(!d->SetAndWait(CORE_STEP))
|
||||
{
|
||||
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))");
|
||||
}
|
||||
*/
|
||||
D_SHMCMD = CORE_STEP;
|
||||
}
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"%d invokes suspend\n",attachmentIdx);
|
||||
// lock now
|
||||
/*
|
||||
if(!d->SetAndWait(CORE_SUSPEND))
|
||||
{
|
||||
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))");
|
||||
}
|
||||
*/
|
||||
D_SHMCMD = CORE_SUSPEND;
|
||||
}
|
||||
//fprintf(stderr,"waiting for lock\n");
|
||||
// we wait for the server to give up our suspend lock (held by default)
|
||||
if(acquireSuspendLock())
|
||||
{
|
||||
d->locked = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: needs a good think-through
|
||||
bool SHMProcess::asyncSuspend()
|
||||
{
|
||||
if(!d->attached)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(d->locked)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//cerr << "async suspend" << endl;// FIXME: throw
|
||||
uint32_t cmd = D_SHMCMD;
|
||||
if(cmd == CORE_SUSPENDED)
|
||||
{
|
||||
// we have to hold the lock to be really suspended
|
||||
if(acquireSuspendLock())
|
||||
{
|
||||
d->locked = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// did we just resume a moment ago?
|
||||
if(cmd == CORE_STEP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if(cmd == CORE_RUN)
|
||||
{
|
||||
D_SHMCMD = CORE_STEP;
|
||||
}
|
||||
else
|
||||
{
|
||||
D_SHMCMD = CORE_SUSPEND;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SHMProcess::forceresume()
|
||||
{
|
||||
return resume();
|
||||
}
|
||||
|
||||
// FIXME: wait for the server to advance a step!
|
||||
bool SHMProcess::resume()
|
||||
{
|
||||
if(!d->attached)
|
||||
return false;
|
||||
if(!d->locked)
|
||||
return true;
|
||||
//cerr << "resume" << endl;// FIXME: throw
|
||||
// unlock the suspend lock
|
||||
if(releaseSuspendLock())
|
||||
{
|
||||
d->locked = false;
|
||||
if(d->SetAndWait(CORE_RUN)) // we have to make sure the server responds!
|
||||
{
|
||||
return true;
|
||||
}
|
||||
throw Error::SHMLockingError("if(d->SetAndWait(CORE_RUN))");
|
||||
}
|
||||
throw Error::SHMLockingError("if(releaseSuspendLock())");
|
||||
return false;
|
||||
}
|
||||
|
||||
// get module index by name and version. bool 0 = error
|
||||
bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(0xdeadbeef);
|
||||
|
||||
modulelookup * payload = D_SHMDATA(modulelookup);
|
||||
payload->version = version;
|
||||
|
||||
strncpy(payload->name,name,255);
|
||||
payload->name[255] = 0;
|
||||
|
||||
if(!SetAndWait(CORE_ACQUIRE_MODULE))
|
||||
{
|
||||
return false; // FIXME: throw a fatal exception instead
|
||||
}
|
||||
if(D_SHMHDR->error)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value);
|
||||
OUTPUT = D_SHMHDR->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID)
|
||||
{
|
||||
if(!locked) throw Error::MemoryAccessDenied(0xdeadbeef);
|
||||
|
||||
SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
|
||||
if(!SetAndWait(CORE_ATTACH)) return false;
|
||||
/*
|
||||
cerr <<"CORE_VERSION" << CORE_VERSION << endl;
|
||||
cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl;
|
||||
*/
|
||||
versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
|
||||
PID = SHMDATA(coreattach)->sv_PID;
|
||||
useYield = SHMDATA(coreattach)->sv_useYield;
|
||||
#ifdef DEBUG
|
||||
if(useYield) cerr << "Using Yield!" << endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(src_address);
|
||||
|
||||
// normal read under 1MB
|
||||
if(size <= SHM_BODY)
|
||||
{
|
||||
D_SHMHDR->address = src_address;
|
||||
D_SHMHDR->length = size;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ);
|
||||
memcpy (target_buffer, D_SHMDATA(void),size);
|
||||
}
|
||||
// a big read, we pull data over the shm in iterations
|
||||
else
|
||||
{
|
||||
// first read equals the size of the SHM window
|
||||
uint32_t to_read = SHM_BODY;
|
||||
while (size)
|
||||
{
|
||||
// read to_read bytes from src_cursor
|
||||
D_SHMHDR->address = src_address;
|
||||
D_SHMHDR->length = to_read;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ);
|
||||
memcpy (target_buffer, D_SHMDATA(void) ,to_read);
|
||||
// decrease size by bytes read
|
||||
size -= to_read;
|
||||
// move the cursors
|
||||
src_address += to_read;
|
||||
target_buffer += to_read;
|
||||
// check how much to write in the next iteration
|
||||
to_read = min(size, (uint32_t) SHM_BODY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_BYTE);
|
||||
val = D_SHMHDR->value;
|
||||
}
|
||||
|
||||
void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_WORD);
|
||||
val = D_SHMHDR->value;
|
||||
}
|
||||
|
||||
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_DWORD);
|
||||
val = D_SHMHDR->value;
|
||||
}
|
||||
|
||||
void SHMProcess::readQuad (const uint32_t offset, uint64_t &val)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_QUAD);
|
||||
val = D_SHMHDR->Qvalue;
|
||||
}
|
||||
|
||||
void SHMProcess::readFloat (const uint32_t offset, float &val)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_DWORD);
|
||||
val = reinterpret_cast<float&> (D_SHMHDR->value);
|
||||
}
|
||||
|
||||
/*
|
||||
* WRITING
|
||||
*/
|
||||
|
||||
void SHMProcess::writeQuad (uint32_t offset, uint64_t data)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
D_SHMHDR->Qvalue = data;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE_QUAD);
|
||||
}
|
||||
|
||||
void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
D_SHMHDR->value = data;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE_DWORD);
|
||||
}
|
||||
|
||||
// using these is expensive.
|
||||
void SHMProcess::writeWord (uint32_t offset, uint16_t data)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
D_SHMHDR->value = data;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE_WORD);
|
||||
}
|
||||
|
||||
void SHMProcess::writeByte (uint32_t offset, uint8_t data)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
D_SHMHDR->value = data;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE_BYTE);
|
||||
}
|
||||
|
||||
void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(dst_address);
|
||||
|
||||
// normal write under 1MB
|
||||
if(size <= SHM_BODY)
|
||||
{
|
||||
D_SHMHDR->address = dst_address;
|
||||
D_SHMHDR->length = size;
|
||||
memcpy(D_SHMDATA(void),source_buffer, size);
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE);
|
||||
}
|
||||
// a big write, we push this over the shm in iterations
|
||||
else
|
||||
{
|
||||
// first write equals the size of the SHM window
|
||||
uint32_t to_write = SHM_BODY;
|
||||
while (size)
|
||||
{
|
||||
// write to_write bytes to dst_cursor
|
||||
D_SHMHDR->address = dst_address;
|
||||
D_SHMHDR->length = to_write;
|
||||
memcpy(D_SHMDATA(void),source_buffer, to_write);
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE);
|
||||
// decrease size by bytes written
|
||||
size -= to_write;
|
||||
// move the cursors
|
||||
source_buffer += to_write;
|
||||
dst_address += to_write;
|
||||
// check how much to write in the next iteration
|
||||
to_write = min(size, (uint32_t) SHM_BODY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string SHMProcess::readCString (uint32_t offset)
|
||||
{
|
||||
std::string temp;
|
||||
int counter = 0;
|
||||
char r;
|
||||
while (1)
|
||||
{
|
||||
r = Process::readByte(offset+counter);
|
||||
if(!r) break;
|
||||
counter++;
|
||||
temp.append(1,r);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
const std::string SHMProcess::readSTLString(uint32_t offset)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_STL_STRING);
|
||||
return(string( D_SHMDATA(char) ));
|
||||
}
|
||||
|
||||
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_STL_STRING);
|
||||
size_t length = D_SHMHDR->value;
|
||||
size_t fit = min(bufcapacity - 1, length);
|
||||
strncpy(buffer,D_SHMDATA(char),fit);
|
||||
buffer[fit] = 0;
|
||||
return fit;
|
||||
}
|
||||
|
||||
size_t SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(address);
|
||||
|
||||
D_SHMHDR->address = address;
|
||||
strncpy(D_SHMDATA(char),writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE_STL_STRING);
|
||||
return writeString.length();
|
||||
}
|
@ -1,421 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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 "PlatformInternal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdio>
|
||||
using namespace std;
|
||||
|
||||
#include "SHMProcess.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <time.h>
|
||||
#include <shms.h>
|
||||
#include <mod-core.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <sched.h>
|
||||
#include <md5wrapper.h>
|
||||
using namespace DFHack;
|
||||
|
||||
SHMProcess::Private::Private(SHMProcess * self_)
|
||||
{
|
||||
memdescriptor = NULL;
|
||||
process_ID = 0;
|
||||
shm_ID = -1;
|
||||
attached = false;
|
||||
identified = false;
|
||||
useYield = false;
|
||||
server_lock = -1;
|
||||
client_lock = -1;
|
||||
suspend_lock = -1;
|
||||
locked = false;
|
||||
self = self_;
|
||||
}
|
||||
|
||||
bool SHMProcess::Private::SetAndWait (uint32_t state)
|
||||
{
|
||||
uint32_t cnt = 0;
|
||||
if(!attached) return false;
|
||||
SHMCMD = state;
|
||||
|
||||
while (SHMCMD == state)
|
||||
{
|
||||
// yield the CPU, only on single-core CPUs
|
||||
if(useYield)
|
||||
{
|
||||
SCHED_YIELD
|
||||
}
|
||||
if(cnt == 10000)
|
||||
{
|
||||
if(!AreLocksOk())// DF not there anymore?
|
||||
{
|
||||
//detach the shared memory
|
||||
shmdt(shm_addr);
|
||||
FreeLocks();
|
||||
attached = locked = identified = false;
|
||||
// we aren't the current process anymore
|
||||
throw Error::SHMServerDisappeared();
|
||||
}
|
||||
else
|
||||
{
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
// server returned a generic error
|
||||
if(SHMCMD == CORE_ERROR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Yeah. with no way to synchronize things (locks are slow, the OS doesn't give us
|
||||
enough control over scheduling)
|
||||
we end up with this silly thing
|
||||
*/
|
||||
bool SHMProcess::SetAndWait (uint32_t state)
|
||||
{
|
||||
return d->SetAndWait(state);
|
||||
}
|
||||
|
||||
uint32_t OS_getAffinity()
|
||||
{
|
||||
cpu_set_t mask;
|
||||
sched_getaffinity(0,sizeof(cpu_set_t),&mask);
|
||||
// FIXME: truncation
|
||||
uint32_t affinity = *(uint32_t *) &mask;
|
||||
return affinity;
|
||||
}
|
||||
|
||||
void SHMProcess::Private::FreeLocks()
|
||||
{
|
||||
attachmentIdx = -1;
|
||||
if(client_lock != -1)
|
||||
{
|
||||
lockf(client_lock,F_ULOCK,0);
|
||||
close(client_lock);
|
||||
client_lock = -1;
|
||||
}
|
||||
if(server_lock != -1)
|
||||
{
|
||||
close(server_lock);
|
||||
server_lock = -1;
|
||||
}
|
||||
if(suspend_lock != -1)
|
||||
{
|
||||
close(suspend_lock);
|
||||
locked = false;
|
||||
suspend_lock = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool SHMProcess::Private::GetLocks()
|
||||
{
|
||||
char name[256];
|
||||
// try to acquire locks
|
||||
// look at the server lock, if it's locked, the server is present
|
||||
sprintf(name, "/tmp/DFHack/%d/SVlock",process_ID);
|
||||
server_lock = open(name,O_WRONLY);
|
||||
if(server_lock == -1)
|
||||
{
|
||||
// cerr << "can't open sv lock" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(lockf( server_lock, F_TEST, 0 ) != -1)
|
||||
{
|
||||
cerr << "sv lock not locked" << endl;
|
||||
close(server_lock);
|
||||
server_lock = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < SHM_MAX_CLIENTS; i++)
|
||||
{
|
||||
// open the client suspend locked
|
||||
sprintf(name, "/tmp/DFHack/%d/CLSlock%d",process_ID,i);
|
||||
suspend_lock = open(name,O_WRONLY);
|
||||
if(suspend_lock == -1)
|
||||
{
|
||||
cerr << "can't open cl S-lock " << i << endl;
|
||||
// couldn't open lock
|
||||
continue;
|
||||
}
|
||||
|
||||
// open the client lock, try to lock it
|
||||
sprintf(name, "/tmp/DFHack/%d/CLlock%d",process_ID,i);
|
||||
client_lock = open(name,O_WRONLY);
|
||||
if(client_lock == -1)
|
||||
{
|
||||
cerr << "can't open cl lock " << i << endl;
|
||||
close(suspend_lock);
|
||||
locked = false;
|
||||
suspend_lock = -1;
|
||||
// couldn't open lock
|
||||
continue;
|
||||
}
|
||||
if(lockf(client_lock,F_TLOCK, 0) == -1)
|
||||
{
|
||||
// couldn't acquire lock
|
||||
cerr << "can't acquire cl lock " << i << endl;
|
||||
close(suspend_lock);
|
||||
locked = false;
|
||||
suspend_lock = -1;
|
||||
close(client_lock);
|
||||
client_lock = -1;
|
||||
continue;
|
||||
}
|
||||
// ok, we have all the locks we need!
|
||||
attachmentIdx = i;
|
||||
return true;
|
||||
}
|
||||
close(server_lock);
|
||||
server_lock = -1;
|
||||
cerr << "can't get any client locks" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// test if we have client and server locks and the server is present
|
||||
bool SHMProcess::Private::AreLocksOk()
|
||||
{
|
||||
// both locks are inited (we hold our lock)
|
||||
if(client_lock != -1 && server_lock != -1)
|
||||
{
|
||||
if(lockf(server_lock,F_TEST,0) == -1) // and server holds its lock
|
||||
{
|
||||
return true; // OK, locks are good
|
||||
}
|
||||
}
|
||||
// locks are bad
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SHMProcess::Private::validate(VersionInfoFactory * factory)
|
||||
{
|
||||
char exe_link_name [256];
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
// find the binary
|
||||
sprintf(exe_link_name,"/proc/%d/exe", process_ID);
|
||||
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
|
||||
if (target_result == -1)
|
||||
{
|
||||
perror("readlink");
|
||||
return false;
|
||||
}
|
||||
// make sure we have a null terminated string...
|
||||
// see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html
|
||||
target_name[target_result] = 0;
|
||||
|
||||
// get hash of the running DF process
|
||||
md5wrapper md5;
|
||||
string hash = md5.getHashFromFile(target_name);
|
||||
|
||||
// create linux process, add it to the vector
|
||||
VersionInfo * vinfo = factory->getVersionInfoByMD5(hash);
|
||||
if(vinfo)
|
||||
{
|
||||
memdescriptor = vinfo;
|
||||
// FIXME: BIG BAD BUG RIGHT HERE!!!!
|
||||
memdescriptor->setParentProcess(self);
|
||||
identified = true;
|
||||
vector_start = memdescriptor->getGroup("vector")->getOffset("start");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// there is only one we care about.
|
||||
bool SHMProcess::getThreadIDs(vector<uint32_t> & threads )
|
||||
{
|
||||
if(d->attached)
|
||||
{
|
||||
threads.clear();
|
||||
threads.push_back(d->process_ID);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//FIXME: cross-reference with ELF segment entries?
|
||||
void SHMProcess::getMemRanges( vector<t_memrange> & ranges )
|
||||
{
|
||||
char buffer[1024];
|
||||
char permissions[5]; // r/-, w/-, x/-, p/s, 0
|
||||
|
||||
sprintf(buffer, "/proc/%lu/maps", (long unsigned)d->process_ID);
|
||||
FILE *mapFile = ::fopen(buffer, "r");
|
||||
uint64_t offset, device1, device2, node;
|
||||
|
||||
while (fgets(buffer, 1024, mapFile))
|
||||
{
|
||||
t_memrange temp;
|
||||
temp.name[0] = 0;
|
||||
sscanf(buffer, "%zx-%zx %s %zx %2zu:%2zu %zu %s",
|
||||
&temp.start,
|
||||
&temp.end,
|
||||
(char*)&permissions,
|
||||
&offset, &device1, &device2, &node,
|
||||
(char*)&temp.name);
|
||||
temp.read = permissions[0] == 'r';
|
||||
temp.write = permissions[1] == 'w';
|
||||
temp.execute = permissions[2] == 'x';
|
||||
temp.valid = true;
|
||||
ranges.push_back(temp);
|
||||
}
|
||||
}
|
||||
|
||||
bool SHMProcess::acquireSuspendLock()
|
||||
{
|
||||
return (lockf(d->suspend_lock,F_LOCK,0) == 0);
|
||||
}
|
||||
|
||||
bool SHMProcess::releaseSuspendLock()
|
||||
{
|
||||
return (lockf(d->suspend_lock,F_ULOCK,0) == 0);
|
||||
}
|
||||
|
||||
|
||||
bool SHMProcess::attach()
|
||||
{
|
||||
if(d->attached)
|
||||
{
|
||||
if(!d->locked)
|
||||
return suspend();
|
||||
return true;
|
||||
}
|
||||
//cerr << "attach" << endl;// FIXME: throw
|
||||
if(!d->GetLocks())
|
||||
{
|
||||
//cerr << "server is full or not really there!" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate the segment.
|
||||
*/
|
||||
if ((d->shm_ID = shmget(SHM_KEY + d->process_ID, SHM_SIZE, 0666)) < 0)
|
||||
{
|
||||
d->FreeLocks();
|
||||
cerr << "can't find segment" << endl; // FIXME: throw
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach the segment
|
||||
*/
|
||||
if ((d->shm_addr = (char *) shmat(d->shm_ID, NULL, 0)) == (char *) -1)
|
||||
{
|
||||
d->FreeLocks();
|
||||
cerr << "can't attach segment" << endl; // FIXME: throw
|
||||
return false;
|
||||
}
|
||||
d->attached = true;
|
||||
if(!suspend())
|
||||
{
|
||||
shmdt(d->shm_addr);
|
||||
d->FreeLocks();
|
||||
cerr << "unable to suspend" << endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHMProcess::detach()
|
||||
{
|
||||
if(!d->attached) return true;
|
||||
if(d->locked)
|
||||
{
|
||||
resume();
|
||||
}
|
||||
// detach segment
|
||||
if(shmdt(d->shm_addr) != -1)
|
||||
{
|
||||
d->FreeLocks();
|
||||
d->locked = false;
|
||||
d->attached = false;
|
||||
d->shm_addr = 0;
|
||||
return true;
|
||||
}
|
||||
// fail if we can't detach
|
||||
// FIXME: throw exception here??
|
||||
perror("failed to detach shared segment");
|
||||
return false;
|
||||
}
|
||||
|
||||
void SHMProcess::readSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
read(address + d->vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
void SHMProcess::writeSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
write(address + d->vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
|
||||
string SHMProcess::doReadClassName (uint32_t vptr)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(vptr);
|
||||
|
||||
int typeinfo = Process::readDWord(vptr - 0x4);
|
||||
int typestring = Process::readDWord(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);
|
||||
}
|
||||
|
||||
string SHMProcess::getPath()
|
||||
{
|
||||
char cwd_name[256];
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
|
||||
sprintf(cwd_name,"/proc/%d/cwd", getPID());
|
||||
// resolve /proc/PID/exe link
|
||||
target_result = readlink(cwd_name, target_name, sizeof(target_name));
|
||||
target_name[target_result] = '\0';
|
||||
return(string(target_name));
|
||||
}
|
||||
|
||||
char * SHMProcess::getSHMStart (void)
|
||||
{
|
||||
if(!d->locked) return 0; //THROW HERE!
|
||||
|
||||
return d->shm_addr;
|
||||
}
|
@ -1,326 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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 "PlatformInternal.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdio>
|
||||
using namespace std;
|
||||
|
||||
#include "LinuxProcess.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
#include <errno.h>
|
||||
#include <sys/ptrace.h>
|
||||
using namespace DFHack;
|
||||
|
||||
LinuxProcessBase::LinuxProcessBase(uint32_t pid)
|
||||
: my_pid(pid)
|
||||
{
|
||||
my_descriptor = NULL;
|
||||
attached = false;
|
||||
suspended = false;
|
||||
memFileHandle = 0;
|
||||
}
|
||||
|
||||
bool LinuxProcessBase::isSuspended()
|
||||
{
|
||||
return suspended;
|
||||
}
|
||||
bool LinuxProcessBase::isAttached()
|
||||
{
|
||||
return attached;
|
||||
}
|
||||
|
||||
bool LinuxProcessBase::isIdentified()
|
||||
{
|
||||
return identified;
|
||||
}
|
||||
|
||||
LinuxProcessBase::~LinuxProcessBase()
|
||||
{
|
||||
// destroy our copy of the memory descriptor
|
||||
if(my_descriptor)
|
||||
delete my_descriptor;
|
||||
}
|
||||
|
||||
VersionInfo * LinuxProcessBase::getDescriptor()
|
||||
{
|
||||
return my_descriptor;
|
||||
}
|
||||
|
||||
int LinuxProcessBase::getPID()
|
||||
{
|
||||
return my_pid;
|
||||
}
|
||||
|
||||
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 LinuxProcessBase::getThreadIDs(vector<uint32_t> & threads )
|
||||
{
|
||||
stringstream ss;
|
||||
vector<string> subdirs;
|
||||
ss << "/proc/" << my_pid << "/task/";
|
||||
if(getdir(ss.str(),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;
|
||||
}
|
||||
|
||||
//FIXME: cross-reference with ELF segment entries?
|
||||
void LinuxProcessBase::getMemRanges( vector<t_memrange> & ranges )
|
||||
{
|
||||
char buffer[1024];
|
||||
char permissions[5]; // r/-, w/-, x/-, p/s, 0
|
||||
|
||||
sprintf(buffer, "/proc/%lu/maps", (long unsigned)my_pid);
|
||||
FILE *mapFile = ::fopen(buffer, "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 %2zu:%2zu %zu %[^\n]s",
|
||||
&start,
|
||||
&end,
|
||||
(char*)&permissions,
|
||||
&offset, &device1, &device2, &node,
|
||||
(char*)&temp.name);
|
||||
temp.start = start;
|
||||
temp.end = 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);
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxProcessBase::read (const uint32_t offset, const uint32_t size, uint8_t *target)
|
||||
{
|
||||
if(size == 0) return;
|
||||
|
||||
ssize_t result;
|
||||
ssize_t total = 0;
|
||||
ssize_t remaining = size;
|
||||
while (total != size)
|
||||
{
|
||||
result = pread(memFileHandle, target + total ,remaining,offset + total);
|
||||
if(result == -1)
|
||||
{
|
||||
cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl;
|
||||
cerr << "errno: " << errno << endl;
|
||||
errno = 0;
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
total += result;
|
||||
remaining -= result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxProcessBase::readByte (const uint32_t offset, uint8_t &val )
|
||||
{
|
||||
read(offset, 1, &val);
|
||||
}
|
||||
|
||||
void LinuxProcessBase::readWord (const uint32_t offset, uint16_t &val)
|
||||
{
|
||||
read(offset, 2, (uint8_t *) &val);
|
||||
}
|
||||
|
||||
void LinuxProcessBase::readDWord (const uint32_t offset, uint32_t &val)
|
||||
{
|
||||
read(offset, 4, (uint8_t *) &val);
|
||||
}
|
||||
|
||||
void LinuxProcessBase::readFloat (const uint32_t offset, float &val)
|
||||
{
|
||||
read(offset, 4, (uint8_t *) &val);
|
||||
}
|
||||
|
||||
void LinuxProcessBase::readQuad (const uint32_t offset, uint64_t &val)
|
||||
{
|
||||
read(offset, 8, (uint8_t *) &val);
|
||||
}
|
||||
|
||||
/*
|
||||
* WRITING
|
||||
*/
|
||||
|
||||
void LinuxProcessBase::writeQuad (uint32_t offset, const uint64_t data)
|
||||
{
|
||||
#ifdef HAVE_64_BIT
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, data);
|
||||
#else
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, (uint32_t) data);
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset+4, (uint32_t) (data >> 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
void LinuxProcessBase::writeDWord (uint32_t offset, uint32_t data)
|
||||
{
|
||||
#ifdef HAVE_64_BIT
|
||||
uint64_t orig = Process::readQuad(offset);
|
||||
orig &= 0xFFFFFFFF00000000;
|
||||
orig |= data;
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
|
||||
#else
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, data);
|
||||
#endif
|
||||
}
|
||||
|
||||
// using these is expensive.
|
||||
void LinuxProcessBase::writeWord (uint32_t offset, uint16_t data)
|
||||
{
|
||||
#ifdef HAVE_64_BIT
|
||||
uint64_t orig = Process::readQuad(offset);
|
||||
orig &= 0xFFFFFFFFFFFF0000;
|
||||
orig |= data;
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
|
||||
#else
|
||||
uint32_t orig = Process::readDWord(offset);
|
||||
orig &= 0xFFFF0000;
|
||||
orig |= data;
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LinuxProcessBase::writeByte (uint32_t offset, uint8_t data)
|
||||
{
|
||||
#ifdef HAVE_64_BIT
|
||||
uint64_t orig = Process::readQuad(offset);
|
||||
orig &= 0xFFFFFFFFFFFFFF00;
|
||||
orig |= data;
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
|
||||
#else
|
||||
uint32_t orig = Process::readDWord(offset);
|
||||
orig &= 0xFFFFFF00;
|
||||
orig |= data;
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
|
||||
#endif
|
||||
}
|
||||
|
||||
// blah. THIS IS RIDICULOUS
|
||||
void LinuxProcessBase::write (uint32_t offset, uint32_t size, uint8_t *source)
|
||||
{
|
||||
uint32_t indexptr = 0;
|
||||
while (size > 0)
|
||||
{
|
||||
#ifdef HAVE_64_BIT
|
||||
// quad!
|
||||
if(size >= 8)
|
||||
{
|
||||
writeQuad(offset, *(uint64_t *) (source + indexptr));
|
||||
offset +=8;
|
||||
indexptr +=8;
|
||||
size -=8;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
// default: we push 4 bytes
|
||||
if(size >= 4)
|
||||
{
|
||||
writeDWord(offset, *(uint32_t *) (source + indexptr));
|
||||
offset +=4;
|
||||
indexptr +=4;
|
||||
size -=4;
|
||||
}
|
||||
// last is either three or 2 bytes
|
||||
else if(size >= 2)
|
||||
{
|
||||
writeWord(offset, *(uint16_t *) (source + indexptr));
|
||||
offset +=2;
|
||||
indexptr +=2;
|
||||
size -=2;
|
||||
}
|
||||
// finishing move
|
||||
else if(size == 1)
|
||||
{
|
||||
writeByte(offset, *(uint8_t *) (source + indexptr));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string LinuxProcessBase::readCString (uint32_t offset)
|
||||
{
|
||||
std::string temp;
|
||||
int counter = 0;
|
||||
char r;
|
||||
while (1)
|
||||
{
|
||||
r = Process::readByte(offset+counter);
|
||||
if(!r) break;
|
||||
counter++;
|
||||
temp.append(1,r);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
string LinuxProcessBase::getPath()
|
||||
{
|
||||
char cwd_name[256];
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
|
||||
sprintf(cwd_name,"/proc/%d/cwd", getPID());
|
||||
// resolve /proc/PID/exe link
|
||||
target_result = readlink(cwd_name, target_name, sizeof(target_name));
|
||||
target_name[target_result] = '\0';
|
||||
return(string(target_name));
|
||||
}
|
@ -1,280 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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 "PlatformInternal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
using namespace std;
|
||||
|
||||
#include "LinuxProcess.h"
|
||||
#include "ProcessFactory.h"
|
||||
#include "MicrosoftSTL.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
using namespace DFHack;
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
#include <md5wrapper.h>
|
||||
|
||||
|
||||
namespace {
|
||||
class WineProcess : public LinuxProcessBase
|
||||
{
|
||||
private:
|
||||
uint8_t vector_start;
|
||||
MicrosoftSTL stl;
|
||||
public:
|
||||
WineProcess(uint32_t pid, VersionInfoFactory * factory);
|
||||
~WineProcess()
|
||||
{
|
||||
if(attached)
|
||||
{
|
||||
detach();
|
||||
}
|
||||
}
|
||||
bool attach();
|
||||
bool detach();
|
||||
|
||||
bool suspend();
|
||||
bool asyncSuspend();
|
||||
bool resume();
|
||||
bool forceresume();
|
||||
|
||||
void readSTLVector(const uint32_t address, t_vecTriplet & triplet);
|
||||
void writeSTLVector(const uint32_t address, t_vecTriplet & triplet);
|
||||
const std::string readSTLString (uint32_t offset);
|
||||
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
|
||||
size_t writeSTLString(const uint32_t address, const std::string writeString);
|
||||
// get class name of an object with rtti/type info
|
||||
std::string doReadClassName(uint32_t vptr);
|
||||
};
|
||||
}
|
||||
|
||||
Process* DFHack::createWineProcess(uint32_t pid, VersionInfoFactory * factory)
|
||||
{
|
||||
return new WineProcess(pid, factory);
|
||||
}
|
||||
|
||||
WineProcess::WineProcess(uint32_t pid, VersionInfoFactory * factory) : LinuxProcessBase(pid)
|
||||
{
|
||||
char dir_name [256];
|
||||
char exe_link_name [256];
|
||||
char mem_name [256];
|
||||
char cwd_name [256];
|
||||
char cmdline_name [256];
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
|
||||
identified = false;
|
||||
my_descriptor = 0;
|
||||
|
||||
sprintf(dir_name,"/proc/%d/", pid);
|
||||
sprintf(exe_link_name,"/proc/%d/exe", pid);
|
||||
sprintf(mem_name,"/proc/%d/mem", pid);
|
||||
memFile = mem_name;
|
||||
sprintf(cwd_name,"/proc/%d/cwd", pid);
|
||||
sprintf(cmdline_name,"/proc/%d/cmdline", pid);
|
||||
|
||||
// resolve /proc/PID/exe link
|
||||
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
|
||||
if (target_result == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// make sure we have a null terminated string...
|
||||
target_name[target_result] = 0;
|
||||
|
||||
// FIXME: this fails when the wine process isn't started from the 'current working directory'. strip path data from cmdline
|
||||
// is this windows version of Df running in wine?
|
||||
if(strstr(target_name, "wine-preloader")!= NULL)
|
||||
{
|
||||
// get working directory
|
||||
target_result = readlink(cwd_name, target_name, sizeof(target_name)-1);
|
||||
target_name[target_result] = 0;
|
||||
|
||||
// got path to executable, do the same for its name
|
||||
ifstream ifs ( cmdline_name , ifstream::in );
|
||||
string cmdline;
|
||||
getline(ifs,cmdline);
|
||||
if (cmdline.find("dwarfort-w.exe") != string::npos || cmdline.find("dwarfort.exe") != string::npos || cmdline.find("Dwarf Fortress.exe") != string::npos)
|
||||
{
|
||||
char exe_link[1024];
|
||||
// put executable name and path together
|
||||
sprintf(exe_link,"%s/%s",target_name,cmdline.c_str());
|
||||
|
||||
md5wrapper md5;
|
||||
// get hash of the running DF process
|
||||
string hash = md5.getHashFromFile(exe_link);
|
||||
// create linux process, add it to the vector
|
||||
VersionInfo * vinfo = factory->getVersionInfoByMD5(hash);
|
||||
if(vinfo)
|
||||
{
|
||||
my_descriptor = new VersionInfo(*vinfo);
|
||||
my_descriptor->setParentProcess(this);
|
||||
vector_start = my_descriptor->getGroup("vector")->getOffset("start");
|
||||
stl.init(this);
|
||||
identified = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WineProcess::readSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
read(address + vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
void WineProcess::writeSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
write(address + vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
|
||||
{
|
||||
return stl.readSTLString(offset, buffer, bufcapacity);
|
||||
}
|
||||
|
||||
size_t WineProcess::writeSTLString(const uint32_t address, const std::string writeString)
|
||||
{
|
||||
return stl.writeSTLString(address,writeString);
|
||||
}
|
||||
|
||||
|
||||
const string WineProcess::readSTLString (uint32_t offset)
|
||||
{
|
||||
return stl.readSTLString(offset);
|
||||
}
|
||||
|
||||
string WineProcess::doReadClassName (uint32_t vptr)
|
||||
{
|
||||
return stl.readClassName(vptr);
|
||||
}
|
||||
|
||||
bool WineProcess::asyncSuspend()
|
||||
{
|
||||
return suspend();
|
||||
}
|
||||
|
||||
bool WineProcess::suspend()
|
||||
{
|
||||
int status;
|
||||
if(suspended)
|
||||
return true;
|
||||
// can we attach?
|
||||
if (ptrace(PTRACE_ATTACH , my_pid, NULL, NULL) == -1)
|
||||
{
|
||||
// no, we got an error
|
||||
perror("ptrace attach error");
|
||||
cerr << "attach failed on pid " << my_pid << endl;
|
||||
return false;
|
||||
}
|
||||
while(true)
|
||||
{
|
||||
// we wait on the pid
|
||||
pid_t w = waitpid(my_pid, &status, 0);
|
||||
if (w == -1)
|
||||
{
|
||||
// child died
|
||||
perror("wait inside attach()");
|
||||
return false;
|
||||
}
|
||||
// stopped -> let's continue
|
||||
if (WIFSTOPPED(status))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
int proc_pid_mem = open(memFile.c_str(),O_RDONLY);
|
||||
if(proc_pid_mem == -1)
|
||||
{
|
||||
ptrace(PTRACE_DETACH, my_pid, NULL, NULL);
|
||||
cerr << memFile << endl;
|
||||
cerr << "couldn't open /proc/" << my_pid << "/mem" << endl;
|
||||
perror("open(memFile.c_str(),O_RDONLY)");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
attached = suspended = true;
|
||||
memFileHandle = proc_pid_mem;
|
||||
return true; // we are attached
|
||||
}
|
||||
}
|
||||
|
||||
bool WineProcess::forceresume()
|
||||
{
|
||||
return resume();
|
||||
}
|
||||
|
||||
bool WineProcess::resume()
|
||||
{
|
||||
if(!suspended)
|
||||
return true;
|
||||
int result = 0;
|
||||
// close /proc/PID/mem
|
||||
result = close(memFileHandle);
|
||||
if(result == -1)
|
||||
{
|
||||
cerr << "couldn't close /proc/"<< my_pid <<"/mem" << endl;
|
||||
perror("mem file close");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// detach
|
||||
result = ptrace(PTRACE_DETACH, my_pid, NULL, NULL);
|
||||
if(result == -1)
|
||||
{
|
||||
cerr << "couldn't detach from process pid" << my_pid << endl;
|
||||
perror("ptrace detach");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
attached = suspended = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool WineProcess::attach()
|
||||
{
|
||||
if(suspended) return true;
|
||||
return suspend();
|
||||
}
|
||||
|
||||
bool WineProcess::detach()
|
||||
{
|
||||
if(!suspended) return true;
|
||||
return resume();
|
||||
}
|
@ -1,410 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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 "PlatformInternal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
using namespace std;
|
||||
|
||||
#include "LinuxProcess.h"
|
||||
#include "ProcessFactory.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
#include <errno.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <md5wrapper.h>
|
||||
using namespace DFHack;
|
||||
|
||||
namespace {
|
||||
class NormalProcess : public LinuxProcessBase
|
||||
{
|
||||
private:
|
||||
uint8_t vector_start;
|
||||
set <uint32_t> thread_ids;
|
||||
|
||||
void waitForSuspend(set<uint32_t> &threads);
|
||||
public:
|
||||
NormalProcess(uint32_t pid, VersionInfoFactory * known_versions);
|
||||
~NormalProcess()
|
||||
{
|
||||
if(attached)
|
||||
{
|
||||
detach();
|
||||
}
|
||||
}
|
||||
bool attach();
|
||||
bool detach();
|
||||
|
||||
bool suspend();
|
||||
bool asyncSuspend();
|
||||
bool resume();
|
||||
bool forceresume();
|
||||
|
||||
void readSTLVector(const uint32_t address, t_vecTriplet & triplet);
|
||||
void writeSTLVector(const uint32_t address, t_vecTriplet & triplet);
|
||||
const std::string readSTLString (uint32_t offset);
|
||||
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
|
||||
size_t writeSTLString(const uint32_t address, const std::string writeString);
|
||||
size_t copySTLString(const uint32_t address, const uint32_t target);
|
||||
// get class name of an object with rtti/type info
|
||||
std::string doReadClassName(uint32_t vptr);
|
||||
};
|
||||
}
|
||||
|
||||
Process* DFHack::createNormalProcess(uint32_t pid, VersionInfoFactory * known_versions)
|
||||
{
|
||||
return new NormalProcess(pid, known_versions);
|
||||
}
|
||||
|
||||
NormalProcess::NormalProcess(uint32_t pid, VersionInfoFactory * known_versions) : LinuxProcessBase(pid)
|
||||
{
|
||||
char dir_name [256];
|
||||
char exe_link_name [256];
|
||||
char mem_name [256];
|
||||
char cwd_name [256];
|
||||
char cmdline_name [256];
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
|
||||
identified = false;
|
||||
my_descriptor = 0;
|
||||
|
||||
sprintf(dir_name,"/proc/%d/", pid);
|
||||
sprintf(exe_link_name,"/proc/%d/exe", pid);
|
||||
sprintf(mem_name,"/proc/%d/mem", pid);
|
||||
memFile = mem_name;
|
||||
sprintf(cwd_name,"/proc/%d/cwd", pid);
|
||||
sprintf(cmdline_name,"/proc/%d/cmdline", pid);
|
||||
|
||||
// resolve /proc/PID/exe link
|
||||
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
|
||||
if (target_result == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// make sure we have a null terminated string...
|
||||
target_name[target_result] = 0;
|
||||
|
||||
// is this the regular linux DF?
|
||||
if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0)
|
||||
{
|
||||
md5wrapper md5;
|
||||
// get hash of the running DF process
|
||||
string hash = md5.getHashFromFile(target_name);
|
||||
// create linux process, add it to the vector
|
||||
VersionInfo * vinfo = known_versions->getVersionInfoByMD5(hash);
|
||||
if(vinfo)
|
||||
{
|
||||
my_descriptor = new VersionInfo(*vinfo);
|
||||
my_descriptor->setParentProcess(this);
|
||||
vector_start = my_descriptor->getGroup("vector")->getOffset("start");
|
||||
identified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct _Rep_base
|
||||
{
|
||||
uint32_t _M_length; // length of text stored, not including zero termination
|
||||
uint32_t _M_capacity; // capacity, not including zero termination
|
||||
int32_t _M_refcount; // reference count (two STL strings can share a common buffer, copy on write rules apply)
|
||||
};
|
||||
|
||||
size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
|
||||
{
|
||||
_Rep_base header;
|
||||
offset = Process::readDWord(offset);
|
||||
read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
|
||||
size_t read_real = min((size_t)header._M_length, bufcapacity-1);// keep space for null termination
|
||||
read(offset,read_real,(uint8_t * )buffer);
|
||||
buffer[read_real] = 0;
|
||||
return read_real;
|
||||
}
|
||||
|
||||
size_t NormalProcess::writeSTLString(const uint32_t address, const std::string writeString)
|
||||
{
|
||||
_Rep_base header;
|
||||
// get buffer location
|
||||
uint32_t start = Process::readDWord(address);
|
||||
// read the header
|
||||
read(start - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
|
||||
|
||||
// the buffer has actual size = 1. no space for storing anything more than a zero byte
|
||||
if(header._M_capacity == 0)
|
||||
return 0;
|
||||
if(header._M_refcount > 0 ) // one ref or one non-shareable (-1) ref
|
||||
return 0;
|
||||
|
||||
// get writeable length (lesser of our string length and capacity of the target)
|
||||
uint32_t lstr = writeString.length();
|
||||
uint32_t allowed_copy = min(lstr, header._M_capacity);
|
||||
// write header with new length.
|
||||
header._M_length = allowed_copy;
|
||||
write(start - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
|
||||
// write string, add a zero terminator, return bytes written
|
||||
write(start, allowed_copy, (uint8_t *) writeString.c_str());
|
||||
writeByte(start + allowed_copy, 0);
|
||||
return allowed_copy;
|
||||
}
|
||||
|
||||
void NormalProcess::readSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
read(address + vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
void NormalProcess::writeSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
write(address + vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
const string NormalProcess::readSTLString (uint32_t offset)
|
||||
{
|
||||
_Rep_base header;
|
||||
|
||||
offset = Process::readDWord(offset);
|
||||
read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
|
||||
|
||||
// FIXME: use char* everywhere, avoid string
|
||||
char * temp = new char[header._M_length+1];
|
||||
read(offset,header._M_length+1,(uint8_t * )temp);
|
||||
string ret(temp);
|
||||
delete[] temp;
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t NormalProcess::copySTLString (uint32_t offset, uint32_t target)
|
||||
{
|
||||
_Rep_base header;
|
||||
|
||||
offset = Process::readDWord(offset);
|
||||
uint32_t old_target = Process::readDWord(target);
|
||||
|
||||
if (offset == old_target)
|
||||
return 0;
|
||||
|
||||
read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
|
||||
|
||||
// destroying the leaked state
|
||||
if (header._M_refcount == -1)
|
||||
header._M_refcount = 1;
|
||||
else
|
||||
header._M_refcount++;
|
||||
|
||||
write(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
|
||||
|
||||
writeDWord(target, offset);
|
||||
return header._M_length;
|
||||
}
|
||||
|
||||
string NormalProcess::doReadClassName (uint32_t vptr)
|
||||
{
|
||||
int typeinfo = Process::readDWord(vptr - 0x4);
|
||||
int typestring = Process::readDWord(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);
|
||||
}
|
||||
|
||||
bool NormalProcess::asyncSuspend()
|
||||
{
|
||||
return suspend();
|
||||
}
|
||||
|
||||
bool NormalProcess::suspend()
|
||||
{
|
||||
if(!attached)
|
||||
return false;
|
||||
if(suspended)
|
||||
return true;
|
||||
|
||||
set<uint32_t> threads;
|
||||
|
||||
for (set<uint32_t>::iterator it = thread_ids.begin(); it != thread_ids.end(); ++it) {
|
||||
if (syscall(SYS_tgkill, my_pid, *it, SIGSTOP) == -1) {
|
||||
cerr << "couldn't stop thread " << *it << endl;
|
||||
perror("kill SIGSTOP error");
|
||||
} else {
|
||||
threads.insert(*it);
|
||||
}
|
||||
}
|
||||
|
||||
if (threads.empty()) {
|
||||
cerr << "couldn't suspend any of the threads";
|
||||
return false;
|
||||
}
|
||||
|
||||
waitForSuspend(threads);
|
||||
|
||||
if (!threads.empty())
|
||||
cerr << "couldn't suspend some of the threads";
|
||||
|
||||
suspended = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NormalProcess::forceresume()
|
||||
{
|
||||
return resume();
|
||||
}
|
||||
|
||||
bool NormalProcess::resume()
|
||||
{
|
||||
if(!attached)
|
||||
return false;
|
||||
if(!suspended)
|
||||
return true;
|
||||
|
||||
bool ok = true;
|
||||
for (set<uint32_t>::iterator it = thread_ids.begin(); it != thread_ids.end(); ++it) {
|
||||
int result = ptrace(PTRACE_CONT, *it, NULL, NULL);
|
||||
if(result == -1)
|
||||
{
|
||||
cerr << "couldn't resume thread " << *it << endl;
|
||||
perror("ptrace resume error");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
suspended = false;
|
||||
return ok;
|
||||
}
|
||||
|
||||
void NormalProcess::waitForSuspend(set<uint32_t> &threads)
|
||||
{
|
||||
int status;
|
||||
while (!threads.empty()) {
|
||||
pid_t w = waitpid(-1, &status, __WALL);
|
||||
if (w == -1) {
|
||||
perror("waitpid");
|
||||
return;
|
||||
}
|
||||
if (threads.find(w) == threads.end()
|
||||
&& thread_ids.find(w) == thread_ids.end())
|
||||
continue;
|
||||
if (WIFSTOPPED(status)) {
|
||||
threads.erase(w);
|
||||
thread_ids.insert(w);
|
||||
} else if (WIFEXITED(status) || WIFSIGNALED(status)) {
|
||||
threads.erase(w);
|
||||
thread_ids.erase(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NormalProcess::attach()
|
||||
{
|
||||
if(attached)
|
||||
{
|
||||
if(!suspended)
|
||||
return suspend();
|
||||
return true;
|
||||
}
|
||||
|
||||
set<uint32_t> threads;
|
||||
vector<uint32_t> thread_vec;
|
||||
|
||||
if (!getThreadIDs(thread_vec))
|
||||
return false;
|
||||
|
||||
for (vector<uint32_t>::iterator it = thread_vec.begin(); it != thread_vec.end(); ++it) {
|
||||
if (ptrace(PTRACE_ATTACH, *it, NULL, NULL) == -1)
|
||||
{
|
||||
// no, we got an error
|
||||
perror("ptrace attach error");
|
||||
cerr << "attach failed on pid " << *it << endl;
|
||||
continue;
|
||||
}
|
||||
threads.insert(*it);
|
||||
}
|
||||
|
||||
thread_ids.clear();
|
||||
waitForSuspend(threads);
|
||||
|
||||
if (thread_ids.empty()) {
|
||||
cerr << "couldn't attach to any threads" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!threads.empty())
|
||||
cerr << "couldn't attach to some threads" << endl;
|
||||
|
||||
suspended = true;
|
||||
|
||||
int proc_pid_mem = open(memFile.c_str(),O_RDONLY);
|
||||
if(proc_pid_mem == -1)
|
||||
{
|
||||
ptrace(PTRACE_DETACH, my_pid, NULL, NULL);
|
||||
cerr << memFile << endl;
|
||||
cerr << "couldn't open /proc/" << my_pid << "/mem" << endl;
|
||||
perror("open(memFile.c_str(),O_RDONLY)");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
attached = true;
|
||||
|
||||
memFileHandle = proc_pid_mem;
|
||||
return true; // we are attached
|
||||
}
|
||||
}
|
||||
|
||||
bool NormalProcess::detach()
|
||||
{
|
||||
if(!attached) return true;
|
||||
if(!suspended) suspend();
|
||||
int result = 0;
|
||||
// close /proc/PID/mem
|
||||
result = close(memFileHandle);
|
||||
if(result == -1)
|
||||
{
|
||||
cerr << "couldn't close /proc/"<< my_pid <<"/mem" << endl;
|
||||
perror("mem file close");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (set<uint32_t>::iterator it = thread_ids.begin(); it != thread_ids.end();) {
|
||||
// detach
|
||||
result = ptrace(PTRACE_DETACH, *it, NULL, NULL);
|
||||
if(result == -1)
|
||||
{
|
||||
cerr << "couldn't detach from process pid" << *it << endl;
|
||||
perror("ptrace detach");
|
||||
return false;;
|
||||
}
|
||||
thread_ids.erase(it++);
|
||||
}
|
||||
|
||||
attached = false;
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,428 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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 "PlatformInternal.h"
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
#include "SHMProcess.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
#include "shms.h"
|
||||
#include "mod-core.h"
|
||||
using namespace DFHack;
|
||||
|
||||
SHMProcess::Private::Private(SHMProcess * self_)
|
||||
{
|
||||
memdescriptor = NULL;
|
||||
process_ID = 0;
|
||||
attached = false;
|
||||
locked = false;
|
||||
identified = false;
|
||||
useYield = 0;
|
||||
DFSVMutex = 0;
|
||||
DFCLMutex = 0;
|
||||
DFCLSuspendMutex = 0;
|
||||
self = self_;
|
||||
}
|
||||
|
||||
bool SHMProcess::Private::SetAndWait (uint32_t state)
|
||||
{
|
||||
uint32_t cnt = 0;
|
||||
if(!attached) return false;
|
||||
SHMCMD = state;
|
||||
|
||||
while (SHMCMD == state)
|
||||
{
|
||||
// yield the CPU, only on single-core CPUs
|
||||
if(useYield)
|
||||
{
|
||||
SCHED_YIELD
|
||||
}
|
||||
if(cnt == 10000)
|
||||
{
|
||||
if(!AreLocksOk())// DF not there anymore?
|
||||
{
|
||||
UnmapViewOfFile(shm_addr);
|
||||
FreeLocks();
|
||||
attached = locked = identified = false;
|
||||
// we aren't the current process anymore
|
||||
throw Error::SHMServerDisappeared();
|
||||
}
|
||||
else
|
||||
{
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
// server returned a generic error
|
||||
if(SHMCMD == CORE_ERROR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHMProcess::SetAndWait (uint32_t state)
|
||||
{
|
||||
return d->SetAndWait(state);
|
||||
}
|
||||
|
||||
uint32_t OS_getAffinity()
|
||||
{
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
DWORD dwProcessAffinityMask, dwSystemAffinityMask;
|
||||
GetProcessAffinityMask( hProcess, &dwProcessAffinityMask, &dwSystemAffinityMask );
|
||||
return dwProcessAffinityMask;
|
||||
}
|
||||
|
||||
void SHMProcess::Private::FreeLocks()
|
||||
{
|
||||
attachmentIdx = -1;
|
||||
if(DFCLMutex != 0)
|
||||
{
|
||||
ReleaseMutex(DFCLMutex);
|
||||
CloseHandle(DFCLMutex);
|
||||
DFCLMutex = 0;
|
||||
}
|
||||
if(DFSVMutex != 0)
|
||||
{
|
||||
CloseHandle(DFSVMutex);
|
||||
DFSVMutex = 0;
|
||||
}
|
||||
if(DFCLSuspendMutex != 0)
|
||||
{
|
||||
ReleaseMutex(DFCLSuspendMutex);
|
||||
CloseHandle(DFCLSuspendMutex);
|
||||
// FIXME: maybe also needs ReleaseMutex!
|
||||
DFCLSuspendMutex = 0;
|
||||
locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SHMProcess::Private::GetLocks()
|
||||
{
|
||||
char name[256];
|
||||
// try to acquire locks
|
||||
// look at the server lock, if it's locked, the server is present
|
||||
sprintf(name,"DFSVMutex-%d",process_ID);
|
||||
DFSVMutex = OpenMutex(SYNCHRONIZE,0, name);
|
||||
if(DFSVMutex == 0)
|
||||
{
|
||||
// cerr << "can't open sv lock" << endl;
|
||||
return false;
|
||||
}
|
||||
// unlike the F_TEST of lockf, this one actually locks. we have to release
|
||||
if(WaitForSingleObject(DFSVMutex,0) == 0)
|
||||
{
|
||||
ReleaseMutex(DFSVMutex);
|
||||
// cerr << "sv lock not locked" << endl;
|
||||
CloseHandle(DFSVMutex);
|
||||
DFSVMutex = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < SHM_MAX_CLIENTS; i++)
|
||||
{
|
||||
// open the client suspend locked
|
||||
sprintf(name, "DFCLSuspendMutex-%d-%d",process_ID,i);
|
||||
DFCLSuspendMutex = OpenMutex(SYNCHRONIZE,0, name);
|
||||
if(DFCLSuspendMutex == 0)
|
||||
{
|
||||
//cerr << "can't open cl S-lock " << i << endl;
|
||||
// couldn't open lock
|
||||
continue;
|
||||
}
|
||||
|
||||
// open the client lock, try to lock it
|
||||
|
||||
sprintf(name,"DFCLMutex-%d-%d",process_ID,i);
|
||||
DFCLMutex = OpenMutex(SYNCHRONIZE,0,name);
|
||||
if(DFCLMutex == 0)
|
||||
{
|
||||
//cerr << "can't open cl lock " << i << endl;
|
||||
CloseHandle(DFCLSuspendMutex);
|
||||
locked = false;
|
||||
DFCLSuspendMutex = 0;
|
||||
continue;
|
||||
}
|
||||
uint32_t waitstate = WaitForSingleObject(DFCLMutex,0);
|
||||
if(waitstate == WAIT_FAILED || waitstate == WAIT_TIMEOUT )
|
||||
{
|
||||
//cerr << "can't acquire cl lock " << i << endl;
|
||||
CloseHandle(DFCLSuspendMutex);
|
||||
locked = false;
|
||||
DFCLSuspendMutex = 0;
|
||||
CloseHandle(DFCLMutex);
|
||||
DFCLMutex = 0;
|
||||
continue;
|
||||
}
|
||||
// ok, we have all the locks we need!
|
||||
attachmentIdx = i;
|
||||
return true;
|
||||
}
|
||||
CloseHandle(DFSVMutex);
|
||||
DFSVMutex = 0;
|
||||
// cerr << "can't get any client locks" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// is the other side still there?
|
||||
bool SHMProcess::Private::AreLocksOk()
|
||||
{
|
||||
// both locks are inited (we hold our lock)
|
||||
if(DFCLMutex != 0 && DFSVMutex != 0)
|
||||
{
|
||||
// try if CL mutex is free
|
||||
switch (WaitForSingleObject(DFSVMutex,0))
|
||||
{
|
||||
case WAIT_ABANDONED:
|
||||
case WAIT_OBJECT_0:
|
||||
{
|
||||
ReleaseMutex(DFSVMutex);
|
||||
return false;
|
||||
}
|
||||
case WAIT_TIMEOUT:
|
||||
{
|
||||
// mutex is held by DF
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
case WAIT_FAILED:
|
||||
{
|
||||
// TODO: now how do I respond to this?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHMProcess::Private::validate(VersionInfoFactory * factory)
|
||||
{
|
||||
// try to identify the DF version
|
||||
IMAGE_NT_HEADERS pe_header;
|
||||
IMAGE_SECTION_HEADER sections[16];
|
||||
HMODULE hmod = NULL;
|
||||
DWORD junk;
|
||||
HANDLE hProcess;
|
||||
bool found = false;
|
||||
identified = false;
|
||||
// open process, we only need the process open
|
||||
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, process_ID );
|
||||
if (NULL == hProcess)
|
||||
return false;
|
||||
|
||||
// try getting the first module of the process
|
||||
if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0)
|
||||
{
|
||||
CloseHandle(hProcess);
|
||||
// cout << "EnumProcessModules fail'd" << endl;
|
||||
return false;
|
||||
}
|
||||
// got base ;)
|
||||
uint32_t base = (uint32_t)hmod;
|
||||
|
||||
// read from this process
|
||||
uint32_t pe_offset = self->Process::readDWord(base+0x3C);
|
||||
self->read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
|
||||
self->read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)§ions );
|
||||
|
||||
VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(pe_header.FileHeader.TimeDateStamp);
|
||||
if(vinfo)
|
||||
{
|
||||
VersionInfo *m = new VersionInfo(*vinfo);
|
||||
m->RebaseAll(base);
|
||||
memdescriptor = m;
|
||||
m->setParentProcess(self);
|
||||
identified = true;
|
||||
vector_start = memdescriptor->getGroup("vector")->getOffset("start");
|
||||
CloseHandle(hProcess);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHMProcess::getThreadIDs(vector<uint32_t> & threads )
|
||||
{
|
||||
HANDLE AllThreads = INVALID_HANDLE_VALUE;
|
||||
THREADENTRY32 te32;
|
||||
|
||||
AllThreads = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
|
||||
if( AllThreads == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
te32.dwSize = sizeof(THREADENTRY32 );
|
||||
|
||||
if( !Thread32First( AllThreads, &te32 ) )
|
||||
{
|
||||
CloseHandle( AllThreads );
|
||||
return false;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if( te32.th32OwnerProcessID == d->process_ID )
|
||||
{
|
||||
threads.push_back(te32.th32ThreadID);
|
||||
}
|
||||
} while( Thread32Next(AllThreads, &te32 ) );
|
||||
|
||||
CloseHandle( AllThreads );
|
||||
return true;
|
||||
}
|
||||
|
||||
//FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries
|
||||
void SHMProcess::getMemRanges( vector<t_memrange> & ranges )
|
||||
{
|
||||
// BLAH
|
||||
ranges.clear();
|
||||
}
|
||||
|
||||
bool SHMProcess::acquireSuspendLock()
|
||||
{
|
||||
return ( WaitForSingleObject(d->DFCLSuspendMutex,INFINITE) == 0 );
|
||||
}
|
||||
|
||||
bool SHMProcess::releaseSuspendLock()
|
||||
{
|
||||
return ( ReleaseMutex(d->DFCLSuspendMutex) != 0);
|
||||
}
|
||||
|
||||
|
||||
bool SHMProcess::attach()
|
||||
{
|
||||
if(d->attached)
|
||||
{
|
||||
if(!d->locked)
|
||||
return suspend();
|
||||
return true;
|
||||
}
|
||||
//cerr << "attach" << endl;// FIXME: throw
|
||||
if(!d->GetLocks())
|
||||
{
|
||||
//cerr << "server is full or not really there!" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate the segment.
|
||||
*/
|
||||
char shmname [256];
|
||||
sprintf(shmname,"DFShm-%d",d->process_ID);
|
||||
HANDLE shmHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,shmname);
|
||||
if(!shmHandle)
|
||||
{
|
||||
d->FreeLocks();
|
||||
//ReleaseMutex(d->DFCLMutex);
|
||||
return false; // we couldn't lock it
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach the segment
|
||||
*/
|
||||
d->shm_addr = (char *) MapViewOfFile(shmHandle,FILE_MAP_ALL_ACCESS, 0,0, SHM_SIZE);
|
||||
if(!d->shm_addr)
|
||||
{
|
||||
CloseHandle(shmHandle);
|
||||
//ReleaseMutex(d->DFCLMutex);
|
||||
d->FreeLocks();
|
||||
return false; // we couldn't attach the mapping // FIXME: throw
|
||||
}
|
||||
// we close the handle right here - it's not needed anymore
|
||||
CloseHandle(shmHandle);
|
||||
|
||||
d->attached = true;
|
||||
if(!suspend())
|
||||
{
|
||||
UnmapViewOfFile(d->shm_addr);
|
||||
d->FreeLocks();
|
||||
//cerr << "unable to suspend" << endl;// FIXME: throw
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHMProcess::detach()
|
||||
{
|
||||
if(!d->attached) return true;
|
||||
if(d->locked)
|
||||
{
|
||||
resume();
|
||||
}
|
||||
// detach segment
|
||||
UnmapViewOfFile(d->shm_addr);
|
||||
// release it for some other client
|
||||
//ReleaseMutex(d->DFCLMutex); // we keep the mutex handles
|
||||
d->FreeLocks();
|
||||
d->attached = false;
|
||||
d->locked = false;
|
||||
d->shm_addr = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SHMProcess::readSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
read(address + d->vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
void SHMProcess::writeSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
write(address + d->vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
string SHMProcess::doReadClassName (uint32_t vptr)
|
||||
{
|
||||
int rtti = Process::readDWord(vptr - 0x4);
|
||||
int typeinfo = Process::readDWord(rtti + 0xC);
|
||||
string raw = readCString(typeinfo + 0xC); // skips the .?AV
|
||||
raw.resize(raw.length() - 2);// trim @@ from end
|
||||
return raw;
|
||||
}
|
||||
|
||||
string SHMProcess::getPath()
|
||||
{
|
||||
HMODULE hmod;
|
||||
DWORD junk;
|
||||
char String[255];
|
||||
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->process_ID ); //get the handle from the process ID
|
||||
EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle
|
||||
GetModuleFileNameEx(hProcess,hmod,String,sizeof(String)); //get the filename from the module
|
||||
string out(String);
|
||||
return(out.substr(0,out.find_last_of("\\")));
|
||||
}
|
||||
|
||||
char * SHMProcess::getSHMStart (void)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(0xdeadbeef);
|
||||
|
||||
return d->shm_addr;
|
||||
}
|
@ -1,611 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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 "PlatformInternal.h"
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
#include "ProcessFactory.h"
|
||||
#include "MicrosoftSTL.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
using namespace DFHack;
|
||||
|
||||
namespace
|
||||
{
|
||||
class NormalProcess : public Process
|
||||
{
|
||||
private:
|
||||
VersionInfo * my_descriptor;
|
||||
HANDLE my_handle;
|
||||
vector <HANDLE> threads;
|
||||
vector <HANDLE> stoppedthreads;
|
||||
uint32_t my_pid;
|
||||
string memFile;
|
||||
bool attached;
|
||||
bool suspended;
|
||||
bool identified;
|
||||
uint8_t vector_start;
|
||||
IMAGE_NT_HEADERS pe_header;
|
||||
IMAGE_SECTION_HEADER * sections;
|
||||
uint32_t base;
|
||||
MicrosoftSTL stl;
|
||||
public:
|
||||
NormalProcess(uint32_t pid, VersionInfoFactory * factory);
|
||||
~NormalProcess();
|
||||
bool attach();
|
||||
bool detach();
|
||||
|
||||
bool suspend();
|
||||
bool asyncSuspend();
|
||||
bool resume();
|
||||
bool forceresume();
|
||||
|
||||
void readQuad(const uint32_t address, uint64_t & value);
|
||||
void writeQuad(const uint32_t address, const uint64_t value);
|
||||
|
||||
void readDWord(const uint32_t address, uint32_t & value);
|
||||
void writeDWord(const uint32_t address, const uint32_t value);
|
||||
|
||||
void readFloat(const uint32_t address, float & value);
|
||||
|
||||
void readWord(const uint32_t address, uint16_t & value);
|
||||
void writeWord(const uint32_t address, const uint16_t value);
|
||||
|
||||
void readByte(const uint32_t address, uint8_t & value);
|
||||
void writeByte(const uint32_t address, const uint8_t value);
|
||||
|
||||
void read( uint32_t address, uint32_t length, uint8_t* buffer);
|
||||
void write(uint32_t address, uint32_t length, uint8_t* buffer);
|
||||
|
||||
void readSTLVector(const uint32_t address, t_vecTriplet & triplet);
|
||||
void writeSTLVector(const uint32_t address, t_vecTriplet & triplet);
|
||||
const std::string readSTLString (uint32_t offset);
|
||||
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
|
||||
size_t writeSTLString(const uint32_t address, const std::string writeString);
|
||||
// get class name of an object with rtti/type info
|
||||
std::string doReadClassName(uint32_t vptr);
|
||||
|
||||
const std::string readCString (uint32_t offset);
|
||||
|
||||
bool isSuspended();
|
||||
bool isAttached();
|
||||
bool isIdentified();
|
||||
|
||||
bool getThreadIDs(std::vector<uint32_t> & threads );
|
||||
void getMemRanges(std::vector<t_memrange> & ranges );
|
||||
VersionInfo *getDescriptor();
|
||||
int getPID();
|
||||
std::string getPath();
|
||||
// get module index by name and version. bool 1 = error
|
||||
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { OUTPUT=0; return false;};
|
||||
// get the SHM start if available
|
||||
char * getSHMStart (void){return 0;};
|
||||
// set a SHM command and wait for a response
|
||||
bool SetAndWait (uint32_t state){return false;};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Process* DFHack::createNormalProcess(uint32_t pid, VersionInfoFactory * factory)
|
||||
{
|
||||
return new NormalProcess(pid, factory);
|
||||
}
|
||||
|
||||
NormalProcess::NormalProcess(uint32_t pid, VersionInfoFactory * factory)
|
||||
: my_pid(pid)
|
||||
{
|
||||
my_descriptor = NULL;
|
||||
attached = false;
|
||||
suspended = false;
|
||||
base = 0;
|
||||
sections = 0;
|
||||
|
||||
HMODULE hmod = NULL;
|
||||
DWORD needed;
|
||||
bool found = false;
|
||||
|
||||
identified = false;
|
||||
// open process
|
||||
my_handle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, my_pid );
|
||||
if (NULL == my_handle)
|
||||
return;
|
||||
|
||||
// try getting the first module of the process
|
||||
if(EnumProcessModules(my_handle, &hmod, sizeof(hmod), &needed) == 0)
|
||||
{
|
||||
CloseHandle(my_handle);
|
||||
my_handle=0;
|
||||
// cout << "EnumProcessModules fail'd" << endl;
|
||||
return; //if enumprocessModules fails, give up
|
||||
}
|
||||
|
||||
// got base ;)
|
||||
base = (uint32_t)hmod;
|
||||
|
||||
// read from this process
|
||||
try
|
||||
{
|
||||
uint32_t pe_offset = Process::readDWord(base+0x3C);
|
||||
read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
|
||||
const size_t sectionsSize = sizeof(IMAGE_SECTION_HEADER) * pe_header.FileHeader.NumberOfSections;
|
||||
sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize);
|
||||
read(base + pe_offset + sizeof(pe_header), sectionsSize, (uint8_t *)sections);
|
||||
}
|
||||
catch (exception &)
|
||||
{
|
||||
CloseHandle(my_handle);
|
||||
my_handle = 0;
|
||||
return;
|
||||
}
|
||||
//cout << "PE Timestamp: " << hex << pe_header.FileHeader.TimeDateStamp << dec << endl;
|
||||
VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(pe_header.FileHeader.TimeDateStamp);
|
||||
if(vinfo)
|
||||
{
|
||||
/*
|
||||
cout << "Using version " << vinfo->getName() << ". Offsets follow:" << endl;
|
||||
cout << "--------------------------------------------------------------" << endl;
|
||||
cout << vinfo->PrintOffsets();
|
||||
cout << "--------------------------------------------------------------" << endl;
|
||||
*/
|
||||
// only enumerate threads if this is a valid DF process. the enumeration is costly.
|
||||
vector<uint32_t> threads_ids;
|
||||
if(!getThreadIDs( threads_ids ))
|
||||
{
|
||||
// thread enumeration failed.
|
||||
CloseHandle(my_handle);
|
||||
my_handle = 0;
|
||||
return;
|
||||
}
|
||||
identified = true;
|
||||
// give the process a data model and memory layout fixed for the base of first module
|
||||
my_descriptor = new VersionInfo(*vinfo);
|
||||
my_descriptor->RebaseAll(base);
|
||||
// keep track of created memory_info object so we can destroy it later
|
||||
my_descriptor->setParentProcess(this);
|
||||
try
|
||||
{
|
||||
vector_start = my_descriptor->getGroup("vector")->getOffset("start");
|
||||
stl.init(this);
|
||||
}
|
||||
catch (DFHack::Error::UnsetMemoryDefinition &)
|
||||
{
|
||||
CloseHandle(my_handle);
|
||||
my_handle = 0;
|
||||
identified = false;
|
||||
return;
|
||||
}
|
||||
for(size_t i = 0; i < threads_ids.size();i++)
|
||||
{
|
||||
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads_ids[i]);
|
||||
if(hThread)
|
||||
threads.push_back(hThread);
|
||||
else
|
||||
cerr << "Unable to open thread :" << hex << (DWORD) threads_ids[i] << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// close handles of processes that aren't DF
|
||||
//cout << "ABOUT TO FREE HANDLE" << endl;
|
||||
CloseHandle(my_handle);
|
||||
//cout << "FREE'D HANDLE" << endl;
|
||||
my_handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
NormalProcess::~NormalProcess()
|
||||
{
|
||||
if(attached)
|
||||
{
|
||||
detach();
|
||||
}
|
||||
// destroy our rebased copy of the memory descriptor
|
||||
delete my_descriptor;
|
||||
if(my_handle != NULL)
|
||||
{
|
||||
CloseHandle(my_handle);
|
||||
}
|
||||
for(size_t i = 0; i < threads.size(); i++)
|
||||
CloseHandle(threads[i]);
|
||||
if(sections != NULL)
|
||||
free(sections);
|
||||
}
|
||||
|
||||
VersionInfo * NormalProcess::getDescriptor()
|
||||
{
|
||||
return my_descriptor;
|
||||
}
|
||||
|
||||
int NormalProcess::getPID()
|
||||
{
|
||||
return my_pid;
|
||||
}
|
||||
|
||||
bool NormalProcess::isSuspended()
|
||||
{
|
||||
return suspended;
|
||||
}
|
||||
bool NormalProcess::isAttached()
|
||||
{
|
||||
return attached;
|
||||
}
|
||||
|
||||
bool NormalProcess::isIdentified()
|
||||
{
|
||||
return identified;
|
||||
}
|
||||
|
||||
bool NormalProcess::asyncSuspend()
|
||||
{
|
||||
return suspend();
|
||||
}
|
||||
|
||||
bool NormalProcess::suspend()
|
||||
{
|
||||
if(!attached)
|
||||
return false;
|
||||
if(suspended)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
for(size_t i = 0; i < threads.size(); i++)
|
||||
{
|
||||
stoppedthreads.push_back(threads[i]);
|
||||
SuspendThread(threads[i]);
|
||||
}
|
||||
suspended = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NormalProcess::forceresume()
|
||||
{
|
||||
if(!attached)
|
||||
return false;
|
||||
for(size_t i = 0; i < threads.size(); i++)
|
||||
while (ResumeThread(threads[i]) > 1);
|
||||
suspended = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool NormalProcess::resume()
|
||||
{
|
||||
if(!attached)
|
||||
return false;
|
||||
if(!suspended)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
for(size_t i = 0; i < stoppedthreads.size(); i++)
|
||||
ResumeThread(stoppedthreads[i]);
|
||||
stoppedthreads.clear();
|
||||
suspended = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NormalProcess::attach()
|
||||
{
|
||||
if(attached)
|
||||
{
|
||||
if(!suspended)
|
||||
return suspend();
|
||||
return true;
|
||||
}
|
||||
attached = true;
|
||||
suspend();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool NormalProcess::detach()
|
||||
{
|
||||
if(!attached) return true;
|
||||
resume();
|
||||
attached = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NormalProcess::getThreadIDs(vector<uint32_t> & threads )
|
||||
{
|
||||
HANDLE AllThreads = INVALID_HANDLE_VALUE;
|
||||
THREADENTRY32 te32;
|
||||
|
||||
AllThreads = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
|
||||
if( AllThreads == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
te32.dwSize = sizeof(THREADENTRY32 );
|
||||
|
||||
if( !Thread32First( AllThreads, &te32 ) )
|
||||
{
|
||||
CloseHandle( AllThreads );
|
||||
return false;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if( te32.th32OwnerProcessID == my_pid )
|
||||
{
|
||||
threads.push_back(te32.th32ThreadID);
|
||||
}
|
||||
} while( Thread32Next(AllThreads, &te32 ) );
|
||||
|
||||
CloseHandle( AllThreads );
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
typedef struct _MEMORY_BASIC_INFORMATION
|
||||
{
|
||||
void * BaseAddress;
|
||||
void * AllocationBase;
|
||||
uint32_t AllocationProtect;
|
||||
size_t RegionSize;
|
||||
uint32_t State;
|
||||
uint32_t Protect;
|
||||
uint32_t Type;
|
||||
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
|
||||
*/
|
||||
/*
|
||||
//Internal structure used to store heap block information.
|
||||
struct HeapBlock
|
||||
{
|
||||
PVOID dwAddress;
|
||||
DWORD dwSize;
|
||||
DWORD dwFlags;
|
||||
ULONG reserved;
|
||||
};
|
||||
*/
|
||||
void HeapNodes(DWORD pid, map<uint64_t, unsigned int> & heaps)
|
||||
{
|
||||
// Create debug buffer
|
||||
PDEBUG_BUFFER db = RtlCreateQueryDebugBuffer(0, FALSE);
|
||||
// Get process heap data
|
||||
RtlQueryProcessDebugInformation( pid, PDI_HEAPS/* | PDI_HEAP_BLOCKS*/, db);
|
||||
ULONG heapNodeCount = db->HeapInformation ? *PULONG(db->HeapInformation):0;
|
||||
PDEBUG_HEAP_INFORMATION heapInfo = PDEBUG_HEAP_INFORMATION(PULONG(db-> HeapInformation) + 1);
|
||||
// Go through each of the heap nodes and dispaly the information
|
||||
for (unsigned int i = 0; i < heapNodeCount; i++)
|
||||
{
|
||||
heaps[heapInfo[i].Base] = i;
|
||||
}
|
||||
// Clean up the buffer
|
||||
RtlDestroyQueryDebugBuffer( db );
|
||||
}
|
||||
|
||||
// FIXME: NEEDS TESTING!
|
||||
void NormalProcess::getMemRanges( vector<t_memrange> & ranges )
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION MBI;
|
||||
map<uint64_t, unsigned int> heaps;
|
||||
uint64_t movingStart = 0;
|
||||
map <uint64_t, string> nameMap;
|
||||
|
||||
// get page size
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
uint64_t PageSize = si.dwPageSize;
|
||||
// enumerate heaps
|
||||
HeapNodes(my_pid, heaps);
|
||||
// go through all the VM regions, convert them to our internal format
|
||||
while (VirtualQueryEx(this->my_handle, (const void*) (movingStart), &MBI, sizeof(MBI)) == sizeof(MBI))
|
||||
{
|
||||
movingStart = ((uint64_t)MBI.BaseAddress + MBI.RegionSize);
|
||||
if(movingStart % PageSize != 0)
|
||||
movingStart = (movingStart / PageSize + 1) * PageSize;
|
||||
// skip empty regions and regions we share with other processes (DLLs)
|
||||
if( !(MBI.State & MEM_COMMIT) /*|| !(MBI.Type & MEM_PRIVATE)*/ )
|
||||
continue;
|
||||
t_memrange temp;
|
||||
temp.start = (uint64_t) MBI.BaseAddress;
|
||||
temp.end = ((uint64_t)MBI.BaseAddress + (uint64_t)MBI.RegionSize);
|
||||
temp.read = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READONLY || MBI.Protect & PAGE_READWRITE;
|
||||
temp.write = MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READWRITE;
|
||||
temp.execute = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_EXECUTE;
|
||||
temp.valid = true;
|
||||
if(!GetModuleBaseName(this->my_handle, (HMODULE) temp.start, temp.name, 1024))
|
||||
{
|
||||
if(nameMap.count(temp.start))
|
||||
{
|
||||
// potential buffer overflow...
|
||||
strcpy(temp.name, nameMap[temp.start].c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// filter away shared segments without a name.
|
||||
if( !(MBI.Type & MEM_PRIVATE) )
|
||||
continue;
|
||||
else
|
||||
{
|
||||
// could be a heap?
|
||||
if(heaps.count(temp.start))
|
||||
{
|
||||
sprintf(temp.name,"HEAP %d",heaps[temp.start]);
|
||||
}
|
||||
else temp.name[0]=0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is our executable! (could be generalized to pull segments from libs, but whatever)
|
||||
if(base == temp.start)
|
||||
{
|
||||
for(int i = 0; i < pe_header.FileHeader.NumberOfSections; i++)
|
||||
{
|
||||
char sectionName[9];
|
||||
memcpy(sectionName,sections[i].Name,8);
|
||||
sectionName[8] = 0;
|
||||
string nm;
|
||||
nm.append(temp.name);
|
||||
nm.append(" : ");
|
||||
nm.append(sectionName);
|
||||
nameMap[temp.start + sections[i].VirtualAddress] = nm;
|
||||
}
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
ranges.push_back(temp);
|
||||
}
|
||||
}
|
||||
|
||||
void NormalProcess::readByte (const uint32_t offset,uint8_t &result)
|
||||
{
|
||||
if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint8_t), NULL))
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
|
||||
void NormalProcess::readWord (const uint32_t offset, uint16_t &result)
|
||||
{
|
||||
if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint16_t), NULL))
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
|
||||
void NormalProcess::readDWord (const uint32_t offset, uint32_t &result)
|
||||
{
|
||||
if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint32_t), NULL))
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
|
||||
void NormalProcess::readQuad (const uint32_t offset, uint64_t &result)
|
||||
{
|
||||
if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint64_t), NULL))
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
|
||||
void NormalProcess::readFloat (const uint32_t offset, float &result)
|
||||
{
|
||||
if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(float), NULL))
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
|
||||
void NormalProcess::read (const uint32_t offset, uint32_t size, uint8_t *target)
|
||||
{
|
||||
if(!ReadProcessMemory(my_handle, (int*) offset, target, size, NULL))
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
|
||||
// WRITING
|
||||
void NormalProcess::writeQuad (const uint32_t offset, uint64_t data)
|
||||
{
|
||||
if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL))
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
|
||||
void NormalProcess::writeDWord (const uint32_t offset, uint32_t data)
|
||||
{
|
||||
if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL))
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
|
||||
// using these is expensive.
|
||||
void NormalProcess::writeWord (uint32_t offset, uint16_t data)
|
||||
{
|
||||
if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL))
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
|
||||
void NormalProcess::writeByte (uint32_t offset, uint8_t data)
|
||||
{
|
||||
if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL))
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
|
||||
void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source)
|
||||
{
|
||||
if(!WriteProcessMemory(my_handle, (int*) offset, source, size, NULL))
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
|
||||
// FIXME: could exploit the fact we can read more than one byte... but still, this is almost unused.
|
||||
const std::string NormalProcess::readCString (const uint32_t offset)
|
||||
{
|
||||
std::string temp;
|
||||
int counter = 0;
|
||||
char r;
|
||||
while (1)
|
||||
{
|
||||
if(!ReadProcessMemory(my_handle, (int*) (offset + counter), &r, sizeof(uint8_t), NULL)) break;
|
||||
r = Process::readByte(offset+counter);
|
||||
// order is important. even if the first character is \0, we cound that as a success. It's an empty string.
|
||||
counter++;
|
||||
if(!r) break;
|
||||
temp.append(1,r);
|
||||
}
|
||||
if(!counter)
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
return temp;
|
||||
}
|
||||
|
||||
void NormalProcess::readSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
read(address + vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
void NormalProcess::writeSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
write(address + vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
|
||||
{
|
||||
return stl.readSTLString(offset, buffer, bufcapacity);
|
||||
}
|
||||
|
||||
const string NormalProcess::readSTLString (uint32_t offset)
|
||||
{
|
||||
return stl.readSTLString(offset);
|
||||
}
|
||||
|
||||
size_t NormalProcess::writeSTLString (uint32_t address, string str)
|
||||
{
|
||||
return stl.writeSTLString(address, str);
|
||||
}
|
||||
|
||||
string NormalProcess::doReadClassName (uint32_t vptr)
|
||||
{
|
||||
return stl.readClassName(vptr);
|
||||
}
|
||||
|
||||
string NormalProcess::getPath()
|
||||
{
|
||||
HMODULE hmod;
|
||||
DWORD junk;
|
||||
char String[255];
|
||||
EnumProcessModules(my_handle, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle
|
||||
GetModuleFileNameEx(my_handle,hmod,String,sizeof(String)); //get the filename from the module
|
||||
string out(String);
|
||||
return(out.substr(0,out.find_last_of("\\")));
|
||||
}
|
@ -1,391 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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 "PlatformInternal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
using namespace std;
|
||||
|
||||
#include "ProcessFactory.h"
|
||||
|
||||
#include "dfhack/VersionInfoFactory.h"
|
||||
#include "dfhack/DFProcessEnumerator.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
|
||||
|
||||
using namespace DFHack;
|
||||
|
||||
typedef std::vector<Process *> PROC_V;
|
||||
typedef std::map<ProcessID, Process*> PID2PROC;
|
||||
|
||||
class DFHack::ProcessEnumerator::Private
|
||||
{
|
||||
public:
|
||||
Private(){};
|
||||
VersionInfoFactory *meminfo;
|
||||
PROC_V Processes;
|
||||
PID2PROC ProcMap;
|
||||
Process *GetProcessObject(ProcessID ID);
|
||||
void EnumPIDs (vector <ProcessID> &PIDs);
|
||||
};
|
||||
|
||||
class DFHack::BadProcesses::Private
|
||||
{
|
||||
public:
|
||||
Private(){};
|
||||
PROC_V bad;
|
||||
};
|
||||
|
||||
BadProcesses::BadProcesses():d(new Private()){}
|
||||
|
||||
BadProcesses::~BadProcesses()
|
||||
{
|
||||
clear();
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool BadProcesses::Contains(Process* p)
|
||||
{
|
||||
for(unsigned int i = 0; i < d->bad.size(); i++)
|
||||
{
|
||||
if(d->bad[i] == p)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BadProcesses::excise(Process* p)
|
||||
{
|
||||
vector<Process*>::iterator it = d->bad.begin();
|
||||
while(it != d->bad.end())
|
||||
{
|
||||
if((*it) == p)
|
||||
{
|
||||
d->bad.erase(it);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t BadProcesses::size()
|
||||
{
|
||||
return d->bad.size();
|
||||
}
|
||||
|
||||
void BadProcesses::clear()
|
||||
{
|
||||
for(unsigned int i = 0; i < d->bad.size(); i++)
|
||||
{
|
||||
delete d->bad[i];
|
||||
}
|
||||
d->bad.clear();
|
||||
}
|
||||
|
||||
void BadProcesses::push_back(Process* p)
|
||||
{
|
||||
if(p)
|
||||
d->bad.push_back(p);
|
||||
}
|
||||
|
||||
Process * BadProcesses::operator[](uint32_t index)
|
||||
{
|
||||
if(index < d->bad.size())
|
||||
return d->bad[index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
//FIXME: wasteful
|
||||
Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID)
|
||||
{
|
||||
Process *p2 = createNormalProcess(ID.pid, meminfo);
|
||||
if(p2->isIdentified())
|
||||
{
|
||||
return p2;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete p2;
|
||||
}
|
||||
#ifdef LINUX_BUILD
|
||||
Process *p3 = createWineProcess(ID.pid, meminfo);
|
||||
if(p3->isIdentified())
|
||||
return p3;
|
||||
else
|
||||
delete p3;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LINUX_BUILD
|
||||
void ProcessEnumerator::Private::EnumPIDs (vector <ProcessID> &PIDs)
|
||||
{
|
||||
DIR *dir_p;
|
||||
struct dirent *dir_entry_p;
|
||||
struct stat st;
|
||||
char fullname[512];
|
||||
fullname[0] = 0;
|
||||
PIDs.clear(); // make sure the vector is clear
|
||||
|
||||
// Open /proc/ directory
|
||||
dir_p = opendir("/proc/");
|
||||
// Reading /proc/ entries
|
||||
while(NULL != (dir_entry_p = readdir(dir_p)))
|
||||
{
|
||||
// Only PID folders (numbers)
|
||||
if (strspn(dir_entry_p->d_name, "0123456789") != strlen(dir_entry_p->d_name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sprintf(fullname, "/proc/%s", dir_entry_p->d_name);
|
||||
int ierr = stat (fullname, &st);
|
||||
if (ierr != 0)
|
||||
{
|
||||
printf("Cannot stat %s: ierr= %d\n", fullname, ierr);
|
||||
continue;
|
||||
}
|
||||
uint64_t Pnum = atoi(dir_entry_p->d_name);
|
||||
uint64_t ctime = st.st_ctime;
|
||||
PIDs.push_back(ProcessID(ctime,Pnum));
|
||||
}
|
||||
closedir(dir_p);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LINUX_BUILD
|
||||
// some magic - will come in handy when we start doing debugger stuff on Windows
|
||||
bool EnableDebugPriv()
|
||||
{
|
||||
bool bRET = FALSE;
|
||||
TOKEN_PRIVILEGES tp;
|
||||
HANDLE hToken;
|
||||
|
||||
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid))
|
||||
{
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
|
||||
{
|
||||
if (hToken != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
tp.PrivilegeCount = 1;
|
||||
if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, 0, 0))
|
||||
{
|
||||
bRET = TRUE;
|
||||
}
|
||||
CloseHandle(hToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bRET;
|
||||
}
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t LowDword;
|
||||
uint32_t HighDword;
|
||||
};
|
||||
uint64_t Quad;
|
||||
} TWO_DWORDS;
|
||||
|
||||
// Convert Windows FileTime structs to POSIX timestamp
|
||||
// from http://frenk.wordpress.com/2009/12/14/convert-filetime-to-unix-timestamp/
|
||||
uint64_t FileTime_to_POSIX(FILETIME ft)
|
||||
{
|
||||
// takes the last modified date
|
||||
TWO_DWORDS date, adjust;
|
||||
date.HighDword = ft.dwHighDateTime;
|
||||
date.LowDword = ft.dwLowDateTime;
|
||||
|
||||
// 100-nanoseconds = milliseconds * 10000
|
||||
adjust.Quad = 11644473600000LL * 10000LL;
|
||||
|
||||
// removes the diff between 1970 and 1601
|
||||
date.Quad -= adjust.Quad;
|
||||
|
||||
// converts back from 100-nanoseconds to seconds
|
||||
return date.Quad / 10000000LL;
|
||||
}
|
||||
|
||||
void ProcessEnumerator::Private::EnumPIDs (vector <ProcessID> &PIDs)
|
||||
{
|
||||
FILETIME ftCreate, ftExit, ftKernel, ftUser;
|
||||
|
||||
PIDs.clear(); // make sure the vector is clear
|
||||
|
||||
// Get the list of process identifiers.
|
||||
DWORD ProcArray[2048], memoryNeeded, numProccesses;
|
||||
if(!EnableDebugPriv())
|
||||
{
|
||||
cerr << "Failed to acquire debug privileges." << endl;
|
||||
}
|
||||
if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) )
|
||||
{
|
||||
cerr << "EnumProcesses fail'd" << endl;
|
||||
return;
|
||||
}
|
||||
// Calculate how many process identifiers were returned.
|
||||
numProccesses = memoryNeeded / sizeof(DWORD);
|
||||
//EnableDebugPriv();
|
||||
// iterate through processes
|
||||
for ( int i = 0; i < (int)numProccesses; i++ )
|
||||
{
|
||||
HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION, false, ProcArray[i]);
|
||||
if(!proc)
|
||||
continue;
|
||||
if(GetProcessTimes(proc, &ftCreate, &ftExit, &ftKernel, &ftUser))
|
||||
{
|
||||
uint64_t ctime = FileTime_to_POSIX(ftCreate);
|
||||
uint64_t Pnum = ProcArray[i];
|
||||
PIDs.push_back(ProcessID(ctime,Pnum));
|
||||
}
|
||||
CloseHandle(proc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ProcessEnumerator::Refresh( BadProcesses* invalidated_processes )
|
||||
{
|
||||
// PIDs to process
|
||||
vector <ProcessID> PIDs;
|
||||
// this will be the new process map
|
||||
PID2PROC temporary;
|
||||
// clear the vector
|
||||
d->Processes.clear();
|
||||
if(invalidated_processes)
|
||||
invalidated_processes->clear();
|
||||
|
||||
d->EnumPIDs(PIDs);
|
||||
|
||||
for(uint64_t i = 0; i < PIDs.size();i++)
|
||||
{
|
||||
ProcessID & PID = PIDs[i];
|
||||
// check if we know about the OS process already
|
||||
PID2PROC::iterator found= d->ProcMap.find(PID);
|
||||
if( found != d->ProcMap.end())
|
||||
{
|
||||
// we do
|
||||
// check if it does have a DFHack Process object associated with it
|
||||
Process * p = (*found).second;
|
||||
if(p)
|
||||
{
|
||||
// add it back to the vector we export
|
||||
d->Processes.push_back(p);
|
||||
}
|
||||
// remove the OS Process from ProcMap
|
||||
d->ProcMap.erase(found);
|
||||
// add the OS Process to what will be the new ProcMap
|
||||
temporary[PID] = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
// an OS process we don't know yet!
|
||||
// try to make a DFHack Process object for it
|
||||
if(Process*p = d->GetProcessObject(PID))
|
||||
{
|
||||
// allright. this is something that can be used
|
||||
d->Processes.push_back(p);
|
||||
temporary[PID] = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
// just a process. we track it anyway. Why not.
|
||||
temporary[PID] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// now the vector we export is filled again and a temporary map with valid processes is created.
|
||||
// we iterate over the old Process map and destroy all the processes that are dead.
|
||||
for(PID2PROC::const_iterator idx = d->ProcMap.begin(); idx != d->ProcMap.end();++idx)
|
||||
{
|
||||
Process * p = (*idx).second;
|
||||
if(p)
|
||||
{
|
||||
if(invalidated_processes)
|
||||
{
|
||||
invalidated_processes->push_back(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
}
|
||||
d->ProcMap.swap(temporary);
|
||||
// return value depends on if we found some DF processes
|
||||
if(d->Processes.size())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t ProcessEnumerator::size()
|
||||
{
|
||||
return d->Processes.size();
|
||||
}
|
||||
|
||||
|
||||
Process * ProcessEnumerator::operator[](uint32_t index)
|
||||
{
|
||||
assert(index < d->Processes.size());
|
||||
return d->Processes[index];
|
||||
}
|
||||
|
||||
|
||||
ProcessEnumerator::ProcessEnumerator( string path_to_xml )
|
||||
: d(new Private())
|
||||
{
|
||||
d->meminfo = new VersionInfoFactory(path_to_xml);
|
||||
}
|
||||
|
||||
void ProcessEnumerator::purge()
|
||||
{
|
||||
for(uint32_t i = 0;i < d->Processes.size();i++)
|
||||
{
|
||||
delete d->Processes[i];
|
||||
}
|
||||
d->ProcMap.clear();
|
||||
d->Processes.clear();
|
||||
}
|
||||
|
||||
ProcessEnumerator::~ProcessEnumerator()
|
||||
{
|
||||
// delete all processes
|
||||
purge();
|
||||
delete d->meminfo;
|
||||
delete d;
|
||||
}
|
@ -1,326 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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 <vector>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "dfhack/DFIntegers.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
#include "dfhack-c/DFProcess_C.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PTR_CHECK if(p_Ptr == NULL) return -1;
|
||||
|
||||
int C_ProcessID_Compare(c_processID* left, c_processID* right)
|
||||
{
|
||||
if(left == NULL || right == NULL)
|
||||
return PROCESSID_C_NULL;
|
||||
else
|
||||
{
|
||||
if(left->time == right->time && left->pid == right->pid)
|
||||
return PROCESSID_C_EQ;
|
||||
else if(left->time < right->time || left->pid < right->pid)
|
||||
return PROCESSID_C_LT;
|
||||
else
|
||||
return PROCESSID_C_GT;
|
||||
}
|
||||
}
|
||||
|
||||
#define FUNCTION_FORWARD(func_name) \
|
||||
int Process_##func_name (DFHackObject* p_Ptr) \
|
||||
{ \
|
||||
if(p_Ptr == NULL) \
|
||||
return -1; \
|
||||
if(((DFHack::Process*)p_Ptr)->func_name()) \
|
||||
return 1; \
|
||||
else \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
FUNCTION_FORWARD(attach)
|
||||
FUNCTION_FORWARD(detach)
|
||||
FUNCTION_FORWARD(suspend)
|
||||
FUNCTION_FORWARD(asyncSuspend)
|
||||
FUNCTION_FORWARD(resume)
|
||||
FUNCTION_FORWARD(forceresume)
|
||||
FUNCTION_FORWARD(isSuspended)
|
||||
FUNCTION_FORWARD(isAttached)
|
||||
FUNCTION_FORWARD(isIdentified)
|
||||
FUNCTION_FORWARD(isSnapshot)
|
||||
|
||||
#define MEMREAD_FUNC_FORWARD(func_name, type) \
|
||||
int Process_##func_name(DFHackObject* p_Ptr, uint32_t address, type* value) \
|
||||
{ \
|
||||
PTR_CHECK \
|
||||
((DFHack::Process*)p_Ptr)->func_name(address, *value); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define MEMWRITE_FUNC_FORWARD(func_name, type) \
|
||||
int Process_##func_name(DFHackObject* p_Ptr, uint32_t address, type value) \
|
||||
{ \
|
||||
PTR_CHECK \
|
||||
((DFHack::Process*)p_Ptr)->func_name(address, value); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
MEMREAD_FUNC_FORWARD(readQuad, uint64_t)
|
||||
MEMWRITE_FUNC_FORWARD(writeQuad, uint64_t)
|
||||
|
||||
MEMREAD_FUNC_FORWARD(readDWord, uint32_t)
|
||||
MEMWRITE_FUNC_FORWARD(writeDWord, uint32_t)
|
||||
|
||||
MEMREAD_FUNC_FORWARD(readWord, uint16_t)
|
||||
MEMWRITE_FUNC_FORWARD(writeWord, uint16_t)
|
||||
|
||||
MEMREAD_FUNC_FORWARD(readFloat, float)
|
||||
|
||||
MEMREAD_FUNC_FORWARD(readByte, uint8_t)
|
||||
MEMWRITE_FUNC_FORWARD(writeByte, uint8_t)
|
||||
|
||||
MEMREAD_FUNC_FORWARD(readSTLVector, t_vecTriplet);
|
||||
|
||||
uint8_t* Process_read(DFHackObject* p_Ptr, uint32_t address, uint32_t length)
|
||||
{
|
||||
if(p_Ptr == NULL || alloc_ubyte_buffer_callback == NULL)
|
||||
return NULL;
|
||||
|
||||
uint8_t* buf;
|
||||
|
||||
((*alloc_ubyte_buffer_callback)(&buf, length));
|
||||
|
||||
if(buf == NULL)
|
||||
return NULL;
|
||||
|
||||
((DFHack::Process*)p_Ptr)->read(address, length, buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void Process_write(DFHackObject* p_Ptr, uint32_t address, uint32_t length, uint8_t* buffer)
|
||||
{
|
||||
if(p_Ptr == NULL || buffer == NULL)
|
||||
return;
|
||||
|
||||
((DFHack::Process*)p_Ptr)->write(address, length, buffer);
|
||||
}
|
||||
|
||||
const char* Process_readString(DFHackObject* p_Ptr, uint32_t offset)
|
||||
{
|
||||
if(p_Ptr == NULL || alloc_char_buffer_callback == NULL)
|
||||
return NULL;
|
||||
|
||||
std::string pString = ((DFHack::Process*)p_Ptr)->readSTLString(offset);
|
||||
|
||||
if(pString.length() > 0)
|
||||
{
|
||||
size_t length = pString.length();
|
||||
|
||||
char* buf;
|
||||
|
||||
//add 1 for the null terminator
|
||||
((*alloc_char_buffer_callback)(&buf, length + 1));
|
||||
|
||||
if(buf == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(buf, '\n', length + 1);
|
||||
|
||||
pString.copy(buf, length);
|
||||
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
const char* Process_getPath(DFHackObject* p_Ptr)
|
||||
{
|
||||
if(p_Ptr == NULL || alloc_char_buffer_callback == NULL)
|
||||
return NULL;
|
||||
|
||||
std::string pString = ((DFHack::Process*)p_Ptr)->getPath();
|
||||
|
||||
if(pString.length() > 0)
|
||||
{
|
||||
size_t length = pString.length();
|
||||
|
||||
char* buf;
|
||||
|
||||
//add 1 for the null terminator
|
||||
((*alloc_char_buffer_callback)(&buf, length + 1));
|
||||
|
||||
if(buf == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(buf, '\0', length + 1);
|
||||
|
||||
pString.copy(buf, length);
|
||||
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
const char* Process_readClassName(DFHackObject* p_Ptr, uint32_t vptr)
|
||||
{
|
||||
if(p_Ptr == NULL || alloc_char_buffer_callback == NULL)
|
||||
return NULL;
|
||||
|
||||
std::string cString = ((DFHack::Process*)p_Ptr)->readClassName(vptr);
|
||||
|
||||
if(cString.length() > 0)
|
||||
{
|
||||
size_t length = cString.length();
|
||||
|
||||
char* buf;
|
||||
|
||||
//add 1 for the null terminator
|
||||
((*alloc_char_buffer_callback)(&buf, length + 1));
|
||||
|
||||
if(buf == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(buf, '\0', length + 1);
|
||||
|
||||
cString.copy(buf, length);
|
||||
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
uint32_t* Process_getThreadIDs(DFHackObject* p_Ptr)
|
||||
{
|
||||
if(p_Ptr == NULL || alloc_uint_buffer_callback == NULL)
|
||||
return NULL;
|
||||
|
||||
std::vector<uint32_t> threads;
|
||||
|
||||
if(((DFHack::Process*)p_Ptr)->getThreadIDs(threads))
|
||||
{
|
||||
uint32_t* buf;
|
||||
if(threads.size() > 0)
|
||||
{
|
||||
((*alloc_uint_buffer_callback)(&buf, threads.size()));
|
||||
if(buf == NULL)
|
||||
return NULL;
|
||||
copy(threads.begin(), threads.end(), buf);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t_memrange* Process_getMemRanges(DFHackObject* p_Ptr)
|
||||
{
|
||||
if(p_Ptr == NULL || alloc_memrange_buffer_callback == NULL)
|
||||
return NULL;
|
||||
|
||||
std::vector<t_memrange> ranges;
|
||||
|
||||
((DFHack::Process*)p_Ptr)->getMemRanges(ranges);
|
||||
|
||||
if(ranges.size() > 0)
|
||||
{
|
||||
t_memrange* buf;
|
||||
uint32_t* rangeDescriptorBuf = (uint32_t*)calloc(ranges.size(), sizeof(uint32_t));
|
||||
|
||||
for(uint32_t i = 0; i < ranges.size(); i++)
|
||||
{
|
||||
t_memrange* r = &ranges[i];
|
||||
rangeDescriptorBuf[i] = (uint32_t)(r->end - r->start);
|
||||
}
|
||||
|
||||
((*alloc_memrange_buffer_callback)(&buf, rangeDescriptorBuf, ranges.size()));
|
||||
free(rangeDescriptorBuf);
|
||||
if(buf == NULL)
|
||||
return NULL;
|
||||
|
||||
for(uint32_t i = 0; i < ranges.size(); i++)
|
||||
{
|
||||
t_memrange* r = &ranges[i];
|
||||
buf[i].start = r->start;
|
||||
buf[i].end = r->end;
|
||||
memset(buf[i].name, '\0', 1024);
|
||||
strncpy(buf[i].name, r->name, 1024);
|
||||
buf[i].read = r->read;
|
||||
buf[i].write = r->write;
|
||||
buf[i].execute = r->execute;
|
||||
buf[i].shared = r->shared;
|
||||
buf[i].valid = r->valid;
|
||||
memcpy(buf[i].buffer, r->buffer, r->end - r->start);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int Process_getPID(DFHackObject* p_Ptr, int32_t* pid)
|
||||
{
|
||||
if(p_Ptr == NULL)
|
||||
{
|
||||
*pid = -1;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pid = ((DFHack::Process*)p_Ptr)->getPID();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int Process_getModuleIndex(DFHackObject* p_Ptr, char* name, uint32_t version, uint32_t* output)
|
||||
{
|
||||
PTR_CHECK
|
||||
|
||||
if(((DFHack::Process*)p_Ptr)->getModuleIndex(name, version, *output))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process_SetAndWait(DFHackObject* p_Ptr, uint32_t state)
|
||||
{
|
||||
PTR_CHECK
|
||||
|
||||
if(((DFHack::Process*)p_Ptr)->SetAndWait(state))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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 "dfhack/DFTileTypes.h"
|
||||
#include "dfhack-c/DFTileTypes_C.h"
|
||||
|
||||
int DFHack_isWallTerrain(int in)
|
||||
{
|
||||
return DFHack::isWallTerrain(in);
|
||||
}
|
||||
|
||||
int DFHack_isFloorTerrain(int in)
|
||||
{
|
||||
return DFHack::isFloorTerrain(in);
|
||||
}
|
||||
|
||||
int DFHack_isRampTerrain(int in)
|
||||
{
|
||||
return DFHack::isRampTerrain(in);
|
||||
}
|
||||
|
||||
int DFHack_isStairTerrain(int in)
|
||||
{
|
||||
return DFHack::isStairTerrain(in);
|
||||
}
|
||||
|
||||
int DFHack_isOpenTerrain(int in)
|
||||
{
|
||||
return DFHack::isOpenTerrain(in);
|
||||
}
|
||||
|
||||
int DFHack_getVegetationType(int in)
|
||||
{
|
||||
return DFHack::tileShape(in);
|
||||
}
|
||||
|
||||
int DFHack_getTileType(int index, TileRow* tPtr)
|
||||
{
|
||||
if(index >= TILE_TYPE_ARRAY_LENGTH)
|
||||
return 0;
|
||||
|
||||
*tPtr = tileTypeTable[index];
|
||||
return 1;
|
||||
}
|
@ -1,173 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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 <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
#include "dfhack/modules/Materials.h"
|
||||
using namespace DFHack;
|
||||
|
||||
/*
|
||||
I believe this is what they call "the bad kind of clever", but writing out registration functions for each callback just feels *so* wrong...
|
||||
|
||||
The output of this macro is something like this...
|
||||
|
||||
void RegisterByteBufferCallback(int(*fptr)(int8_t*, uint32_t))
|
||||
{
|
||||
alloc_byte_buffer_callback = fptr;
|
||||
}
|
||||
|
||||
*/
|
||||
#define BUILD(a) a ## BufferCallback
|
||||
#define REG_MACRO(type_name, type, callback) void BUILD(Register ## type_name) (int (*fptr)(type, uint32_t)) { callback = fptr; }
|
||||
|
||||
/*
|
||||
The output of this macro is something like this...
|
||||
|
||||
void UnregisterByteBufferCallback()
|
||||
{
|
||||
alloc_byte_buffer_callback = NULL;
|
||||
}
|
||||
|
||||
*/
|
||||
#define UNREG_MACRO(type_name, callback) void BUILD(Unregister ## type_name) () { callback = NULL; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int (*alloc_byte_buffer_callback)(int8_t**, uint32_t) = NULL;
|
||||
int (*alloc_short_buffer_callback)(int16_t**, uint32_t) = NULL;
|
||||
int (*alloc_int_buffer_callback)(int32_t**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_ubyte_buffer_callback)(uint8_t**, uint32_t) = NULL;
|
||||
int (*alloc_ushort_buffer_callback)(uint16_t**, uint32_t) = NULL;
|
||||
int (*alloc_uint_buffer_callback)(uint32_t**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_char_buffer_callback)(char**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_matgloss_buffer_callback)(t_matgloss**, uint32_t) = NULL;
|
||||
int (*alloc_descriptor_buffer_callback)(t_descriptor_color**, uint32_t) = NULL;
|
||||
int (*alloc_matgloss_other_buffer_callback)(t_matglossOther**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_feature_buffer_callback)(t_feature**, uint32_t) = NULL;
|
||||
int (*alloc_hotkey_buffer_callback)(t_hotkey**, uint32_t) = NULL;
|
||||
int (*alloc_screen_buffer_callback)(t_screen**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_tree_buffer_callback)(dfh_plant**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_memrange_buffer_callback)(t_memrange**, uint32_t*, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_customWorkshop_buffer_callback)(t_customWorkshop**, uint32_t) = NULL;
|
||||
int (*alloc_material_buffer_callback)(t_material**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_creaturetype_buffer_callback)(c_creaturetype**, c_creaturetype_descriptor*, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_vein_buffer_callback)(t_vein**, uint32_t) = NULL;
|
||||
int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein**, uint32_t) = NULL;
|
||||
int (*alloc_spattervein_buffer_callback)(t_spattervein**, uint32_t) = NULL;
|
||||
int (*alloc_grassvein_buffer_callback)(t_grassvein**, uint32_t) = NULL;
|
||||
int (*alloc_worldconstruction_buffer_callback)(t_worldconstruction**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_featuremap_buffer_callback)(c_featuremap_node**, uint32_t*, uint32_t) = NULL;
|
||||
|
||||
//int (*alloc_bodypart_buffer_callback)(t_bodypart**, uint32_t) = NULL;
|
||||
REG_MACRO(Byte, int8_t**, alloc_byte_buffer_callback)
|
||||
REG_MACRO(Short, int16_t**, alloc_short_buffer_callback)
|
||||
REG_MACRO(Int, int32_t**, alloc_int_buffer_callback)
|
||||
REG_MACRO(UByte, uint8_t**, alloc_ubyte_buffer_callback)
|
||||
REG_MACRO(UShort, uint16_t**, alloc_ushort_buffer_callback)
|
||||
REG_MACRO(UInt, uint32_t**, alloc_uint_buffer_callback)
|
||||
REG_MACRO(Char, char**, alloc_char_buffer_callback)
|
||||
REG_MACRO(Matgloss, t_matgloss**, alloc_matgloss_buffer_callback)
|
||||
REG_MACRO(DescriptorColor, t_descriptor_color**, alloc_descriptor_buffer_callback)
|
||||
REG_MACRO(MatglossOther, t_matglossOther**, alloc_matgloss_other_buffer_callback)
|
||||
REG_MACRO(Feature, t_feature**, alloc_feature_buffer_callback)
|
||||
REG_MACRO(Hotkey, t_hotkey**, alloc_hotkey_buffer_callback)
|
||||
REG_MACRO(Screen, t_screen**, alloc_screen_buffer_callback)
|
||||
REG_MACRO(Tree, dfh_plant**, alloc_tree_buffer_callback)
|
||||
REG_MACRO(CustomWorkshop, t_customWorkshop**, alloc_customWorkshop_buffer_callback)
|
||||
REG_MACRO(Material, t_material**, alloc_material_buffer_callback)
|
||||
|
||||
void RegisterMemRangeBufferCallback(int (*funcptr)(t_memrange**, uint32_t*, uint32_t))
|
||||
{
|
||||
alloc_memrange_buffer_callback = funcptr;
|
||||
}
|
||||
|
||||
UNREG_MACRO(Byte, alloc_byte_buffer_callback)
|
||||
UNREG_MACRO(Short, alloc_short_buffer_callback)
|
||||
UNREG_MACRO(Int, alloc_int_buffer_callback)
|
||||
UNREG_MACRO(UByte, alloc_ubyte_buffer_callback)
|
||||
UNREG_MACRO(UShort, alloc_ushort_buffer_callback)
|
||||
UNREG_MACRO(UInt, alloc_uint_buffer_callback)
|
||||
UNREG_MACRO(Char, alloc_char_buffer_callback)
|
||||
UNREG_MACRO(Matgloss, alloc_matgloss_buffer_callback)
|
||||
UNREG_MACRO(DescriptorColor, alloc_descriptor_buffer_callback)
|
||||
UNREG_MACRO(MatglossOther, alloc_matgloss_other_buffer_callback)
|
||||
UNREG_MACRO(Feature, alloc_feature_buffer_callback)
|
||||
UNREG_MACRO(Hotkey, alloc_hotkey_buffer_callback)
|
||||
UNREG_MACRO(Screen, alloc_screen_buffer_callback)
|
||||
UNREG_MACRO(Tree, alloc_tree_buffer_callback)
|
||||
UNREG_MACRO(MemRange, alloc_memrange_buffer_callback)
|
||||
UNREG_MACRO(CustomWorkshop, alloc_customWorkshop_buffer_callback)
|
||||
UNREG_MACRO(Material, alloc_material_buffer_callback)
|
||||
|
||||
void RegisterCreatureTypeBufferCallback(int (*funcptr)(c_creaturetype**, c_creaturetype_descriptor*, uint32_t))
|
||||
{
|
||||
alloc_creaturetype_buffer_callback = funcptr;
|
||||
}
|
||||
|
||||
UNREG_MACRO(CreatureType, alloc_creaturetype_buffer_callback)
|
||||
|
||||
REG_MACRO(Vein, t_vein**, alloc_vein_buffer_callback)
|
||||
REG_MACRO(FrozenLiquidVein, t_frozenliquidvein**, alloc_frozenliquidvein_buffer_callback)
|
||||
REG_MACRO(SpatterVein, t_spattervein**, alloc_spattervein_buffer_callback)
|
||||
REG_MACRO(GrassVein, t_grassvein**, alloc_grassvein_buffer_callback)
|
||||
REG_MACRO(WorldConstruction, t_worldconstruction**, alloc_worldconstruction_buffer_callback)
|
||||
|
||||
UNREG_MACRO(Vein, alloc_vein_buffer_callback)
|
||||
UNREG_MACRO(FrozenLiquidVein, alloc_frozenliquidvein_buffer_callback)
|
||||
UNREG_MACRO(SpatterVein, alloc_spattervein_buffer_callback)
|
||||
UNREG_MACRO(GrassVein, alloc_grassvein_buffer_callback)
|
||||
UNREG_MACRO(WorldConstruction, alloc_worldconstruction_buffer_callback)
|
||||
|
||||
void RegisterFeatureMapBufferCallback(int (*funcptr)(c_featuremap_node**, uint32_t*, uint32_t))
|
||||
{
|
||||
alloc_featuremap_buffer_callback = funcptr;
|
||||
}
|
||||
|
||||
UNREG_MACRO(FeatureMap, alloc_featuremap_buffer_callback)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,247 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
#include "DFHack.h"
|
||||
#include "dfhack/Core.h"
|
||||
#include "dfhack/FakeSDL.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);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SDL part starts here *
|
||||
*******************************************************************************/
|
||||
bool FirstCall(void);
|
||||
bool inited = false;
|
||||
|
||||
DFhackCExport int SDL_NumJoysticks(void)
|
||||
{
|
||||
DFHack::Core & c = DFHack::Core::getInstance();
|
||||
// the 'inited' variable should be normally protected by a lock. It isn't
|
||||
// this is harmless enough. only thing this can cause is a slight delay before
|
||||
// DF input events start to be processed by Core
|
||||
int ret = c.Update();
|
||||
if(ret == 0)
|
||||
inited = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ptr to the real functions
|
||||
//static void (*_SDL_GL_SwapBuffers)(void) = 0;
|
||||
static void (*_SDL_Quit)(void) = 0;
|
||||
static int (*_SDL_Init)(uint32_t flags) = 0;
|
||||
static SDL::Thread * (*_SDL_CreateThread)(int (*fn)(void *), void *data) = 0;
|
||||
//static int (*_SDL_Flip)(void * some_ptr) = 0;
|
||||
/*
|
||||
// hook - called every tick in OpenGL mode of DF
|
||||
DFhackCExport void SDL_GL_SwapBuffers(void)
|
||||
{
|
||||
if(_SDL_GL_SwapBuffers)
|
||||
{
|
||||
if(!errorstate)
|
||||
{
|
||||
SHM_Act();
|
||||
}
|
||||
counter ++;
|
||||
_SDL_GL_SwapBuffers();
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
// hook - called every tick in the 2D mode of DF
|
||||
DFhackCExport int SDL_Flip(void * some_ptr)
|
||||
{
|
||||
if(_SDL_Flip)
|
||||
{
|
||||
if(!errorstate)
|
||||
{
|
||||
SHM_Act();
|
||||
}
|
||||
counter ++;
|
||||
return _SDL_Flip(some_ptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
static SDL::Mutex * (*_SDL_CreateMutex)(void) = 0;
|
||||
DFhackCExport SDL::Mutex * SDL_CreateMutex(void)
|
||||
{
|
||||
return _SDL_CreateMutex();
|
||||
}
|
||||
|
||||
static int (*_SDL_mutexP)(SDL::Mutex * mutex) = 0;
|
||||
DFhackCExport int SDL_mutexP(SDL::Mutex * mutex)
|
||||
{
|
||||
return _SDL_mutexP(mutex);
|
||||
}
|
||||
|
||||
static int (*_SDL_mutexV)(SDL::Mutex * mutex) = 0;
|
||||
DFhackCExport int SDL_mutexV(SDL::Mutex * mutex)
|
||||
{
|
||||
return _SDL_mutexV(mutex);
|
||||
}
|
||||
|
||||
static void (*_SDL_DestroyMutex)(SDL::Mutex * mutex) = 0;
|
||||
DFhackCExport void SDL_DestroyMutex(SDL::Mutex * mutex)
|
||||
{
|
||||
_SDL_DestroyMutex(mutex);
|
||||
}
|
||||
|
||||
// hook - called at program exit
|
||||
DFhackCExport void SDL_Quit(void)
|
||||
{
|
||||
DFHack::Core & c = DFHack::Core::getInstance();
|
||||
c.Shutdown();
|
||||
if(_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)
|
||||
{
|
||||
int orig_return = _SDL_PollEvent(event);
|
||||
// only send events to Core after we get first SDL_NumJoysticks call
|
||||
// DF event loop is possibly polling for SDL events before things get inited properly
|
||||
// SDL handles it. We don't, because we use some other parts of SDL too.
|
||||
|
||||
// possible data race. whatever. it's a flag, we don't mind all that much
|
||||
if(inited && event != 0)
|
||||
{
|
||||
DFHack::Core & c = DFHack::Core::getInstance();
|
||||
return c.SDL_Event(event, orig_return);
|
||||
}
|
||||
return orig_return;
|
||||
}
|
||||
|
||||
static uint32_t (*_SDL_ThreadID)(void) = 0;
|
||||
DFhackCExport uint32_t SDL_ThreadID()
|
||||
{
|
||||
return _SDL_ThreadID();
|
||||
}
|
||||
|
||||
static SDL::Cond * (*_SDL_CreateCond)(void) = 0;
|
||||
DFhackCExport SDL::Cond *SDL_CreateCond(void)
|
||||
{
|
||||
return _SDL_CreateCond();
|
||||
}
|
||||
static void (*_SDL_DestroyCond)(SDL::Cond *) = 0;
|
||||
DFhackCExport void SDL_DestroyCond(SDL::Cond *cond)
|
||||
{
|
||||
_SDL_DestroyCond(cond);
|
||||
}
|
||||
static int (*_SDL_CondSignal)(SDL::Cond *) = 0;
|
||||
DFhackCExport int SDL_CondSignal(SDL::Cond *cond)
|
||||
{
|
||||
return _SDL_CondSignal(cond);
|
||||
}
|
||||
static int (*_SDL_CondWait)(SDL::Cond *, SDL::Mutex *) = 0;
|
||||
DFhackCExport int SDL_CondWait(SDL::Cond *cond, SDL::Mutex * mut)
|
||||
{
|
||||
return _SDL_CondWait(cond, mut);
|
||||
}
|
||||
|
||||
// hook - called at program start, initialize some stuffs we'll use later
|
||||
DFhackCExport int SDL_Init(uint32_t flags)
|
||||
{
|
||||
freopen("stdout.log", "w", stdout);
|
||||
freopen("stderr.log", "w", stderr);
|
||||
// horrible casts not supported by the C or C++ standards. Only POSIX. Damn you, POSIX.
|
||||
// find real functions
|
||||
//_SDL_GL_SwapBuffers = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_GL_SwapBuffers");
|
||||
_SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init");
|
||||
//_SDL_Flip = (int (*)( void * )) dlsym(RTLD_NEXT, "SDL_Flip");
|
||||
_SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit");
|
||||
_SDL_CreateThread = (SDL::Thread* (*)(int (*fn)(void *), void *data))dlsym(RTLD_NEXT, "SDL_CreateThread");
|
||||
_SDL_CreateMutex = (SDL::Mutex*(*)())dlsym(RTLD_NEXT,"SDL_CreateMutex");
|
||||
_SDL_DestroyMutex = (void (*)(SDL::Mutex*))dlsym(RTLD_NEXT,"SDL_DestroyMutex");
|
||||
_SDL_mutexP = (int (*)(SDL::Mutex*))dlsym(RTLD_NEXT,"SDL_mutexP");
|
||||
_SDL_mutexV = (int (*)(SDL::Mutex*))dlsym(RTLD_NEXT,"SDL_mutexV");
|
||||
_SDL_PollEvent = (int (*)(SDL::Event*))dlsym(RTLD_NEXT,"SDL_PollEvent");
|
||||
_SDL_ThreadID = (uint32_t (*)())dlsym(RTLD_NEXT,"SDL_ThreadID");
|
||||
|
||||
_SDL_CreateCond = (SDL::Cond * (*)())dlsym(RTLD_NEXT,"SDL_CreateCond");
|
||||
_SDL_DestroyCond = (void(*)(SDL::Cond *))dlsym(RTLD_NEXT,"SDL_DestroyCond");
|
||||
_SDL_CondSignal = (int (*)(SDL::Cond *))dlsym(RTLD_NEXT,"SDL_CondSignal");
|
||||
_SDL_CondWait = (int (*)(SDL::Cond *, SDL::Mutex *))dlsym(RTLD_NEXT,"SDL_CondWait");
|
||||
|
||||
// check if we got them
|
||||
if(_SDL_Init && _SDL_Quit && _SDL_CreateThread
|
||||
&& _SDL_CreateMutex && _SDL_DestroyMutex && _SDL_mutexP
|
||||
&& _SDL_mutexV && _SDL_PollEvent && _SDL_ThreadID
|
||||
&& _SDL_CondSignal && _SDL_CondWait && _SDL_CreateCond && _SDL_DestroyCond)
|
||||
{
|
||||
fprintf(stderr,"dfhack: hooking successful\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// bail, this would be a disaster otherwise
|
||||
fprintf(stderr,"dfhack: something went horribly wrong\n");
|
||||
exit(1);
|
||||
}
|
||||
int ret = _SDL_Init(flags);
|
||||
return ret;
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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 <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
#include "MicrosoftSTL.h"
|
||||
#include "dfhack/DFProcess.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
|
||||
using namespace DFHack;
|
||||
|
||||
void MicrosoftSTL::init(Process* self)
|
||||
{
|
||||
p = self;
|
||||
OffsetGroup * strGrp = p->getDescriptor()->getGroup("string")->getGroup("MSVC");
|
||||
STLSTR_buf_off = strGrp->getOffset("buffer");
|
||||
STLSTR_size_off = strGrp->getOffset("size");
|
||||
STLSTR_cap_off = strGrp->getOffset("capacity");
|
||||
}
|
||||
|
||||
size_t MicrosoftSTL::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
|
||||
{
|
||||
uint32_t start_offset = offset + STLSTR_buf_off;
|
||||
size_t length = p->readDWord(offset + STLSTR_size_off);
|
||||
size_t capacity = p->readDWord(offset + STLSTR_cap_off);
|
||||
|
||||
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
|
||||
|
||||
// read data from inside the string structure
|
||||
if(capacity < 16)
|
||||
{
|
||||
p->read(start_offset, read_real , (uint8_t *)buffer);
|
||||
}
|
||||
else // read data from what the offset + 4 dword points to
|
||||
{
|
||||
start_offset = p->readDWord(start_offset);// dereference the start offset
|
||||
p->read(start_offset, read_real, (uint8_t *)buffer);
|
||||
}
|
||||
|
||||
buffer[read_real] = 0;
|
||||
return read_real;
|
||||
}
|
||||
|
||||
const string MicrosoftSTL::readSTLString (uint32_t offset)
|
||||
{
|
||||
uint32_t start_offset = offset + STLSTR_buf_off;
|
||||
size_t length = p->readDWord(offset + STLSTR_size_off);
|
||||
size_t capacity = p->readDWord(offset + STLSTR_cap_off);
|
||||
|
||||
char * temp = new char[capacity+1];
|
||||
|
||||
// read data from inside the string structure
|
||||
if(capacity < 16)
|
||||
{
|
||||
p->read(start_offset, capacity, (uint8_t *)temp);
|
||||
}
|
||||
else // read data from what the offset + 4 dword points to
|
||||
{
|
||||
start_offset = p->readDWord(start_offset);// dereference the start offset
|
||||
p->read(start_offset, capacity, (uint8_t *)temp);
|
||||
}
|
||||
|
||||
temp[length] = 0;
|
||||
string ret = temp;
|
||||
delete temp;
|
||||
return ret;
|
||||
}
|
||||
|
||||
string MicrosoftSTL::readClassName (uint32_t vptr)
|
||||
{
|
||||
int rtti = p->readDWord(vptr - 0x4);
|
||||
int typeinfo = p->readDWord(rtti + 0xC);
|
||||
string raw = p->readCString(typeinfo + 0xC); // skips the .?AV
|
||||
raw.resize(raw.length() - 2);// trim @@ from end
|
||||
return raw;
|
||||
}
|
||||
|
||||
// FIXME: really, fix this.
|
||||
size_t MicrosoftSTL::writeSTLString(const uint32_t address, const std::string writeString)
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,395 @@
|
||||
/*
|
||||
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 "dfhack/Core.h"
|
||||
#include "dfhack/Process.h"
|
||||
#include "dfhack/PluginManager.h"
|
||||
#include "dfhack/Console.h"
|
||||
using namespace DFHack;
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
#ifdef LINUX_BUILD
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#else
|
||||
#include "wdirent.h"
|
||||
#endif
|
||||
|
||||
static int getdir (string dir, vector<string> &files)
|
||||
{
|
||||
DIR *dp;
|
||||
struct dirent *dirp;
|
||||
if((dp = opendir(dir.c_str())) == NULL)
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
while ((dirp = readdir(dp)) != NULL) {
|
||||
files.push_back(string(dirp->d_name));
|
||||
}
|
||||
closedir(dp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool hasEnding (std::string const &fullString, std::string const &ending)
|
||||
{
|
||||
if (fullString.length() > ending.length())
|
||||
{
|
||||
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
struct Plugin::RefLock
|
||||
{
|
||||
RefLock()
|
||||
{
|
||||
refcount = 0;
|
||||
wakeup = SDL_CreateCond();
|
||||
mut = SDL_CreateMutex();
|
||||
}
|
||||
~RefLock()
|
||||
{
|
||||
SDL_DestroyCond(wakeup);
|
||||
SDL_DestroyMutex(mut);
|
||||
}
|
||||
void lock()
|
||||
{
|
||||
SDL_mutexP(mut);
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
SDL_mutexV(mut);
|
||||
}
|
||||
void lock_add()
|
||||
{
|
||||
SDL_mutexP(mut);
|
||||
refcount ++;
|
||||
SDL_mutexV(mut);
|
||||
}
|
||||
void lock_sub()
|
||||
{
|
||||
SDL_mutexP(mut);
|
||||
refcount --;
|
||||
SDL_CondSignal(wakeup);
|
||||
SDL_mutexV(mut);
|
||||
}
|
||||
void operator++()
|
||||
{
|
||||
refcount ++;
|
||||
}
|
||||
void operator--()
|
||||
{
|
||||
refcount --;
|
||||
SDL_CondSignal(wakeup);
|
||||
}
|
||||
void wait()
|
||||
{
|
||||
while(refcount)
|
||||
{
|
||||
SDL_CondWait(wakeup, mut);
|
||||
}
|
||||
}
|
||||
SDL::Cond * wakeup;
|
||||
SDL::Mutex * mut;
|
||||
int refcount;
|
||||
};
|
||||
Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _filename, PluginManager * pm)
|
||||
{
|
||||
filename = filepath;
|
||||
parent = pm;
|
||||
name.reserve(_filename.size());
|
||||
for(int i = 0; i < _filename.size();i++)
|
||||
{
|
||||
char ch = _filename[i];
|
||||
if(ch == '.')
|
||||
break;
|
||||
name.append(1,ch);
|
||||
}
|
||||
Console & con = core->con;
|
||||
plugin_lib = 0;
|
||||
plugin_init = 0;
|
||||
plugin_shutdown = 0;
|
||||
plugin_status = 0;
|
||||
plugin_onupdate = 0;
|
||||
state = PS_UNLOADED;
|
||||
access = new RefLock();
|
||||
}
|
||||
|
||||
Plugin::~Plugin()
|
||||
{
|
||||
if(state == PS_LOADED)
|
||||
{
|
||||
unload();
|
||||
}
|
||||
delete access;
|
||||
}
|
||||
|
||||
bool Plugin::load()
|
||||
{
|
||||
access->lock();
|
||||
if(state == PS_BROKEN)
|
||||
{
|
||||
access->unlock();
|
||||
return false;
|
||||
}
|
||||
else if(state == PS_LOADED)
|
||||
{
|
||||
access->unlock();
|
||||
return true;
|
||||
}
|
||||
Core & c = Core::getInstance();
|
||||
Console & con = c.con;
|
||||
DFLibrary * plug = OpenPlugin(filename.c_str());
|
||||
if(!plug)
|
||||
{
|
||||
con.printerr("Can't load plugin %s\n", filename.c_str());
|
||||
state = PS_BROKEN;
|
||||
access->unlock();
|
||||
return false;
|
||||
}
|
||||
const char * (*_PlugName)() =(const char * (*)()) LookupPlugin(plug, "plugin_name");
|
||||
if(!_PlugName)
|
||||
{
|
||||
con.printerr("Plugin %s has no name.\n", filename.c_str());
|
||||
ClosePlugin(plug);
|
||||
state = PS_BROKEN;
|
||||
access->unlock();
|
||||
return false;
|
||||
}
|
||||
plugin_init = (command_result (*)(Core *, std::vector <PluginCommand> &)) LookupPlugin(plug, "plugin_init");
|
||||
if(!plugin_init)
|
||||
{
|
||||
con.printerr("Plugin %s has no init function.\n", filename.c_str());
|
||||
ClosePlugin(plug);
|
||||
state = PS_BROKEN;
|
||||
access->unlock();
|
||||
return false;
|
||||
}
|
||||
plugin_status = (command_result (*)(Core *, std::string &)) LookupPlugin(plug, "plugin_status");
|
||||
plugin_onupdate = (command_result (*)(Core *)) LookupPlugin(plug, "plugin_onupdate");
|
||||
plugin_shutdown = (command_result (*)(Core *)) LookupPlugin(plug, "plugin_shutdown");
|
||||
//name = _PlugName();
|
||||
plugin_lib = plug;
|
||||
if(plugin_init(&c,commands) == CR_OK)
|
||||
{
|
||||
state = PS_LOADED;
|
||||
parent->registerCommands(this);
|
||||
access->unlock();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
con.printerr("Plugin %s has failed to initialize properly.\n", filename.c_str());
|
||||
ClosePlugin(plugin_lib);
|
||||
state = PS_BROKEN;
|
||||
access->unlock();
|
||||
return false;
|
||||
}
|
||||
// not reachable
|
||||
}
|
||||
|
||||
bool Plugin::unload()
|
||||
{
|
||||
Core & c = Core::getInstance();
|
||||
Console & con = c.con;
|
||||
// get the mutex
|
||||
access->lock();
|
||||
// if we are actually loaded
|
||||
if(state == PS_LOADED)
|
||||
{
|
||||
// notify plugin about shutdown
|
||||
command_result cr = plugin_shutdown(&Core::getInstance());
|
||||
// wait for all calls to finish
|
||||
access->wait();
|
||||
// cleanup...
|
||||
parent->unregisterCommands(this);
|
||||
if(cr == CR_OK)
|
||||
{
|
||||
ClosePlugin(plugin_lib);
|
||||
state = PS_UNLOADED;
|
||||
access->unlock();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
con.printerr("Plugin %s has failed to shutdown!\n",name.c_str());
|
||||
state = PS_BROKEN;
|
||||
access->unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(state == PS_UNLOADED)
|
||||
{
|
||||
access->unlock();
|
||||
return true;
|
||||
}
|
||||
access->unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Plugin::reload()
|
||||
{
|
||||
if(state != PS_LOADED)
|
||||
return false;
|
||||
if(!unload())
|
||||
return false;
|
||||
if(!load())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
command_result Plugin::invoke( std::string & command, std::vector <std::string> & parameters)
|
||||
{
|
||||
Core & c = Core::getInstance();
|
||||
command_result cr = CR_NOT_IMPLEMENTED;
|
||||
access->lock_add();
|
||||
if(state == PS_LOADED)
|
||||
{
|
||||
for (int i = 0; i < commands.size();i++)
|
||||
{
|
||||
if(commands[i].name == command)
|
||||
{
|
||||
cr = commands[i].function(&c, parameters);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
access->lock_sub();
|
||||
return cr;
|
||||
}
|
||||
|
||||
command_result Plugin::on_update()
|
||||
{
|
||||
Core & c = Core::getInstance();
|
||||
command_result cr = CR_NOT_IMPLEMENTED;
|
||||
access->lock_add();
|
||||
if(state == PS_LOADED && plugin_onupdate)
|
||||
{
|
||||
cr = plugin_onupdate(&c);
|
||||
}
|
||||
access->lock_sub();
|
||||
return cr;
|
||||
}
|
||||
|
||||
Plugin::plugin_state Plugin::getState() const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
PluginManager::PluginManager(Core * core)
|
||||
{
|
||||
#ifdef LINUX_BUILD
|
||||
string path = core->p->getPath() + "/plugins/";
|
||||
const string searchstr = ".plug.so";
|
||||
#else
|
||||
string path = core->p->getPath() + "\\plugins\\";
|
||||
const string searchstr = ".plug.dll";
|
||||
#endif
|
||||
cmdlist_mutex = SDL_CreateMutex();
|
||||
vector <string> filez;
|
||||
getdir(path, filez);
|
||||
for(int i = 0; i < filez.size();i++)
|
||||
{
|
||||
if(hasEnding(filez[i],searchstr))
|
||||
{
|
||||
Plugin * p = new Plugin(core, path + filez[i], filez[i], this);
|
||||
all_plugins.push_back(p);
|
||||
// make all plugins load by default (until a proper design emerges).
|
||||
p->load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PluginManager::~PluginManager()
|
||||
{
|
||||
for(int i = 0; i < all_plugins.size();i++)
|
||||
{
|
||||
delete all_plugins[i];
|
||||
}
|
||||
all_plugins.clear();
|
||||
SDL_DestroyMutex(cmdlist_mutex);
|
||||
}
|
||||
|
||||
Plugin *PluginManager::getPluginByName (const std::string & name)
|
||||
{
|
||||
for(int i = 0; i < all_plugins.size(); i++)
|
||||
{
|
||||
if(name == all_plugins[i]->name)
|
||||
return all_plugins[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// FIXME: handle name collisions...
|
||||
command_result PluginManager::InvokeCommand( std::string & command, std::vector <std::string> & parameters)
|
||||
{
|
||||
command_result cr = CR_NOT_IMPLEMENTED;
|
||||
Core * c = &Core::getInstance();
|
||||
SDL_mutexP(cmdlist_mutex);
|
||||
map <string, Plugin *>::iterator iter = belongs.find(command);
|
||||
if(iter != belongs.end())
|
||||
{
|
||||
cr = iter->second->invoke(command, parameters);
|
||||
}
|
||||
SDL_mutexV(cmdlist_mutex);
|
||||
return cr;
|
||||
}
|
||||
|
||||
void PluginManager::OnUpdate( void )
|
||||
{
|
||||
for(int i = 0; i < all_plugins.size(); i++)
|
||||
{
|
||||
all_plugins[i]->on_update();
|
||||
}
|
||||
}
|
||||
// FIXME: doesn't check name collisions!
|
||||
void PluginManager::registerCommands( Plugin * p )
|
||||
{
|
||||
SDL_mutexP(cmdlist_mutex);
|
||||
vector <PluginCommand> & cmds = p->commands;
|
||||
for(int i = 0; i < cmds.size();i++)
|
||||
{
|
||||
belongs[cmds[i].name] = p;
|
||||
}
|
||||
SDL_mutexV(cmdlist_mutex);
|
||||
}
|
||||
|
||||
// FIXME: doesn't check name collisions!
|
||||
void PluginManager::unregisterCommands( Plugin * p )
|
||||
{
|
||||
SDL_mutexP(cmdlist_mutex);
|
||||
vector <PluginCommand> & cmds = p->commands;
|
||||
for(int i = 0; i < cmds.size();i++)
|
||||
{
|
||||
belongs.erase(cmds[i].name);
|
||||
}
|
||||
SDL_mutexV(cmdlist_mutex);
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
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 <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
using namespace std;
|
||||
|
||||
#include <md5wrapper.h>
|
||||
#include "dfhack/Process.h"
|
||||
#include "dfhack/VersionInfoFactory.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/Error.h"
|
||||
using namespace DFHack;
|
||||
|
||||
Process::Process(VersionInfoFactory * known_versions)
|
||||
{
|
||||
const char * dir_name = "/proc/self/";
|
||||
const char * exe_link_name = "/proc/self/exe";
|
||||
const char * cwd_name = "/proc/self/cwd";
|
||||
const char * cmdline_name = "/proc/self/cmdline";
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
|
||||
identified = false;
|
||||
my_descriptor = 0;
|
||||
|
||||
// resolve /proc/self/exe link
|
||||
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
|
||||
if (target_result == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// make sure we have a null terminated string...
|
||||
target_name[target_result] = 0;
|
||||
|
||||
// is this the regular linux DF?
|
||||
if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0)
|
||||
{
|
||||
md5wrapper md5;
|
||||
// get hash of the running DF process
|
||||
string hash = md5.getHashFromFile(target_name);
|
||||
// create linux process, add it to the vector
|
||||
VersionInfo * vinfo = known_versions->getVersionInfoByMD5(hash);
|
||||
if(vinfo)
|
||||
{
|
||||
my_descriptor = new VersionInfo(*vinfo);
|
||||
my_descriptor->setParentProcess(this);
|
||||
identified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string Process::doReadClassName (void * vptr)
|
||||
{
|
||||
//FIXME: BAD!!!!!
|
||||
int typeinfo = Process::readDWord((uint32_t)vptr - 0x4);
|
||||
int typestring = Process::readDWord(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 %2zu:%2zu %zu %[^\n]s",
|
||||
&start,
|
||||
&end,
|
||||
(char*)&permissions,
|
||||
&offset, &device1, &device2, &node,
|
||||
(char*)&temp.name);
|
||||
temp.start = start;
|
||||
temp.end = 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()
|
||||
{
|
||||
const char * cwd_name = "/proc/self/cwd";
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
target_result = readlink(cwd_name, target_name, sizeof(target_name));
|
||||
target_name[target_result] = '\0';
|
||||
return(string(target_name));
|
||||
}
|
||||
|
||||
int Process::getPID()
|
||||
{
|
||||
return getpid();
|
||||
}
|
@ -1,7 +1,30 @@
|
||||
// vim: sts=4 sta et shiftwidth=4:
|
||||
#include "dfhack/DFIntegers.h"
|
||||
#include "dfhack/DFTileTypes.h"
|
||||
#include "dfhack/DFExport.h"
|
||||
/*
|
||||
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 "dfhack/TileTypes.h"
|
||||
#include "dfhack/Export.h"
|
||||
|
||||
namespace DFHack
|
||||
{
|
@ -0,0 +1,16 @@
|
||||
#include "Internal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "dfhack/Process.h"
|
||||
#include "dfhack/Core.h"
|
||||
#include "dfhack/Virtual.h"
|
||||
using namespace DFHack;
|
||||
|
||||
std::string t_virtual::getClassName()
|
||||
{
|
||||
Core & c = Core::getInstance();
|
||||
return c.p->readClassName(vptr);
|
||||
}
|
@ -1,819 +0,0 @@
|
||||
/* Copyright (C) 2004 Xavier Decoret <Xavier.Decoret@imag.fr>
|
||||
*
|
||||
* argsteam is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Foobar 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Foobar; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef ARGSTREAM_H
|
||||
#define ARGSTREAM_H
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
class argstream;
|
||||
|
||||
template<class T>
|
||||
class ValueHolder;
|
||||
|
||||
template <typename T>
|
||||
argstream& operator>> (argstream&, const ValueHolder<T>&);
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of ValueHolder<T>
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
template<class T>
|
||||
class ValueHolder
|
||||
{
|
||||
public:
|
||||
ValueHolder(char s,
|
||||
const char* l,
|
||||
T& b,
|
||||
const char* desc,
|
||||
bool mandatory);
|
||||
ValueHolder(const char* l,
|
||||
T& b,
|
||||
const char* desc,
|
||||
bool mandatory);
|
||||
ValueHolder(char s,
|
||||
T& b,
|
||||
const char* desc,
|
||||
bool mandatory);
|
||||
friend argstream& operator>><>(argstream& s,const ValueHolder<T>& v);
|
||||
std::string name() const;
|
||||
std::string description() const;
|
||||
private:
|
||||
std::string shortName_;
|
||||
std::string longName_;
|
||||
T* value_;
|
||||
T initialValue_;
|
||||
std::string description_;
|
||||
bool mandatory_;
|
||||
};
|
||||
template <class T>
|
||||
inline ValueHolder<T>
|
||||
parameter(char s,
|
||||
const char* l,
|
||||
T& b,
|
||||
const char* desc="",
|
||||
bool mandatory = true)
|
||||
{
|
||||
return ValueHolder<T>(s,l,b,desc,mandatory);
|
||||
}
|
||||
template <class T>
|
||||
inline ValueHolder<T>
|
||||
parameter(char s,
|
||||
T& b,
|
||||
const char* desc="",
|
||||
bool mandatory = true)
|
||||
{
|
||||
return ValueHolder<T>(s,b,desc,mandatory);
|
||||
}
|
||||
template <class T>
|
||||
inline ValueHolder<T>
|
||||
parameter(const char* l,
|
||||
T& b,
|
||||
const char* desc="",
|
||||
bool mandatory = true)
|
||||
{
|
||||
return ValueHolder<T>(l,b,desc,mandatory);
|
||||
}
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of OptionHolder
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
class OptionHolder
|
||||
{
|
||||
public:
|
||||
inline OptionHolder(char s,
|
||||
const char* l,
|
||||
bool& b,
|
||||
const char* desc);
|
||||
inline OptionHolder(const char* l,
|
||||
bool& b,
|
||||
const char* desc);
|
||||
inline OptionHolder(char s,
|
||||
bool& b,
|
||||
const char* desc);
|
||||
friend argstream& operator>>(argstream& s,const OptionHolder& v);
|
||||
inline std::string name() const;
|
||||
inline std::string description() const;
|
||||
protected:
|
||||
inline OptionHolder(char s,
|
||||
const char* l,
|
||||
const char* desc);
|
||||
friend OptionHolder help(char s='h',
|
||||
const char* l="help",
|
||||
const char* desc="Display this help");
|
||||
private:
|
||||
std::string shortName_;
|
||||
std::string longName_;
|
||||
bool* value_;
|
||||
std::string description_;
|
||||
};
|
||||
inline OptionHolder
|
||||
option(char s,
|
||||
const char* l,
|
||||
bool& b,
|
||||
const char* desc="")
|
||||
{
|
||||
return OptionHolder(s,l,b,desc);
|
||||
}
|
||||
inline OptionHolder
|
||||
option(char s,
|
||||
bool& b,
|
||||
const char* desc="")
|
||||
{
|
||||
return OptionHolder(s,b,desc);
|
||||
}
|
||||
inline OptionHolder
|
||||
option(const char* l,
|
||||
bool& b,
|
||||
const char* desc="")
|
||||
{
|
||||
return OptionHolder(l,b,desc);
|
||||
}
|
||||
inline OptionHolder
|
||||
help(char s,
|
||||
const char* l,
|
||||
const char* desc)
|
||||
{
|
||||
return OptionHolder(s,l,desc);
|
||||
}
|
||||
template <class T, class O>
|
||||
class ValuesHolder;
|
||||
template <typename T, typename O>
|
||||
argstream& operator>> (argstream&, const ValuesHolder<T, O>&);
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of ValuesHolder
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
template<class T,class O>
|
||||
class ValuesHolder
|
||||
{
|
||||
public:
|
||||
ValuesHolder(const O& o,
|
||||
const char* desc,
|
||||
int len);
|
||||
friend argstream& operator>><>(argstream& s,const ValuesHolder<T,O>& v);
|
||||
std::string name() const;
|
||||
std::string description() const;
|
||||
typedef T value_type;
|
||||
private:
|
||||
mutable O value_;
|
||||
std::string description_;
|
||||
int len_;
|
||||
char letter_;
|
||||
};
|
||||
template<class T,class O>
|
||||
inline ValuesHolder<T,O>
|
||||
values(const O& o,
|
||||
const char* desc="",
|
||||
int len=-1)
|
||||
{
|
||||
return ValuesHolder<T,O>(o,desc,len);
|
||||
}
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of ValueParser
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
template <class T>
|
||||
class ValueParser
|
||||
{
|
||||
public:
|
||||
inline T operator()(const std::string& s) const
|
||||
{
|
||||
std::istringstream is(s);
|
||||
T t;
|
||||
is>>t;
|
||||
return t;
|
||||
}
|
||||
};
|
||||
// We need to specialize for string otherwise parsing of a value that
|
||||
// contains space (for example a string with space passed in quotes on the
|
||||
// command line) would parse only the first element of the value!!!
|
||||
template <>
|
||||
class ValueParser<std::string>
|
||||
{
|
||||
public:
|
||||
inline std::string operator()(const std::string& s) const
|
||||
{
|
||||
return s;
|
||||
}
|
||||
};
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// Interface of argstream
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
class argstream
|
||||
{
|
||||
public:
|
||||
inline argstream(int argc,char** argv);
|
||||
//inline argstream(const char* c);
|
||||
template<class T>
|
||||
friend argstream& operator>>(argstream& s,const ValueHolder<T>& v);
|
||||
friend inline argstream& operator>>(argstream& s,const OptionHolder& v);
|
||||
template<class T,class O>
|
||||
friend argstream& operator>>(argstream& s,const ValuesHolder<T,O>& v);
|
||||
|
||||
inline bool helpRequested() const;
|
||||
inline bool isOk() const;
|
||||
inline std::string errorLog() const;
|
||||
inline std::string usage() const;
|
||||
inline void defaultErrorHandling(bool ignoreUnused=false) const;
|
||||
static inline char uniqueLetter();
|
||||
protected:
|
||||
void parse(int argc,char** argv);
|
||||
private:
|
||||
typedef std::list<std::string>::iterator value_iterator;
|
||||
typedef std::pair<std::string,std::string> help_entry;
|
||||
std::string progName_;
|
||||
std::map<std::string,value_iterator> options_;
|
||||
std::list<std::string> values_;
|
||||
bool minusActive_;
|
||||
bool isOk_;
|
||||
std::deque<help_entry> argHelps_;
|
||||
std::string cmdLine_;
|
||||
std::deque<std::string> errors_;
|
||||
bool helpRequested_;
|
||||
};
|
||||
//************************************************************
|
||||
// Implementation of ValueHolder<T>
|
||||
//************************************************************
|
||||
template<class T>
|
||||
ValueHolder<T>::ValueHolder(char s,
|
||||
const char* l,
|
||||
T& v,
|
||||
const char* desc,
|
||||
bool mandatory)
|
||||
: shortName_(1,s),
|
||||
longName_(l),
|
||||
value_(&v),
|
||||
initialValue_(v),
|
||||
description_(desc),
|
||||
mandatory_(mandatory)
|
||||
{
|
||||
}
|
||||
template<class T>
|
||||
ValueHolder<T>::ValueHolder(const char* l,
|
||||
T& v,
|
||||
const char* desc,
|
||||
bool mandatory)
|
||||
: longName_(l),
|
||||
value_(&v),
|
||||
initialValue_(v),
|
||||
description_(desc),
|
||||
mandatory_(mandatory)
|
||||
{
|
||||
}
|
||||
template<class T>
|
||||
ValueHolder<T>::ValueHolder(char s,
|
||||
T& v,
|
||||
const char* desc,
|
||||
bool mandatory)
|
||||
: shortName_(1,s),
|
||||
value_(&v),
|
||||
initialValue_(v),
|
||||
description_(desc),
|
||||
mandatory_(mandatory)
|
||||
{
|
||||
}
|
||||
template<class T>
|
||||
std::string
|
||||
ValueHolder<T>::name() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
if (!shortName_.empty()) os<<'-'<<shortName_;
|
||||
if (!longName_.empty()) {
|
||||
if (!shortName_.empty()) os<<'/';
|
||||
os<<"--"<<longName_;
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
template<class T>
|
||||
std::string
|
||||
ValueHolder<T>::description() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os<<description_;
|
||||
if (mandatory_)
|
||||
{
|
||||
os<<"(mandatory)";
|
||||
}
|
||||
else
|
||||
{
|
||||
os<<"(default="<<initialValue_<<")";
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
//************************************************************
|
||||
// Implementation of OptionHolder
|
||||
//************************************************************
|
||||
inline OptionHolder::OptionHolder(char s,
|
||||
const char* l,
|
||||
bool& b,
|
||||
const char* desc)
|
||||
: shortName_(1,s),
|
||||
longName_(l),
|
||||
value_(&b),
|
||||
description_(desc)
|
||||
{
|
||||
}
|
||||
inline OptionHolder::OptionHolder(const char* l,
|
||||
bool& b,
|
||||
const char* desc)
|
||||
: longName_(l),
|
||||
value_(&b),
|
||||
description_(desc)
|
||||
{
|
||||
}
|
||||
inline OptionHolder::OptionHolder(char s,
|
||||
bool& b,
|
||||
const char* desc)
|
||||
: shortName_(1,s),
|
||||
value_(&b),
|
||||
description_(desc)
|
||||
{
|
||||
}
|
||||
inline OptionHolder::OptionHolder(char s,
|
||||
const char* l,
|
||||
const char* desc)
|
||||
: shortName_(1,s),
|
||||
longName_(l),
|
||||
value_(NULL),
|
||||
description_(desc)
|
||||
{
|
||||
}
|
||||
inline std::string
|
||||
OptionHolder::name() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
if (!shortName_.empty()) os<<'-'<<shortName_;
|
||||
if (!longName_.empty())
|
||||
{
|
||||
if (!shortName_.empty()) os<<'/';
|
||||
os<<"--"<<longName_;
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
inline std::string
|
||||
OptionHolder::description() const
|
||||
{
|
||||
return description_;
|
||||
}
|
||||
//************************************************************
|
||||
// Implementation of ValuesHolder<T,O>
|
||||
//************************************************************
|
||||
template<class T,class O>
|
||||
ValuesHolder<T,O>::ValuesHolder(const O& o,
|
||||
const char* desc,
|
||||
int len)
|
||||
: value_(o),
|
||||
description_(desc),
|
||||
len_(len)
|
||||
{
|
||||
letter_ = argstream::uniqueLetter();
|
||||
}
|
||||
template <class T,class O>
|
||||
std::string
|
||||
ValuesHolder<T,O>::name() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os<<letter_<<"i";
|
||||
return os.str();
|
||||
}
|
||||
template <class T,class O>
|
||||
std::string
|
||||
ValuesHolder<T,O>::description() const
|
||||
{
|
||||
return description_;
|
||||
}
|
||||
//************************************************************
|
||||
// Implementation of argstream
|
||||
//************************************************************
|
||||
inline
|
||||
argstream::argstream(int argc,char** argv)
|
||||
: progName_(argv[0]),
|
||||
minusActive_(true),
|
||||
isOk_(true)
|
||||
{
|
||||
parse(argc,argv);
|
||||
}
|
||||
//inline
|
||||
// argstream::argstream(const char* c)
|
||||
// : progName_(""),
|
||||
// minusActive_(true),
|
||||
// isOk_(true)
|
||||
//{
|
||||
// std::string s(c);
|
||||
// // Build argc, argv from s. We must add a dummy first element for
|
||||
// // progName because parse() expects it!!
|
||||
// std::deque<std::string> args;
|
||||
// args.push_back("");
|
||||
// std::istringstream is(s);
|
||||
// while (is.good())
|
||||
// {
|
||||
// std::string t;
|
||||
// is>>t;
|
||||
// args.push_back(t);
|
||||
// }
|
||||
// char* pargs[args.size()];
|
||||
// char** p = pargs;
|
||||
// for (std::deque<std::string>::const_iterator
|
||||
// iter = args.begin();
|
||||
// iter != args.end();++iter)
|
||||
// {
|
||||
// *p++ = const_cast<char*>(iter->c_str());
|
||||
// }
|
||||
// parse(args.size(),pargs);
|
||||
//}
|
||||
inline void
|
||||
argstream::parse(int argc,char** argv)
|
||||
{
|
||||
// Run thru all arguments.
|
||||
// * it has -- in front : it is a long name option, if remainder is empty,
|
||||
// it is an error
|
||||
// * it has - in front : it is a sequence of short name options, if
|
||||
// remainder is empty, deactivates option (- will
|
||||
// now be considered a char).
|
||||
// * if any other char, or if option was deactivated
|
||||
// : it is a value. Values are split in parameters
|
||||
// (immediately follow an option) and pure values.
|
||||
// Each time a value is parsed, if the previously parsed argument was an
|
||||
// option, then the option is linked to the value in case of it is a
|
||||
// option with parameter. The subtle point is that when several options
|
||||
// are given with short names (ex: -abc equivalent to -a -b -c), the last
|
||||
// parsed option is -c).
|
||||
// Since we use map for option, any successive call overides the previous
|
||||
// one: foo -a -b -a hello is equivalent to foo -b -a hello
|
||||
// For values it is not true since we might have several times the same
|
||||
// value.
|
||||
value_iterator* lastOption = NULL;
|
||||
for (char** a = argv,**astop=a+argc;++a!=astop;)
|
||||
{
|
||||
std::string s(*a);
|
||||
if (minusActive_ && s[0] == '-')
|
||||
{
|
||||
if (s.size() > 1 && s[1] == '-')
|
||||
{
|
||||
if (s.size() == 2)
|
||||
{
|
||||
minusActive_ = false;
|
||||
continue;
|
||||
}
|
||||
lastOption = &(options_[s.substr(2)] = values_.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s.size() > 1)
|
||||
{
|
||||
// Parse all chars, if it is a minus we have an error
|
||||
for (std::string::const_iterator cter = s.begin();
|
||||
++cter != s.end();)
|
||||
{
|
||||
if (*cter == '-')
|
||||
{
|
||||
isOk_ = false;
|
||||
std::ostringstream os;
|
||||
os<<"- in the middle of a switch "<<a;
|
||||
errors_.push_back(os.str());
|
||||
break;
|
||||
}
|
||||
lastOption = &(options_[std::string(1,*cter)] = values_.end());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isOk_ = false;
|
||||
errors_.push_back("Invalid argument -");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
values_.push_back(s);
|
||||
if (lastOption != NULL)
|
||||
{
|
||||
*lastOption = --values_.end();
|
||||
}
|
||||
lastOption = NULL;
|
||||
}
|
||||
}
|
||||
#ifdef ARGSTREAM_DEBUG
|
||||
for (std::map<std::string,value_iterator>::const_iterator
|
||||
iter = options_.begin();iter != options_.end();++iter)
|
||||
{
|
||||
std::cout<<"DEBUG: option "<<iter->first;
|
||||
if (iter->second != values_.end())
|
||||
{
|
||||
std::cout<<" -> "<<*(iter->second);
|
||||
}
|
||||
std::cout<<std::endl;
|
||||
}
|
||||
for (std::list<std::string>::const_iterator
|
||||
iter = values_.begin();iter != values_.end();++iter)
|
||||
{
|
||||
std::cout<<"DEBUG: value "<<*iter<<std::endl;
|
||||
}
|
||||
#endif // ARGSTREAM_DEBUG
|
||||
}
|
||||
inline bool
|
||||
argstream::isOk() const
|
||||
{
|
||||
return isOk_;
|
||||
}
|
||||
inline bool
|
||||
argstream::helpRequested() const
|
||||
{
|
||||
return helpRequested_;
|
||||
}
|
||||
inline std::string
|
||||
argstream::usage() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os<<"usage: "<<progName_<<cmdLine_<<'\n';
|
||||
unsigned int lmax = 0;
|
||||
for (std::deque<help_entry>::const_iterator
|
||||
iter = argHelps_.begin();iter != argHelps_.end();++iter)
|
||||
{
|
||||
if (lmax<iter->first.size()) lmax = iter->first.size();
|
||||
}
|
||||
for (std::deque<help_entry>::const_iterator
|
||||
iter = argHelps_.begin();iter != argHelps_.end();++iter)
|
||||
{
|
||||
os<<'\t'<<iter->first<<std::string(lmax-iter->first.size(),' ')
|
||||
<<" : "<<iter->second<<'\n';
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
inline std::string
|
||||
argstream::errorLog() const
|
||||
{
|
||||
std::string s;
|
||||
for(std::deque<std::string>::const_iterator iter = errors_.begin();
|
||||
iter != errors_.end();++iter)
|
||||
{
|
||||
s += *iter;
|
||||
s += '\n';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
inline char
|
||||
argstream::uniqueLetter()
|
||||
{
|
||||
static unsigned int c = 'a';
|
||||
return c++;
|
||||
}
|
||||
template<class T>
|
||||
argstream&
|
||||
operator>>(argstream& s,const ValueHolder<T>& v)
|
||||
{
|
||||
// Search in the options if there is any such option defined either with a
|
||||
// short name or a long name. If both are found, only the last one is
|
||||
// used.
|
||||
#ifdef ARGSTREAM_DEBUG
|
||||
std::cout<<"DEBUG: searching "<<v.shortName_<<" "<<v.longName_<<std::endl;
|
||||
#endif
|
||||
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||
if (v.mandatory_)
|
||||
{
|
||||
if (!v.shortName_.empty())
|
||||
{
|
||||
s.cmdLine_ += " -";
|
||||
s.cmdLine_ += v.shortName_;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.cmdLine_ += " --";
|
||||
s.cmdLine_ += v.longName_;
|
||||
}
|
||||
s.cmdLine_ += " value";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!v.shortName_.empty())
|
||||
{
|
||||
s.cmdLine_ += " [-";
|
||||
s.cmdLine_ += v.shortName_;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.cmdLine_ += " [--";
|
||||
s.cmdLine_ += v.longName_;
|
||||
}
|
||||
s.cmdLine_ += " value]";
|
||||
|
||||
}
|
||||
std::map<std::string,argstream::value_iterator>::iterator iter =
|
||||
s.options_.find(v.shortName_);
|
||||
if (iter == s.options_.end())
|
||||
{
|
||||
iter = s.options_.find(v.longName_);
|
||||
}
|
||||
if (iter != s.options_.end())
|
||||
{
|
||||
// If we find counterpart for value holder on command line, either it
|
||||
// has an associated value in which case we assign it, or it has not, in
|
||||
// which case we have an error.
|
||||
if (iter->second != s.values_.end())
|
||||
{
|
||||
#ifdef ARGSTREAM_DEBUG
|
||||
std::cout<<"DEBUG: found value "<<*(iter->second)<<std::endl;
|
||||
#endif
|
||||
ValueParser<T> p;
|
||||
*(v.value_) = p(*(iter->second));
|
||||
// The option and its associated value are removed, the subtle thing
|
||||
// is that someother options might have this associated value too,
|
||||
// which we must invalidate.
|
||||
s.values_.erase(iter->second);
|
||||
|
||||
// FIXME this loop seems to crash if a std::string is used as the value
|
||||
//for (std::map<std::string,argstream::value_iterator>::iterator
|
||||
// jter = s.options_.begin();jter != s.options_.end();++jter)
|
||||
//{
|
||||
// if (jter->second == iter->second)
|
||||
// {
|
||||
// jter->second = s.values_.end();
|
||||
// }
|
||||
//}
|
||||
s.options_.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
s.isOk_ = false;
|
||||
std::ostringstream os;
|
||||
os<<"No value following switch "<<iter->first
|
||||
<<" on command line";
|
||||
s.errors_.push_back(os.str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v.mandatory_)
|
||||
{
|
||||
s.isOk_ = false;
|
||||
std::ostringstream os;
|
||||
os<<"Mandatory parameter ";
|
||||
if (!v.shortName_.empty()) os<<'-'<<v.shortName_;
|
||||
if (!v.longName_.empty())
|
||||
{
|
||||
if (!v.shortName_.empty()) os<<'/';
|
||||
os<<"--"<<v.longName_;
|
||||
}
|
||||
os<<" missing";
|
||||
s.errors_.push_back(os.str());
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
inline argstream&
|
||||
operator>>(argstream& s,const OptionHolder& v)
|
||||
{
|
||||
// Search in the options if there is any such option defined either with a
|
||||
// short name or a long name. If both are found, only the last one is
|
||||
// used.
|
||||
#ifdef ARGSTREAM_DEBUG
|
||||
std::cout<<"DEBUG: searching "<<v.shortName_<<" "<<v.longName_<<std::endl;
|
||||
#endif
|
||||
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||
{
|
||||
std::string c;
|
||||
if (!v.shortName_.empty())
|
||||
{
|
||||
c += " [-";
|
||||
c += v.shortName_;
|
||||
}
|
||||
else
|
||||
{
|
||||
c += " [--";
|
||||
c += v.longName_;
|
||||
}
|
||||
c += "]";
|
||||
s.cmdLine_ = c+s.cmdLine_;
|
||||
}
|
||||
std::map<std::string,argstream::value_iterator>::iterator iter =
|
||||
s.options_.find(v.shortName_);
|
||||
if (iter == s.options_.end())
|
||||
{
|
||||
iter = s.options_.find(v.longName_);
|
||||
}
|
||||
if (iter != s.options_.end())
|
||||
{
|
||||
// If we find counterpart for value holder on command line then the
|
||||
// option is true and if an associated value was found, it is ignored
|
||||
if (v.value_ != NULL)
|
||||
{
|
||||
*(v.value_) = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.helpRequested_ = true;
|
||||
}
|
||||
// The option only is removed
|
||||
s.options_.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v.value_ != NULL)
|
||||
{
|
||||
*(v.value_) = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.helpRequested_ = false;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
template<class T,class O>
|
||||
argstream&
|
||||
operator>>(argstream& s,const ValuesHolder<T,O>& v)
|
||||
{
|
||||
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||
{
|
||||
std::ostringstream os;
|
||||
os<<' '<<v.letter_<<'1';
|
||||
switch (v.len_)
|
||||
{
|
||||
case -1:
|
||||
os<<"...";
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
os<<"..."<<v.letter_<<v.len_;
|
||||
break;
|
||||
}
|
||||
s.cmdLine_ += os.str();
|
||||
}
|
||||
std::list<std::string>::iterator first = s.values_.begin();
|
||||
// We add to the iterator as much values as we can, limited to the length
|
||||
// specified (if different of -1)
|
||||
int n = v.len_ != -1?v.len_:s.values_.size();
|
||||
while (first != s.values_.end() && n-->0)
|
||||
{
|
||||
// Read the value from the string *first
|
||||
ValueParser<T> p;
|
||||
*(v.value_++) = p(*first );
|
||||
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||
// The value we just removed was maybe "remembered" by an option so we
|
||||
// remove it now.
|
||||
for (std::map<std::string,argstream::value_iterator>::iterator
|
||||
jter = s.options_.begin();jter != s.options_.end();++jter)
|
||||
{
|
||||
if (jter->second == first)
|
||||
{
|
||||
jter->second = s.values_.end();
|
||||
}
|
||||
}
|
||||
++first;
|
||||
}
|
||||
// Check if we have enough values
|
||||
if (n != 0)
|
||||
{
|
||||
s.isOk_ = false;
|
||||
std::ostringstream os;
|
||||
os<<"Expecting "<<v.len_<<" values";
|
||||
s.errors_.push_back(os.str());
|
||||
}
|
||||
// Erase the values parsed
|
||||
s.values_.erase(s.values_.begin(),first);
|
||||
return s;
|
||||
}
|
||||
inline void
|
||||
argstream::defaultErrorHandling(bool ignoreUnused) const
|
||||
{
|
||||
if (helpRequested_)
|
||||
{
|
||||
std::cout<<usage();
|
||||
exit(1);
|
||||
}
|
||||
if (!isOk_)
|
||||
{
|
||||
std::cerr<<errorLog();
|
||||
exit(1);
|
||||
}
|
||||
if (!ignoreUnused &&
|
||||
(!values_.empty() || !options_.empty()))
|
||||
{
|
||||
std::cerr<<"Unused arguments"<<std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // ARGSTREAM_H
|
||||
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* www.sourceforge.net/projects/dfhack
|
||||
* Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef DFHACK_C_API
|
||||
#define DFHACK_C_API
|
||||
|
||||
#define HBUILD(a) a ## BufferCallback
|
||||
#define HREG_MACRO(type_name, type) DFHACK_EXPORT void HBUILD(Register ## type_name) (int (*funcptr)(type, uint32_t));
|
||||
|
||||
#define HUNREG_MACRO(type_name) DFHACK_EXPORT void HBUILD(Unregister ## type_name) ();
|
||||
|
||||
#include "dfhack/DFPragma.h"
|
||||
|
||||
#include "dfhack/DFExport.h"
|
||||
#include "dfhack/DFIntegers.h"
|
||||
|
||||
typedef void DFHackObject;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace DFHack {};
|
||||
using namespace DFHack;
|
||||
extern "C" {
|
||||
#endif
|
||||
// some global stuff here
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,157 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef DFHACK_C_CONTEXT
|
||||
#define DFHACK_C_CONTEXT
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Allocates a new ContextManager.
|
||||
@param path_to_xml A const string pointer containing the path to the Memory.xml file.
|
||||
@return A DFHackObject pointer that points to the allocated ContextManager.
|
||||
*/
|
||||
DFHACK_EXPORT DFHackObject* ContextManager_Alloc(const char* path_to_xml);
|
||||
|
||||
/**
|
||||
Frees a previously allocated ContextManager.
|
||||
@param contextMgr A DFHackObject pointer that points to a previously allocated ContextManager.
|
||||
@return None.
|
||||
*/
|
||||
DFHACK_EXPORT void ContextManager_Free(DFHackObject* contextMgr);
|
||||
|
||||
DFHACK_EXPORT int ContextManager_Refresh(DFHackObject* contextMgr);
|
||||
|
||||
/**
|
||||
Gets the number of active DF processes.
|
||||
@param contextMgr A pointer to an active ContextManager.
|
||||
@param size A pointer to an unsigned 32-bit integer that will contain the count of active DF processes.
|
||||
@return
|
||||
- 0: Failure.
|
||||
- 1: Success.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int ContextManager_size(DFHackObject* contextMgr, uint32_t* size);
|
||||
|
||||
DFHACK_EXPORT int ContextManager_purge(DFHackObject* contextMgr);
|
||||
DFHACK_EXPORT DFHackObject* ContextManager_getContext(DFHackObject* contextMgr, uint32_t index);
|
||||
DFHACK_EXPORT DFHackObject* ContextManager_getSingleContext(DFHackObject* contextMgr);
|
||||
|
||||
/**
|
||||
Frees a previously allocated Context.
|
||||
@param context A DFHackObject pointer that points to a previously allocated Context.
|
||||
@return None.
|
||||
*/
|
||||
DFHACK_EXPORT void Context_Free(DFHackObject* context);
|
||||
|
||||
/**
|
||||
Attaches to a running DF process.
|
||||
@param context A pointer to an unattached Context.
|
||||
@return
|
||||
- 0: Failure.
|
||||
- 1: Success.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int Context_Attach(DFHackObject* context);
|
||||
|
||||
/**
|
||||
Detaches from a tracked DF process.
|
||||
@param context A pointer to an attached Context.
|
||||
@return
|
||||
- 0: Failure.
|
||||
- 1: Success.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int Context_Detach(DFHackObject* context);
|
||||
|
||||
/**
|
||||
Determines whether or not the given Context is attached to a running DF process.
|
||||
@param context A pointer to an attached Context.
|
||||
@return
|
||||
- 0: The supplied Context is not attached.
|
||||
- 1: The supplied Context is attached.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int Context_isAttached(DFHackObject* context);
|
||||
|
||||
/**
|
||||
Suspends a running DF process.
|
||||
@param context A pointer to an attached Context.
|
||||
@return
|
||||
- 0: The tracked process was not suspended.
|
||||
- 1: The tracked process was suspended.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int Context_Suspend(DFHackObject* context);
|
||||
|
||||
/**
|
||||
Resume a running DF process.
|
||||
@param context A pointer to an attached Context.
|
||||
@return
|
||||
- 0: The tracked process was not resumed.
|
||||
- 1: The tracked process was resumed.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int Context_Resume(DFHackObject* context);
|
||||
|
||||
/**
|
||||
Determines whether or not the given Context's tracked process is suspended.
|
||||
@param context A pointer to an attached Context.
|
||||
@return
|
||||
- 0: The tracked process is not suspended.
|
||||
- 1: The tracked process is suspended.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int Context_isSuspended(DFHackObject* context);
|
||||
DFHACK_EXPORT int Context_ForceResume(DFHackObject* context);
|
||||
DFHACK_EXPORT int Context_AsyncSuspend(DFHackObject* context);
|
||||
|
||||
DFHACK_EXPORT DFHackObject* Context_getMemoryInfo(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getProcess(DFHackObject* context);
|
||||
|
||||
DFHACK_EXPORT DFHackObject* Context_getCreatures(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getMaps(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getGui(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getMaterials(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getTranslation(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getVegetation(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getBuildings(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getConstructions(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getItems(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getWorld(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getWindowIO(DFHackObject* context);
|
||||
|
||||
//these are DANGEROUS...can crash/segfault DF, turn the seas to blood, call up the Antichrist, etc
|
||||
DFHACK_EXPORT void Context_ReadRaw(DFHackObject* context, const uint32_t offset, const uint32_t size, uint8_t* target);
|
||||
DFHACK_EXPORT void Context_WriteRaw(DFHackObject* context, const uint32_t offset, const uint32_t size, uint8_t* source);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef PROCESS_C_API
|
||||
#define PROCESS_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFProcess.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct c_processID
|
||||
{
|
||||
uint64_t time;
|
||||
uint64_t pid;
|
||||
};
|
||||
|
||||
#define PROCESSID_C_NULL -2
|
||||
#define PROCESSID_C_LT -1
|
||||
#define PROCESSID_C_EQ 0
|
||||
#define PROCESSID_C_GT 1
|
||||
|
||||
DFHACK_EXPORT extern int C_ProcessID_Compare(c_processID* left, c_processID* right);
|
||||
|
||||
DFHACK_EXPORT int Process_attach(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_detach(DFHackObject* p_Ptr);
|
||||
|
||||
DFHACK_EXPORT int Process_suspend(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_asyncSuspend(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_resume(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_forceresume(DFHackObject* p_Ptr);
|
||||
|
||||
DFHACK_EXPORT int Process_readQuad(DFHackObject* p_Ptr, uint32_t address, uint64_t* value);
|
||||
DFHACK_EXPORT int Process_writeQuad(DFHackObject* p_Ptr, uint32_t address, uint64_t value);
|
||||
|
||||
DFHACK_EXPORT int Process_readDWord(DFHackObject* p_Ptr, uint32_t address, uint32_t* value);
|
||||
DFHACK_EXPORT int Process_writeDWord(DFHackObject* p_Ptr, uint32_t address, uint32_t value);
|
||||
|
||||
DFHACK_EXPORT int Process_readWord(DFHackObject* p_Ptr, uint32_t address, uint16_t* value);
|
||||
DFHACK_EXPORT int Process_writeWord(DFHackObject* p_Ptr, uint32_t address, uint16_t value);
|
||||
|
||||
DFHACK_EXPORT int Process_readFloat(DFHackObject* p_Ptr, uint32_t address, float* value);
|
||||
|
||||
DFHACK_EXPORT int Process_readByte(DFHackObject* p_Ptr, uint32_t address, uint8_t* value);
|
||||
DFHACK_EXPORT int Process_writeByte(DFHackObject* p_Ptr, uint32_t address, uint8_t value);
|
||||
|
||||
DFHACK_EXPORT uint8_t* Process_read(DFHackObject* p_Ptr, uint32_t address, uint32_t length);
|
||||
DFHACK_EXPORT void Process_write(DFHackObject* p_Ptr, uint32_t address, uint32_t length, uint8_t* buffer);
|
||||
|
||||
DFHACK_EXPORT int Process_readSTLVector(DFHackObject* p_Ptr, uint32_t address, t_vecTriplet* vector);
|
||||
|
||||
DFHACK_EXPORT const char* Process_readString(DFHackObject* p_Ptr, uint32_t offset);
|
||||
DFHACK_EXPORT const char* Process_getPath(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT const char* Process_readClassName(DFHackObject* p_Ptr, uint32_t vptr);
|
||||
|
||||
DFHACK_EXPORT int Process_isSuspended(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_isAttached(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_isIdentified(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_isSnapshot(DFHackObject* p_Ptr);
|
||||
|
||||
DFHACK_EXPORT uint32_t* Process_getThreadIDs(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT t_memrange* Process_getMemRanges(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_getPID(DFHackObject* p_Ptr, int32_t* pid);
|
||||
|
||||
DFHACK_EXPORT int Process_getModuleIndex(DFHackObject* p_Ptr, char* name, uint32_t version, uint32_t* output);
|
||||
|
||||
DFHACK_EXPORT int Process_SetAndWait(DFHackObject* p_Ptr, uint32_t state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef TILETYPES_C_API
|
||||
#define TILETYPES_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTileTypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int DFHack_isWallTerrain(int in);
|
||||
DFHACK_EXPORT int DFHack_isFloorTerrain(int in);
|
||||
DFHACK_EXPORT int DFHack_isRampTerrain(int in);
|
||||
DFHACK_EXPORT int DFHack_isStairTerrain(int in);
|
||||
DFHACK_EXPORT int DFHack_isOpenTerrain(int in);
|
||||
DFHACK_EXPORT int DFHack_getVegetationType(int in);
|
||||
|
||||
DFHACK_EXPORT int DFHack_getTileType(int index, TileRow* tPtr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,262 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef TYPES_C_API
|
||||
#define TYPES_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "DFProcess_C.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack/modules/Maps.h"
|
||||
#include "dfhack/modules/Materials.h"
|
||||
#include "dfhack/modules/Gui.h"
|
||||
|
||||
#define HBUILD(a) a ## BufferCallback
|
||||
#define HREG_MACRO(type_name, type) DFHACK_EXPORT void HBUILD(Register ## type_name) (int (*funcptr)(type, uint32_t));
|
||||
|
||||
#define HUNREG_MACRO(type_name) DFHACK_EXPORT void HBUILD(Unregister ## type_name) ();
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_byte_buffer_callback)(int8_t**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_short_buffer_callback)(int16_t**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_int_buffer_callback)(int32_t**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_ubyte_buffer_callback)(uint8_t**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_ushort_buffer_callback)(uint16_t**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_uint_buffer_callback)(uint32_t**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_char_buffer_callback)(char**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_matgloss_buffer_callback)(t_matgloss**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_descriptor_buffer_callback)(t_descriptor_color**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_matgloss_other_buffer_callback)(t_matglossOther**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_feature_buffer_callback)(t_feature**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_hotkey_buffer_callback)(t_hotkey**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_screen_buffer_callback)(t_screen**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_tree_buffer_callback)(dfh_plant**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_memrange_buffer_callback)(t_memrange**, uint32_t*, uint32_t);
|
||||
|
||||
DFHACK_EXPORT void RegisterByteBufferCallback(int (*funcptr)(int8_t**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterShortBufferCallback(int (*funcptr)(int16_t**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterIntBufferCallback(int (*funcptr)(int32_t**, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterUByteBufferCallback(int (*funcptr)(uint8_t**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterUShortBufferCallback(int (*funcptr)(uint16_t**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterUIntBufferCallback(int (*funcptr)(uint32_t**, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterCharBufferCallback(int (*funcptr)(char**, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterMatglossBufferCallback(int (*funcptr)(t_matgloss**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterDescriptorColorBufferCallback(int (*funcptr)(t_descriptor_color**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterMatglossOtherBufferCallback(int (*funcptr)(t_matglossOther**, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterFeatureBufferCallback(int (*funcptr)(t_feature**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterHotkeyBufferCallback(int (*funcptr)(t_hotkey**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterScreenBufferCallback(int (*funcptr)(t_screen**, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterTreeBufferCallback(int (*funcptr)(dfh_plant**, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterMemRangeBufferCallback(int (*funcptr)(t_memrange**, uint32_t*, uint32_t));
|
||||
|
||||
HUNREG_MACRO(Byte)
|
||||
HUNREG_MACRO(Short)
|
||||
HUNREG_MACRO(Int)
|
||||
HUNREG_MACRO(UByte)
|
||||
HUNREG_MACRO(UShort)
|
||||
HUNREG_MACRO(UInt)
|
||||
|
||||
HUNREG_MACRO(Char)
|
||||
|
||||
HUNREG_MACRO(Matgloss)
|
||||
HUNREG_MACRO(DescriptorColor)
|
||||
HUNREG_MACRO(MatglossOther)
|
||||
|
||||
HUNREG_MACRO(Feature)
|
||||
HUNREG_MACRO(Hotkey)
|
||||
HUNREG_MACRO(Screen)
|
||||
|
||||
HUNREG_MACRO(Tree)
|
||||
HUNREG_MACRO(MemRange)
|
||||
|
||||
struct t_customWorkshop
|
||||
{
|
||||
uint32_t index;
|
||||
char name[256];
|
||||
};
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_customWorkshop_buffer_callback)(t_customWorkshop**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_material_buffer_callback)(t_material**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT void RegisterCustomWorkshopBufferCallback(int (*funcptr)(t_customWorkshop**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterMaterialBufferCallback(int (*funcptr)(t_material**, uint32_t));
|
||||
|
||||
HUNREG_MACRO(CustomWorkshop)
|
||||
HUNREG_MACRO(Material)
|
||||
|
||||
struct c_colormodifier
|
||||
{
|
||||
char part[128];
|
||||
uint32_t* colorlist;
|
||||
uint32_t colorlistLength;
|
||||
uint32_t startdate;
|
||||
uint32_t enddate;
|
||||
};
|
||||
|
||||
struct c_colormodifier_descriptor
|
||||
{
|
||||
uint32_t colorlistLength;
|
||||
};
|
||||
|
||||
struct c_creaturecaste
|
||||
{
|
||||
char rawname[128];
|
||||
char singular[128];
|
||||
char plural[128];
|
||||
char adjective[128];
|
||||
|
||||
c_colormodifier* colorModifier;
|
||||
uint32_t colorModifierLength;
|
||||
|
||||
t_bodypart* bodypart;
|
||||
uint32_t bodypartLength;
|
||||
|
||||
t_attrib strength;
|
||||
t_attrib agility;
|
||||
t_attrib toughness;
|
||||
t_attrib endurance;
|
||||
t_attrib recuperation;
|
||||
t_attrib disease_resistance;
|
||||
t_attrib analytical_ability;
|
||||
t_attrib focus;
|
||||
t_attrib willpower;
|
||||
t_attrib creativity;
|
||||
t_attrib intuition;
|
||||
t_attrib patience;
|
||||
t_attrib memory;
|
||||
t_attrib linguistic_ability;
|
||||
t_attrib spatial_sense;
|
||||
t_attrib musicality;
|
||||
t_attrib kinesthetic_sense;
|
||||
};
|
||||
|
||||
struct c_creaturecaste_descriptor
|
||||
{
|
||||
c_colormodifier_descriptor* color_descriptors;
|
||||
uint32_t colorModifierLength;
|
||||
uint32_t bodypartLength;
|
||||
};
|
||||
|
||||
struct c_creaturetype
|
||||
{
|
||||
char rawname[128];
|
||||
|
||||
c_creaturecaste* castes;
|
||||
uint32_t castesCount;
|
||||
|
||||
t_creatureextract* extract;
|
||||
uint32_t extractCount;
|
||||
|
||||
uint8_t tile_character;
|
||||
|
||||
struct
|
||||
{
|
||||
uint16_t fore;
|
||||
uint16_t back;
|
||||
uint16_t bright;
|
||||
} tilecolor;
|
||||
};
|
||||
|
||||
struct c_creaturetype_descriptor
|
||||
{
|
||||
c_creaturecaste_descriptor* caste_descriptors;
|
||||
uint32_t castesCount;
|
||||
uint32_t extractCount;
|
||||
};
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_creaturetype_buffer_callback)(c_creaturetype**, c_creaturetype_descriptor*, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_vein_buffer_callback)(t_vein**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_spattervein_buffer_callback)(t_spattervein**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_grassvein_buffer_callback)(t_grassvein**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_worldconstruction_buffer_callback)(t_worldconstruction**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT void RegisterCreatureTypeBufferCallback(int (*funcptr)(c_creaturetype**, c_creaturetype_descriptor*, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterVeinBufferCallback(int (*funcptr)(t_vein**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterFrozenLiquidVeinBufferCallback(int (*funcptr)(t_frozenliquidvein**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterSpatterVeinBufferCallback(int (*funcptr)(t_spattervein**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterGrassVeinBufferCallback(int (*funcptr)(t_grassvein**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterWorldConstructionBufferCallback(int (*funcptr)(t_worldconstruction**, uint32_t));
|
||||
|
||||
HUNREG_MACRO(CreatureType)
|
||||
|
||||
HUNREG_MACRO(Vein)
|
||||
HUNREG_MACRO(FrozenLiquidVein)
|
||||
HUNREG_MACRO(SpatterVein)
|
||||
HUNREG_MACRO(GrassVein)
|
||||
HUNREG_MACRO(WorldConstruction)
|
||||
|
||||
struct c_mapcoord
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint32_t z;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
} dim;
|
||||
|
||||
uint64_t comparate;
|
||||
};
|
||||
};
|
||||
|
||||
struct c_featuremap_node
|
||||
{
|
||||
c_mapcoord coordinate;
|
||||
t_feature* features;
|
||||
uint32_t feature_length;
|
||||
};
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_featuremap_buffer_callback)(c_featuremap_node**, uint32_t*, uint32_t);
|
||||
|
||||
DFHACK_EXPORT void RegisterFeatureMapBufferCallback(int (*funcptr)(c_featuremap_node**, uint32_t*, uint32_t));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,133 +0,0 @@
|
||||
=======================================
|
||||
Introduction And Reasons For Existence
|
||||
=======================================
|
||||
|
||||
C++ is not an easy language to access from other languages. There are several "features" that make interoperability considerably more painful when trying to write bindings for Python, Ruby, Lua, or whatever. To that end, dfhack has a C translation layer to ease the process of making bindings for other languages. A shadow API, if you will.
|
||||
|
||||
.. contents::
|
||||
|
||||
|
||||
=================
|
||||
Getting DFHack-C
|
||||
=================
|
||||
The C shim is a part of the standard dfhack package. If you've installed dfhack, you've already got it. The dfhack source and binaries are hosted on github_, at http://github.com/peterix/dfhack
|
||||
|
||||
.. _github: http://www.github.com/
|
||||
|
||||
Packages
|
||||
=========
|
||||
The library and tools are packaged for Archlinux and are available both
|
||||
in AUR and the arch-games repository.
|
||||
|
||||
The package name is dfhack-git.
|
||||
|
||||
========
|
||||
Layout
|
||||
========
|
||||
The structure of the C shim mimics, as far as possible, the normal dfhack structure. Of course, since C lacks things like classes, templates, and function overloading, there are a few places where deviations are unavoidable.
|
||||
|
||||
Return Values
|
||||
=============
|
||||
Unless otherwise specified, functions that return an int return one of the following values:
|
||||
|
||||
- 0: The operation failed.
|
||||
- 1: The operation succeeded.
|
||||
- -1: An invalid module pointer was supplied.
|
||||
|
||||
Types
|
||||
=======
|
||||
Module objects are passed around as void pointers with the typedef name 'DFHackObject'. Wherever possible, the structures and enumerations defined by dfhack are used without redefinition.
|
||||
|
||||
Allocator Callbacks
|
||||
====================
|
||||
Wherever possible, the C shim eschews the native allocation of memory, as this would require language bindings to remember to free the memory later, and would, in my opinion, make the shim less flexible. So a number of function pointers are exposed to allow memory to be allocated in the language being used to wrap dfhack. In general, the allocations relate to arrays of dfhack structures, but there are a couple of corner cases.
|
||||
|
||||
The buffer callback functions should take a pointer to an array of the particular type, and a 32-bit unsigned integer (uint32_t) defining the length of the array needed. If the buffer was successfully created, the callback function should return 1. In case of failure, set the buffer pointer to NULL (or 0) and return 0.
|
||||
|
||||
All of the allocators are defined in dfhack/library/include/dfhack-c/DFTypes_C.h.
|
||||
|
||||
Buffer Callback List
|
||||
---------------------
|
||||
- alloc_byte_buffer_callback(int8_t**, uint32_t)
|
||||
- alloc_short_buffer_callback(int16_t**, uint32_t)
|
||||
- alloc_int_buffer_callback(int32_t**, uint32_t)
|
||||
- alloc_ubyte_buffer_callback(uint8_t**, uint32_t)
|
||||
- alloc_ushort_buffer_callback(uint16_t**, uint32_t)
|
||||
- alloc_uint_buffer_callback(uint32_t**, uint32_t)
|
||||
- alloc_char_buffer_callback(char** uint32_t)
|
||||
- alloc_matgloss_buffer_callback(t_matgloss**, uint32_t)
|
||||
- alloc_descriptor_buffer_callback(t_descriptor_color**, uint32_t)
|
||||
- alloc_matgloss_other_buffer_callback(t_matglossOther**, uint32_t)
|
||||
- alloc_t_feature_buffer_callback(t_feature**, uint32_t)
|
||||
- alloc_t_hotkey_buffer_callback(t_hotkey**, uint32_t)
|
||||
- alloc_t_screen_buffer_callback(t_screen**, uint32_t)
|
||||
- alloc_t_customWorkshop_buffer_callback(t_customWorkshop**, uint32_t)
|
||||
- alloc_t_material_buffer_callback(t_material**, uint32_t)
|
||||
- alloc_vein_buffer_callback(t_vein**, uint32_t)
|
||||
- alloc_frozenliquidvein_buffer_callback(t_frozenliquidvein**, uint32_t)
|
||||
- alloc_spattervein_buffer_callback(t_spattervein**, uint32_t)
|
||||
- alloc_grassvein_buffer_callback(t_grassvein**, uint32_t)
|
||||
- alloc_worldconstruction_buffer_callback(t_worldconstruction**, uint32_t)
|
||||
|
||||
|
||||
Templates Make My Life Harder
|
||||
-------------------------------
|
||||
Several dfhack structures contain vectors, which (obviously) don't work in C. Therefore, these structures have C versions that replace the vector with a buffer and length, but are otherwise identical to their C++ counterparts. For each structure, there are three associated callbacks. One initializes an empty instance of the structure (*alloc_empty_colormodifier_callback*, for instance), one initializes an instance with values passed in (*alloc_colormodifier_callback*), and one allocates a buffer in the same manner as the other allocators (*alloc_colormodifier_buffer_callback*).
|
||||
|
||||
The replaced structures and their callbacks are as follows.
|
||||
|
||||
- c_colormodifier
|
||||
* alloc_empty_colormodifier_callback(c_colormodifier*)
|
||||
* alloc_colormodifier_callback(c_colormodifier*, const char*, uint32_t)
|
||||
* alloc_colormodifier_buffer_callback(c_colormodifier*, uint32_t)
|
||||
- c_creaturecaste
|
||||
* alloc_empty_creaturecaste_callback(c_creaturecaste*)
|
||||
* alloc_creaturecaste_callback(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t)
|
||||
* alloc_creaturecaste_buffer_callback(c_creaturecaste*, uint32_t)
|
||||
- c_creaturetype
|
||||
* alloc_empty_creaturetype_callback(c_creaturetype*)
|
||||
* alloc_creaturetype_callback(c_creaturetype*, const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t)
|
||||
* alloc_creaturetype_buffer_callback(c_creaturetype*, uint32_t)
|
||||
|
||||
A Small Callback Example In Python
|
||||
-------------------------------------
|
||||
The Python bindings for dfhack implement the unsigned integer allocator callback like this:
|
||||
|
||||
.. admonition:: util.py
|
||||
|
||||
| from ctypes import \*
|
||||
|
|
||||
| def _allocate_array(t_type, count):
|
||||
| arr_type = t_type * count
|
||||
| arr = arr_type()
|
||||
|
|
||||
| return arr
|
||||
|
|
||||
| def _alloc_uint_buffer(ptr, count):
|
||||
| a = _allocate_array(c_uint, count)
|
||||
|
|
||||
| p = cast(a, POINTER(c_uint))
|
||||
|
|
||||
| ptr[0] = p
|
||||
|
|
||||
| return 1
|
||||
|
|
||||
| _uint_functype = CFUNCTYPE(c_int, POINTER(c_uint), c_uint)
|
||||
| alloc_uint_buffer = _uint_functype(_alloc_uint_buffer)
|
||||
|
||||
.. admonition:: dftypes.py
|
||||
|
||||
| from ctypes import \*
|
||||
| from util import \*
|
||||
|
|
||||
| libdfhack = cdll.libdfhack
|
||||
|
|
||||
| def _register_callback(name, func):
|
||||
| ptr = c_void_p.in_dll(libdfhack, name)
|
||||
| ptr.value = cast(func, c_void_p).value
|
||||
|
|
||||
| _register_callback("alloc_uint_buffer_callback", alloc_uint_buffer)
|
||||
|
||||
Modules
|
||||
========
|
||||
Every dfhack module has a corresponding set of C functions. The functions are named <MODULE>_<FUNCTION>, as in 'Maps_Start', 'Materials_ReadOthers', etc. The first argument to any module function is a void pointer that points to an instance of the module object in question.
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef BUILDINGS_C_API
|
||||
#define BUILDINGS_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack/modules/Buildings.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Buildings_Start(DFHackObject* b_Ptr, uint32_t* numBuildings);
|
||||
DFHACK_EXPORT int Buildings_Finish(DFHackObject* b_Ptr);
|
||||
|
||||
DFHACK_EXPORT int Buildings_Read(DFHackObject* b_Ptr, const uint32_t index, t_building* building);
|
||||
|
||||
DFHACK_EXPORT t_customWorkshop* Buildings_ReadCustomWorkshopTypes(DFHackObject* b_Ptr);
|
||||
DFHACK_EXPORT int Buildings_GetCustomWorkshopType(DFHackObject* b_Ptr, t_building* building);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef CONSTRUCTIONS_C_API
|
||||
#define CONSTRUCTIONS_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack/modules/Constructions.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Constructions_Start(DFHackObject* c_Ptr, uint32_t* numConstructions);
|
||||
DFHACK_EXPORT int Constructions_Finish(DFHackObject* c_Ptr);
|
||||
|
||||
DFHACK_EXPORT int Constructions_Read(DFHackObject* c_Ptr, const uint32_t index, t_construction* construction);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef CREATURES_C_API
|
||||
#define CREATURES_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
#include "dfhack/modules/Materials.h"
|
||||
#include "dfhack/modules/Creatures.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Creatures_Start(DFHackObject* cPtr, uint32_t* numCreatures);
|
||||
DFHACK_EXPORT int Creatures_Finish(DFHackObject* cPtr);
|
||||
|
||||
DFHACK_EXPORT int32_t Creatures_ReadCreatureInBox(DFHackObject* cPtr, const int32_t index, t_creature* furball,
|
||||
const uint16_t x1, const uint16_t y1, const uint16_t z1,
|
||||
const uint16_t x2, const uint16_t y2, const uint16_t z2);
|
||||
|
||||
DFHACK_EXPORT int Creatures_ReadCreature(DFHackObject* cPtr, const int32_t index, t_creature* furball);
|
||||
DFHACK_EXPORT t_material* Creatures_ReadJob(DFHackObject* cPtr, const t_creature* furball);
|
||||
|
||||
DFHACK_EXPORT uint32_t* Creatures_ReadInventoryIdx(DFHackObject* cPtr, const uint32_t index);
|
||||
DFHACK_EXPORT uint32_t* Creatures_ReadInventoryPtr(DFHackObject* cPtr, const uint32_t index);
|
||||
|
||||
DFHACK_EXPORT uint32_t Creatures_GetDwarfRaceIndex(DFHackObject* cPtr);
|
||||
DFHACK_EXPORT int32_t Creatures_GetDwarfCivId(DFHackObject* cPtr);
|
||||
|
||||
DFHACK_EXPORT int Creatures_WriteLabors(DFHackObject* cPtr, const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]);
|
||||
DFHACK_EXPORT int Creatures_WriteHappiness(DFHackObject* cPtr, const uint32_t index, const uint32_t happiness_value);
|
||||
DFHACK_EXPORT int Creatures_WriteFlags(DFHackObject* cPtr, const uint32_t index, const uint32_t flags1, const uint32_t flags2);
|
||||
DFHACK_EXPORT int Creatures_WriteFlags3(DFHackObject* cPtr, const uint32_t index, const uint32_t flags1, const uint32_t flags2, const uint32_t flags3);
|
||||
DFHACK_EXPORT int Creatures_WriteSkills(DFHackObject* cPtr, const uint32_t index, const t_soul* soul);
|
||||
DFHACK_EXPORT int Creatures_WriteAttributes(DFHackObject* cPtr, const uint32_t index, const t_creature* creature);
|
||||
DFHACK_EXPORT int Creatures_WriteSex(DFHackObject* cPtr, const uint32_t index, const uint8_t sex);
|
||||
DFHACK_EXPORT int Creatures_WriteTraits(DFHackObject* cPtr, const uint32_t index, const t_soul* soul);
|
||||
DFHACK_EXPORT int Creatures_WriteMood(DFHackObject* cPtr, const uint32_t index, const uint16_t mood);
|
||||
DFHACK_EXPORT int Creatures_WriteMoodSkill(DFHackObject* cPtr, const uint32_t index, const uint16_t moodSkill);
|
||||
DFHACK_EXPORT int Creatures_WriteJob(DFHackObject* cPtr, const t_creature* furball, const t_material* mat, const uint32_t mat_count);
|
||||
DFHACK_EXPORT int Creatures_WritePos(DFHackObject* cPtr, const uint32_t index, const t_creature* creature);
|
||||
DFHACK_EXPORT int Creatures_WriteCiv(DFHackObject* cPtr, const uint32_t index, const int32_t civ);
|
||||
DFHACK_EXPORT int Creatures_WritePregnancy(DFHackObject* cPtr, const uint32_t index, const uint32_t pregTimer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef GUI_C_API
|
||||
#define GUI_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack/modules/Gui.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Gui_Start(DFHackObject* gui);
|
||||
DFHACK_EXPORT int Gui_Finish(DFHackObject* gui);
|
||||
|
||||
DFHACK_EXPORT int Gui_getViewCoords(DFHackObject* gui, int32_t* x, int32_t* y, int32_t* z);
|
||||
DFHACK_EXPORT int Gui_setViewCoords(DFHackObject* gui, int32_t x, int32_t y, int32_t z);
|
||||
|
||||
DFHACK_EXPORT int Gui_getCursorCoords(DFHackObject* gui, int32_t* x, int32_t* y, int32_t* z);
|
||||
DFHACK_EXPORT int Gui_setCursorCoords(DFHackObject* gui, int32_t x, int32_t y, int32_t z);
|
||||
|
||||
DFHACK_EXPORT t_hotkey* Gui_ReadHotkeys(DFHackObject* gui);
|
||||
|
||||
DFHACK_EXPORT int Gui_getWindowSize(DFHackObject* gui, int32_t* width, int32_t* height);
|
||||
|
||||
DFHACK_EXPORT t_screen* Gui_getScreenTiles(DFHackObject* gui, int32_t width, int32_t height);
|
||||
|
||||
DFHACK_EXPORT int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen);
|
||||
DFHACK_EXPORT int Gui_ReadMenuState(DFHackObject* gui, uint32_t* menuState);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef ITEMS_C_API
|
||||
#define ITEMS_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFProcess.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
#include "dfhack/modules/Items.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Items_Start(DFHackObject* items);
|
||||
DFHACK_EXPORT int Items_Finish(DFHackObject* items);
|
||||
|
||||
DFHACK_EXPORT char* Items_getItemDescription(DFHackObject* items, dfh_item* item, DFHackObject* mats);
|
||||
DFHACK_EXPORT char* Items_getItemClass(DFHackObject* items, int32_t index);
|
||||
DFHACK_EXPORT int Items_getItemData(DFHackObject* items, uint32_t itemptr, dfh_item* item);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MAPS_C_API
|
||||
#define MAPS_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack/modules/Maps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Maps_Start(DFHackObject* maps);
|
||||
DFHACK_EXPORT int Maps_Finish(DFHackObject* maps);
|
||||
|
||||
DFHACK_EXPORT uint16_t* Maps_ReadGeology(DFHackObject* maps);
|
||||
|
||||
DFHACK_EXPORT t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps);
|
||||
DFHACK_EXPORT c_featuremap_node* Maps_ReadLocalFeatures(DFHackObject* maps);
|
||||
|
||||
DFHACK_EXPORT void Maps_getSize(DFHackObject* maps, uint32_t* x, uint32_t* y, uint32_t* z);
|
||||
DFHACK_EXPORT void Maps_getPosition(DFHackObject* maps, int32_t* x, int32_t* y, int32_t* z);
|
||||
|
||||
DFHACK_EXPORT int Maps_isValidBlock(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
|
||||
DFHACK_EXPORT uint32_t Maps_getBlockPtr(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadBlock40d(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, mapblock40d* buffer);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadTileTypes(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, tiletypes40d* buffer);
|
||||
DFHACK_EXPORT int Maps_WriteTileTypes(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, tiletypes40d* buffer);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadDesignations(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, designations40d* buffer);
|
||||
DFHACK_EXPORT int Maps_WriteDesignations(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, designations40d* buffer);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadTemperatures(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, t_temperatures* temp1, t_temperatures* temp2);
|
||||
DFHACK_EXPORT int Maps_WriteTemperatures(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, t_temperatures* temp1, t_temperatures* temp2);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadOccupancy(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, occupancies40d* buffer);
|
||||
DFHACK_EXPORT int Maps_WriteOccupancy(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, occupancies40d* buffer);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadDirtyBit(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int* dirtybit);
|
||||
DFHACK_EXPORT int Maps_WriteDirtyBit(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int dirtybit);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadFeatures(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int16_t* local, int16_t* global);
|
||||
DFHACK_EXPORT int Maps_WriteLocalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int16_t local);
|
||||
DFHACK_EXPORT int Maps_WriteEmptyLocalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
DFHACK_EXPORT int Maps_WriteGlobalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int16_t local);
|
||||
DFHACK_EXPORT int Maps_WriteEmptyGlobalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadBlockFlags(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, t_blockflags* blockflags);
|
||||
DFHACK_EXPORT int Maps_WriteBlockFlags(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, t_blockflags blockflags);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadRegionOffsets(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, biome_indices40d* buffer);
|
||||
|
||||
DFHACK_EXPORT t_vein* Maps_ReadStandardVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
DFHACK_EXPORT t_frozenliquidvein* Maps_ReadFrozenVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
DFHACK_EXPORT t_spattervein* Maps_ReadSpatterVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
DFHACK_EXPORT t_grassvein* Maps_ReadGrassVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
DFHACK_EXPORT t_worldconstruction* Maps_ReadWorldConstructions(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
t_vein* veins;
|
||||
t_frozenliquidvein* frozen_veins;
|
||||
t_spattervein* spatter_veins;
|
||||
t_grassvein* grass_veins;
|
||||
t_worldconstruction* world_constructions;
|
||||
} c_allveins;
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadAllVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, c_allveins* vein_struct);
|
||||
|
||||
DFHACK_EXPORT dfh_plant* Maps_ReadVegetation(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MATERIALS_C_API
|
||||
#define MATERIALS_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
#include "dfhack/modules/Materials.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Materials_ReadInorganicMaterials(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadOrganicMaterials(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadWoodMaterials(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadPlantMaterials(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadCreatureTypes(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadCreatureTypesEx(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadDescriptorColors(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadOthers(DFHackObject* mat);
|
||||
|
||||
DFHACK_EXPORT void Materials_ReadAllMaterials(DFHackObject* mat);
|
||||
|
||||
DFHACK_EXPORT const char* Materials_getType(DFHackObject* mat, t_material* material);
|
||||
DFHACK_EXPORT const char* Materials_getDescription(DFHackObject* mat, t_material* material);
|
||||
|
||||
DFHACK_EXPORT int Materials_getInorganicSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getOrganicSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getTreeSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getPlantSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getRaceSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getRaceExSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getColorSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getOtherSize(DFHackObject* mat);
|
||||
|
||||
DFHACK_EXPORT t_matgloss* Materials_getInorganic(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_matgloss* Materials_getOrganic(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_matgloss* Materials_getTree(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_matgloss* Materials_getPlant(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_matgloss* Materials_getRace(DFHackObject* mat);
|
||||
|
||||
DFHACK_EXPORT c_creaturetype* Materials_getRaceEx(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_descriptor_color* Materials_getColor(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_matglossOther* Materials_getOther(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_matgloss* Materials_getAllDesc(DFHackObject* mat);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef TRANSLATION_C_API
|
||||
#define TRANSLATION_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
#include "dfhack/modules/Translation.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Translation_Start(DFHackObject* trans);
|
||||
DFHACK_EXPORT int Translation_Finish(DFHackObject* trans);
|
||||
|
||||
DFHACK_EXPORT char* Translation_TranslateNameEnglish(DFHackObject* trans, const DFHack::t_name* name);
|
||||
DFHACK_EXPORT char* Translation_TranslateNameNonEnglish(DFHackObject* trans, const DFHack::t_name* name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef VEGETATION_C_API
|
||||
#define VEGETATION_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack/modules/Vegetation.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Vegetation_Start(DFHackObject* veg, uint32_t* numTrees);
|
||||
DFHACK_EXPORT int Vegetation_Finish(DFHackObject* veg);
|
||||
|
||||
DFHACK_EXPORT int Vegetation_Read(DFHackObject* veg, const uint32_t index, dfh_plant* shrubbery);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef WINDOWIO_C_API
|
||||
#define WINDOWIO_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/modules/WindowIO.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int WindowIO_TypeStr(DFHackObject* window, const char* input, uint32_t delay, int8_t useShift);
|
||||
|
||||
DFHACK_EXPORT int WindowIO_TypeSpecial(DFHackObject* window, t_special command, uint32_t count, uint32_t delay);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef WORLD_C_API
|
||||
#define WORLD_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/modules/World.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int World_Start(DFHackObject* world);
|
||||
DFHACK_EXPORT int World_Finish(DFHackObject* world);
|
||||
|
||||
DFHACK_EXPORT int World_ReadCurrentTick(DFHackObject* world, uint32_t* tick);
|
||||
DFHACK_EXPORT int World_ReadCurrentYear(DFHackObject* world, uint32_t* year);
|
||||
DFHACK_EXPORT int World_ReadCurrentMonth(DFHackObject* world, uint32_t* month);
|
||||
DFHACK_EXPORT int World_ReadCurrentDay(DFHackObject* world, uint32_t* day);
|
||||
|
||||
DFHACK_EXPORT int World_ReadCurrentWeather(DFHackObject* world, uint8_t* weather);
|
||||
DFHACK_EXPORT int World_WriteCurrentWeather(DFHackObject* world, uint8_t weather);
|
||||
|
||||
DFHACK_EXPORT int World_ReadGameMode(DFHackObject* world, t_gamemodes*);
|
||||
DFHACK_EXPORT int World_WriteGameMode(DFHackObject* world, t_gamemodes);
|
||||
|
||||
DFHACK_EXPORT int World_ReadPauseState(DFHackObject* gui);
|
||||
DFHACK_EXPORT int World_SetPauseState(DFHackObject* gui, int8_t paused);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
https://github.com/peterix/dfhack
|
||||
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dfhack/Pragma.h"
|
||||
#include "dfhack/Export.h"
|
||||
#include <ostream>
|
||||
#include "FakeSDL.h"
|
||||
namespace DFHack
|
||||
{
|
||||
class Private;
|
||||
class DFHACK_EXPORT Console : public std::ostream
|
||||
{
|
||||
public:
|
||||
enum color_value
|
||||
{
|
||||
COLOR_RESET = -1,
|
||||
COLOR_BLACK = 0,
|
||||
COLOR_BLUE,
|
||||
COLOR_GREEN,
|
||||
COLOR_CYAN,
|
||||
COLOR_RED,
|
||||
COLOR_MAGENTA,
|
||||
COLOR_BROWN,
|
||||
COLOR_GREY,
|
||||
COLOR_DARKGREY,
|
||||
COLOR_LIGHTBLUE,
|
||||
COLOR_LIGHTGREEN,
|
||||
COLOR_LIGHTCYAN,
|
||||
COLOR_LIGHTRED,
|
||||
COLOR_LIGHTMAGENTA,
|
||||
COLOR_YELLOW,
|
||||
COLOR_WHITE,
|
||||
COLOR_MAX = COLOR_WHITE
|
||||
};
|
||||
///ctor, NOT thread-safe
|
||||
Console();
|
||||
///dtor, NOT thread-safe
|
||||
~Console();
|
||||
/// initialize the console. NOT thread-safe
|
||||
bool init( void );
|
||||
/// shutdown the console. NOT thread-safe
|
||||
bool shutdown( void );
|
||||
|
||||
/// Print a formatted string, like printf
|
||||
int print(const char * format, ...);
|
||||
/// Print a formatted string, like printf, in red
|
||||
int printerr(const char * format, ...);
|
||||
/// Clear the console, along with its scrollback
|
||||
void clear();
|
||||
/// Position cursor at x,y. 1,1 = top left corner
|
||||
void gotoxy(int x, int y);
|
||||
/// Set color (ANSI color number)
|
||||
void color(color_value c);
|
||||
/// Reset color to default
|
||||
void reset_color(void);
|
||||
/// Enable or disable the caret/cursor
|
||||
void cursor(bool enable = true);
|
||||
/// Waits given number of milliseconds before continuing.
|
||||
void msleep(unsigned int msec);
|
||||
/// get the current number of columns
|
||||
int get_columns(void);
|
||||
/// get the current number of rows
|
||||
int get_rows(void);
|
||||
/// beep. maybe?
|
||||
//void beep (void);
|
||||
/// A simple line edit (raw mode)
|
||||
int lineedit(const std::string& prompt, std::string& output);
|
||||
/// add a command to the history
|
||||
void history_add(const std::string& command);
|
||||
/// clear the command history
|
||||
void history_clear();
|
||||
private:
|
||||
Private * d;
|
||||
SDL::Mutex * wlock;
|
||||
bool inited;
|
||||
};
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
/*
|
||||
https://github.com/peterix/dfhack
|
||||
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dfhack/Pragma.h"
|
||||
#include "dfhack/Export.h"
|
||||
#include "dfhack/FakeSDL.h"
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
#include "dfhack/Console.h"
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
class Process;
|
||||
class Module;
|
||||
class Creatures;
|
||||
class Engravings;
|
||||
class Maps;
|
||||
class Gui;
|
||||
class World;
|
||||
class Materials;
|
||||
class Items;
|
||||
class Translation;
|
||||
class Vegetation;
|
||||
class Buildings;
|
||||
class Constructions;
|
||||
class Vermin;
|
||||
class Notes;
|
||||
class VersionInfo;
|
||||
class VersionInfoFactory;
|
||||
class PluginManager;
|
||||
class Core;
|
||||
// anon type, pretty much
|
||||
struct DFLibrary;
|
||||
|
||||
DFLibrary * OpenPlugin (const char * filename);
|
||||
void * LookupPlugin (DFLibrary * plugin ,const char * function);
|
||||
void ClosePlugin (DFLibrary * plugin);
|
||||
|
||||
// Core is a singleton. Why? Because it is closely tied to SDL calls. It tracks the global state of DF.
|
||||
// There should never be more than one instance
|
||||
// Better than tracking some weird variables all over the place.
|
||||
class DFHACK_EXPORT Core
|
||||
{
|
||||
friend int ::SDL_NumJoysticks(void);
|
||||
friend void ::SDL_Quit(void);
|
||||
friend int ::SDL_PollEvent(SDL::Event *);
|
||||
public:
|
||||
/// Get the single Core instance or make one.
|
||||
static Core& getInstance()
|
||||
{
|
||||
// FIXME: add critical section for thread safety here.
|
||||
static Core instance;
|
||||
return instance;
|
||||
}
|
||||
/// try to acquire the activity lock
|
||||
void Suspend(void);
|
||||
/// return activity lock
|
||||
void Resume(void);
|
||||
/// Is everything OK?
|
||||
bool isValid(void) { return !errorstate; }
|
||||
|
||||
/// get the creatures module
|
||||
Creatures * getCreatures();
|
||||
/// get the engravings module
|
||||
Engravings * getEngravings();
|
||||
/// get the maps module
|
||||
Maps * getMaps();
|
||||
/// get the gui module
|
||||
Gui * getGui();
|
||||
/// get the world module
|
||||
World * getWorld();
|
||||
/// get the materials module
|
||||
Materials * getMaterials();
|
||||
/// get the items module
|
||||
Items * getItems();
|
||||
/// get the translation module
|
||||
Translation * getTranslation();
|
||||
/// get the vegetation module
|
||||
Vegetation * getVegetation();
|
||||
/// get the buildings module
|
||||
Buildings * getBuildings();
|
||||
/// get the constructions module
|
||||
Constructions * getConstructions();
|
||||
/// get the vermin module
|
||||
Vermin * getVermin();
|
||||
/// get the notes module
|
||||
Notes * getNotes();
|
||||
/// sets the current hotkey command
|
||||
bool setHotkeyCmd( std::string cmd );
|
||||
/// removes the hotkey command and gives it to the caller thread
|
||||
std::string getHotkeyCmd( void );
|
||||
|
||||
DFHack::Process * p;
|
||||
DFHack::VersionInfo * vinfo;
|
||||
DFHack::Console con;
|
||||
private:
|
||||
Core();
|
||||
bool Init();
|
||||
int Update (void);
|
||||
int Shutdown (void);
|
||||
int SDL_Event(SDL::Event* event, int orig_return);
|
||||
Core(Core const&); // Don't Implement
|
||||
void operator=(Core const&); // Don't implement
|
||||
bool errorstate;
|
||||
// regulate access to DF
|
||||
struct Cond;
|
||||
SDL::Mutex * AccessMutex;
|
||||
SDL::Mutex * StackMutex;
|
||||
std::stack < Core::Cond * > suspended_tools;
|
||||
Core::Cond * core_cond;
|
||||
// FIXME: shouldn't be kept around like this
|
||||
DFHack::VersionInfoFactory * vif;
|
||||
// Module storage
|
||||
struct
|
||||
{
|
||||
Creatures * pCreatures;
|
||||
Engravings * pEngravings;
|
||||
Maps * pMaps;
|
||||
Gui * pGui;
|
||||
World * pWorld;
|
||||
Materials * pMaterials;
|
||||
Items * pItems;
|
||||
Translation * pTranslation;
|
||||
Vegetation * pVegetation;
|
||||
Buildings * pBuildings;
|
||||
Constructions * pConstructions;
|
||||
Vermin * pVermin;
|
||||
Notes * pNotes;
|
||||
} s_mods;
|
||||
std::vector <Module *> allModules;
|
||||
DFHack::PluginManager * plug_mgr;
|
||||
// hotkey-related stuff
|
||||
int hotkey_states[16];
|
||||
std::string hotkey_cmd;
|
||||
bool hotkey_set;
|
||||
SDL::Mutex * HotkeyMutex;
|
||||
SDL::Cond * HotkeyCond;
|
||||
// Very important!
|
||||
bool started;
|
||||
};
|
||||
}
|
@ -1,172 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef CONTEXT_H_INCLUDED
|
||||
#define CONTEXT_H_INCLUDED
|
||||
|
||||
#include "DFExport.h"
|
||||
namespace DFHack
|
||||
{
|
||||
class Creatures;
|
||||
class Engravings;
|
||||
class Maps;
|
||||
class Gui;
|
||||
class World;
|
||||
class Materials;
|
||||
class Items;
|
||||
class Translation;
|
||||
class Vegetation;
|
||||
class Buildings;
|
||||
class Constructions;
|
||||
class VersionInfo;
|
||||
class DFContextShared;
|
||||
class WindowIO;
|
||||
class Process;
|
||||
/**
|
||||
* This class wraps all the different related objects for a particular Process
|
||||
* \ingroup grp_context
|
||||
*/
|
||||
class DFHACK_EXPORT Context
|
||||
{
|
||||
public:
|
||||
Context(Process * p);
|
||||
~Context();
|
||||
|
||||
/// @return true if there's version information for the associated Process
|
||||
bool isValid();
|
||||
/// attach to the related process. Claims OS debugging resources
|
||||
bool Attach();
|
||||
/// detach from the related process. Releases OS debugging resources
|
||||
bool Detach();
|
||||
/// @return true if the process is attached.
|
||||
bool isAttached();
|
||||
|
||||
/// stop the tracked process
|
||||
bool Suspend();
|
||||
/// @return true if the process is stopped
|
||||
bool isSuspended();
|
||||
|
||||
/// stop the tracked process, asynchronous
|
||||
bool AsyncSuspend();
|
||||
|
||||
/// resume the tracked process
|
||||
bool Resume();
|
||||
|
||||
/// forces resume on Windows. This can be a bad thing with multiple tools running!
|
||||
bool ForceResume();
|
||||
|
||||
VersionInfo *getMemoryInfo();
|
||||
Process* getProcess();
|
||||
|
||||
void ReadRaw (const uint32_t offset, const uint32_t size, uint8_t *target);
|
||||
void WriteRaw (const uint32_t offset, const uint32_t size, uint8_t *source);
|
||||
|
||||
/// get the creatures module
|
||||
Creatures * getCreatures();
|
||||
|
||||
/// get the engravings module
|
||||
Engravings * getEngravings();
|
||||
|
||||
/// get the maps module
|
||||
Maps * getMaps();
|
||||
|
||||
/// get the gui module
|
||||
Gui * getGui();
|
||||
|
||||
/// get the world module
|
||||
World * getWorld();
|
||||
|
||||
/// get the materials module
|
||||
Materials * getMaterials();
|
||||
|
||||
/// get the items module
|
||||
Items * getItems();
|
||||
|
||||
/// get the translation module
|
||||
Translation * getTranslation();
|
||||
|
||||
/// get the vegetation module
|
||||
Vegetation * getVegetation();
|
||||
|
||||
/// get the buildings module
|
||||
Buildings * getBuildings();
|
||||
|
||||
/// get the constructions module
|
||||
Constructions * getConstructions();
|
||||
|
||||
/// get the Window management and I/O module
|
||||
WindowIO * getWindowIO();
|
||||
|
||||
// DEAD CODE, WAITING TO BE UPDATED TO DF2010
|
||||
/*
|
||||
* Effects like mist, dragonfire or dust
|
||||
*/
|
||||
/*
|
||||
bool InitReadEffects ( uint32_t & numeffects );
|
||||
bool ReadEffect(const uint32_t index, t_effect_df40d & effect);
|
||||
bool WriteEffect(const uint32_t index, const t_effect_df40d & effect);
|
||||
void FinishReadEffects();
|
||||
*/
|
||||
/*
|
||||
* Notes placed by the player
|
||||
*/
|
||||
/*
|
||||
/// start reading notes. numnotes is an output - total notes present
|
||||
bool InitReadNotes( uint32_t & numnotes );
|
||||
/// read note from the note vector at index
|
||||
bool ReadNote(const int32_t index, t_note & note);
|
||||
/// free the note vector
|
||||
void FinishReadNotes();
|
||||
*/
|
||||
/*
|
||||
* Settlements
|
||||
*/
|
||||
/*
|
||||
bool InitReadSettlements( uint32_t & numsettlements );
|
||||
bool ReadSettlement(const int32_t index, t_settlement & settlement);
|
||||
bool ReadCurrentSettlement(t_settlement & settlement);
|
||||
void FinishReadSettlements();
|
||||
*/
|
||||
/*
|
||||
* Item reading
|
||||
*/
|
||||
/*
|
||||
bool InitReadItems(uint32_t & numitems);
|
||||
bool getItemIndexesInBox(std::vector<uint32_t> &indexes,
|
||||
const uint16_t x1, const uint16_t y1, const uint16_t z1,
|
||||
const uint16_t x2, const uint16_t y2, const uint16_t z2);
|
||||
bool ReadItem(const uint32_t index, t_item & item);
|
||||
void FinishReadItems();
|
||||
*/
|
||||
/*
|
||||
* Get the other API parts for raw access
|
||||
*/
|
||||
private:
|
||||
DFContextShared * d;
|
||||
};
|
||||
}
|
||||
#endif //CONTEXT_H_INCLUDED
|
||||
|
@ -1,149 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef CONTEXTMANAGER_H_INCLUDED
|
||||
#define CONTEXTMANAGER_H_INCLUDED
|
||||
|
||||
|
||||
#include "DFPragma.h"
|
||||
#include "DFExport.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
class Context;
|
||||
class BadContexts;
|
||||
class Process;
|
||||
/**
|
||||
* Used to enumerate, create and destroy Contexts. The very base of DFHack.
|
||||
* @see DFHack::Context
|
||||
* \ingroup grp_context
|
||||
*/
|
||||
class DFHACK_EXPORT ContextManager
|
||||
{
|
||||
class Private;
|
||||
Private * const d;
|
||||
public:
|
||||
/**
|
||||
* Constructs the ContextManager.
|
||||
* @param path_to_xml the path to the file that defines memory offsets. (Memory.xml)
|
||||
*/
|
||||
ContextManager(const std::string path_to_xml);
|
||||
|
||||
/**
|
||||
* Destroys the ContextManager.
|
||||
*/
|
||||
~ContextManager();
|
||||
|
||||
/**
|
||||
* Refresh the internal list of valid Context objects.
|
||||
* @param bad_contexts pointer to a BadContexts object. Not required. All contexts are automatically destroyed if the object is not provided.
|
||||
* @see DFHack::BadContexts
|
||||
* @return Number of tracked contexts
|
||||
*/
|
||||
uint32_t Refresh(BadContexts* bad_contexts = 0);
|
||||
|
||||
/**
|
||||
* Get the number of tracked contexts.
|
||||
* @return Number of tracked contexts
|
||||
*/
|
||||
uint32_t size();
|
||||
|
||||
/**
|
||||
* Get a context by index
|
||||
* @param index index of the context to be returned
|
||||
* @return pointer to a Context. 0 if the index is out of range.
|
||||
*/
|
||||
Context * operator[](uint32_t index);
|
||||
|
||||
/**
|
||||
* Convenience method to return a single valid Context
|
||||
* @return pointer to a Context. The Context isn't attached!
|
||||
*/
|
||||
Context * getSingleContext();
|
||||
|
||||
/**
|
||||
* Destroy all tracked Context objects
|
||||
* Normally called during object destruction. Calling this from outside ContextManager is nasty.
|
||||
*/
|
||||
void purge(void);
|
||||
};
|
||||
|
||||
/**
|
||||
* Class used for holding a set of invalidated Context AND Process objects temporarily and destroy them safely.
|
||||
* @see DFHack::Context
|
||||
* @see DFHack::Process
|
||||
* \ingroup grp_context
|
||||
*/
|
||||
class DFHACK_EXPORT BadContexts
|
||||
{
|
||||
class Private;
|
||||
Private * const d;
|
||||
void push_back(Context * c);
|
||||
friend class ContextManager;
|
||||
void clear();
|
||||
public:
|
||||
BadContexts();
|
||||
/**
|
||||
* Destructor.
|
||||
* All Processes and Contexts tracked by the BadContexts object will be destroyed also.
|
||||
*/
|
||||
~BadContexts();
|
||||
|
||||
/**
|
||||
* Test if a Context is among the invalidated Contexts
|
||||
* @param c pointer to a Context to be checked
|
||||
* @return true if the Context is among the invalidated. false otherwise.
|
||||
*/
|
||||
bool Contains(Context* c);
|
||||
|
||||
/**
|
||||
* Test if a Process is among the invalidated Processes/Contexts
|
||||
* @param p pointer to a Process to be checked
|
||||
* @see DFHack::Process
|
||||
* @return true if the Process is among the invalidated. false otherwise.
|
||||
*/
|
||||
bool Contains(Process* p);
|
||||
|
||||
// TODO: Add excise(Context *) method
|
||||
|
||||
/**
|
||||
* Get the number of tracked invalid contexts.
|
||||
* @return Number of tracked invalid contexts
|
||||
*/
|
||||
uint32_t size();
|
||||
|
||||
/**
|
||||
* Get an invalid Context by index
|
||||
* @param index index of the invalid Context to be returned
|
||||
* @return pointer to an invalid Context
|
||||
*/
|
||||
Context * operator[](uint32_t index);
|
||||
};
|
||||
} // namespace DFHack
|
||||
#endif // CONTEXTMANAGER_H_INCLUDED
|
@ -1,19 +0,0 @@
|
||||
/*
|
||||
This file is a wrapper for stdint.h
|
||||
|
||||
Visual Studio doesn't have stdint.h
|
||||
|
||||
stdint.h is part of the C99 standard. It's ancient and simply should be there. FAIL
|
||||
|
||||
You can turn off the include by defining SKIP_DFHACK_STDINT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef SKIP_DFHACK_STDINT
|
||||
#ifndef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include "DFstdint_win.h"
|
||||
#endif
|
||||
#endif
|
@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef DFHACK_TRANQUILITY
|
||||
#define DFHACK_TRANQUILITY
|
||||
|
||||
// This is here to keep MSVC from spamming the build output with nonsense
|
||||
// Call it public domain.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// don't spew nonsense
|
||||
#pragma warning( disable: 4251 )
|
||||
// don't display bogus 'deprecation' and 'unsafe' warnings.
|
||||
// See the idiocy: http://msdn.microsoft.com/en-us/magazine/cc163794.aspx
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#define _SCL_SECURE_NO_DEPRECATE
|
||||
#pragma warning( disable: 4996 )
|
||||
// Let me demonstrate:
|
||||
/**
|
||||
* [peterix@peterix dfhack]$ man wcscpy_s
|
||||
* No manual entry for wcscpy_s
|
||||
*
|
||||
* Proprietary extensions.
|
||||
*/
|
||||
// disable stupid
|
||||
#pragma warning( disable: 4800 )
|
||||
// disable more stupid
|
||||
#pragma warning( disable: 4068 )
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,246 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef PROCESS_H_INCLUDED
|
||||
#define PROCESS_H_INCLUDED
|
||||
|
||||
#include "DFPragma.h"
|
||||
#include "DFExport.h"
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
class VersionInfo;
|
||||
class Process;
|
||||
class Window;
|
||||
class DFVector;
|
||||
|
||||
/**
|
||||
* A type for storing an extended OS Process ID (combines PID and the time the process was started for unique identification)
|
||||
* \ingroup grp_context
|
||||
*/
|
||||
struct ProcessID
|
||||
{
|
||||
ProcessID(const uint64_t _time, const uint64_t _pid): time(_time), pid(_pid){};
|
||||
bool operator==(const ProcessID &other) const
|
||||
{
|
||||
return (other.time == time && other.pid == pid);
|
||||
}
|
||||
bool operator< (const ProcessID& ms) const
|
||||
{
|
||||
if (time < ms.time)
|
||||
return true;
|
||||
else if(time == ms.time)
|
||||
return pid < ms.pid ;
|
||||
return false;
|
||||
}
|
||||
uint64_t time;
|
||||
uint64_t pid;
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure describing a section of virtual memory inside a process
|
||||
* \ingroup grp_context
|
||||
*/
|
||||
struct DFHACK_EXPORT t_memrange
|
||||
{
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
// memory range name (if any)
|
||||
char name[1024];
|
||||
// permission to read
|
||||
bool read : 1;
|
||||
// permission to write
|
||||
bool write : 1;
|
||||
// permission to execute
|
||||
bool execute : 1;
|
||||
// is a shared region
|
||||
bool shared : 1;
|
||||
inline bool isInRange( uint64_t address)
|
||||
{
|
||||
if (address >= start && address < end) return true;
|
||||
return false;
|
||||
}
|
||||
bool valid;
|
||||
uint8_t * buffer;
|
||||
};
|
||||
struct t_vecTriplet
|
||||
{
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
uint32_t alloc_end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allows low-level access to the memory of an OS process. OS processes can be enumerated by \ref ProcessEnumerator
|
||||
* \ingroup grp_context
|
||||
*/
|
||||
class DFHACK_EXPORT Process
|
||||
{
|
||||
protected:
|
||||
std::map<uint32_t, std::string> classNameCache;
|
||||
|
||||
public:
|
||||
/// this is the single most important destructor ever. ~px
|
||||
virtual ~Process(){};
|
||||
/// Set up stuff so we can read memory, suspends synchronously
|
||||
virtual bool attach() = 0;
|
||||
/// detach from DF, resume its execution if it's suspended
|
||||
virtual bool detach() = 0;
|
||||
/**
|
||||
* synchronous suspend
|
||||
* waits for DF to be actually suspended,
|
||||
* this might take a while depending on implementation
|
||||
*/
|
||||
virtual bool suspend() = 0;
|
||||
/// asynchronous suspend to use together with polling and timers
|
||||
virtual bool asyncSuspend() = 0;
|
||||
/// resume DF execution
|
||||
virtual bool resume() = 0;
|
||||
/// force-resume DF execution
|
||||
virtual bool forceresume() = 0;
|
||||
|
||||
/// read a 8-byte integer
|
||||
uint64_t readQuad(const uint32_t address) { uint64_t result; readQuad(address, result); return result; }
|
||||
/// read a 8-byte integer
|
||||
virtual void readQuad(const uint32_t address, uint64_t & value) = 0;
|
||||
/// write a 8-byte integer
|
||||
virtual void writeQuad(const uint32_t address, const uint64_t value) = 0;
|
||||
|
||||
/// read a 4-byte integer
|
||||
uint32_t readDWord(const uint32_t address) { uint32_t result; readDWord(address, result); return result; }
|
||||
/// read a 4-byte integer
|
||||
virtual void readDWord(const uint32_t address, uint32_t & value) = 0;
|
||||
/// write a 4-byte integer
|
||||
virtual void writeDWord(const uint32_t address, const uint32_t value) = 0;
|
||||
|
||||
/// read a float
|
||||
float readFloat(const uint32_t address) { float result; readFloat(address, result); return result; }
|
||||
/// write a float
|
||||
virtual void readFloat(const uint32_t address, float & value) = 0;
|
||||
|
||||
/// read a 2-byte integer
|
||||
uint16_t readWord(const uint32_t address) { uint16_t result; readWord(address, result); return result; }
|
||||
/// read a 2-byte integer
|
||||
virtual void readWord(const uint32_t address, uint16_t & value) = 0;
|
||||
/// write a 2-byte integer
|
||||
virtual void writeWord(const uint32_t address, const uint16_t value) = 0;
|
||||
|
||||
/// read a byte
|
||||
uint8_t readByte(const uint32_t address) { uint8_t result; readByte(address, result); return result; }
|
||||
/// read a byte
|
||||
virtual void readByte(const uint32_t address, uint8_t & value) = 0;
|
||||
/// write a byte
|
||||
virtual void writeByte(const uint32_t address, const uint8_t value) = 0;
|
||||
|
||||
/// read an arbitrary amount of bytes
|
||||
virtual void read( uint32_t address, uint32_t length, uint8_t* buffer) = 0;
|
||||
/// write an arbitrary amount of bytes
|
||||
virtual void write(uint32_t address, uint32_t length, uint8_t* buffer) = 0;
|
||||
|
||||
/// read an STL string
|
||||
virtual const std::string readSTLString (uint32_t offset) = 0;
|
||||
/// read an STL string
|
||||
virtual size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) = 0;
|
||||
/**
|
||||
* write an STL string
|
||||
* @return length written
|
||||
*/
|
||||
virtual size_t writeSTLString(const uint32_t address, const std::string writeString) = 0;
|
||||
/**
|
||||
* attempt to copy a string from source address to target address. may truncate or leak, depending on platform
|
||||
* @return length copied
|
||||
*/
|
||||
virtual size_t copySTLString(const uint32_t address, const uint32_t target)
|
||||
{
|
||||
return writeSTLString(target, readSTLString(address));
|
||||
}
|
||||
|
||||
/// read a STL vector
|
||||
virtual void readSTLVector(const uint32_t address, t_vecTriplet & triplet) = 0;
|
||||
virtual void writeSTLVector(const uint32_t address, t_vecTriplet & triplet) = 0;
|
||||
/// get class name of an object with rtti/type info
|
||||
virtual std::string doReadClassName(uint32_t vptr) = 0;
|
||||
|
||||
std::string readClassName(uint32_t vptr)
|
||||
{
|
||||
std::map<uint32_t, std::string>::iterator it = classNameCache.find(vptr);
|
||||
if (it != classNameCache.end())
|
||||
return it->second;
|
||||
return classNameCache[vptr] = doReadClassName(vptr);
|
||||
}
|
||||
|
||||
/// read a null-terminated C string
|
||||
virtual const std::string readCString (uint32_t offset) = 0;
|
||||
|
||||
/// @return true if the process is suspended
|
||||
virtual bool isSuspended() = 0;
|
||||
/// @return true if the process is attached
|
||||
virtual bool isAttached() = 0;
|
||||
/// @return true if the process is identified -- has a Memory.xml entry
|
||||
virtual bool isIdentified() = 0;
|
||||
/// @return true if this is a Process snapshot
|
||||
virtual bool isSnapshot() { return false; };
|
||||
|
||||
/// find the thread IDs of the process
|
||||
virtual bool getThreadIDs(std::vector<uint32_t> & threads ) = 0;
|
||||
/// get virtual memory ranges of the process (what is mapped where)
|
||||
virtual void getMemRanges(std::vector<t_memrange> & ranges ) = 0;
|
||||
|
||||
/// get the flattened Memory.xml entry of this process
|
||||
virtual VersionInfo *getDescriptor() = 0;
|
||||
/// get the DF Process ID
|
||||
virtual int getPID() = 0;
|
||||
/// get the DF Process FilePath
|
||||
virtual std::string getPath() = 0;
|
||||
/// get module index by name and version. bool 1 = error
|
||||
virtual bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) = 0;
|
||||
/// get the SHM start if available
|
||||
virtual char * getSHMStart (void) = 0;
|
||||
/// set a SHM command and wait for a response, return 0 on error or throw exception
|
||||
virtual bool SetAndWait (uint32_t state) = 0;
|
||||
};
|
||||
|
||||
class DFHACK_EXPORT ClassNameCheck
|
||||
{
|
||||
std::string name;
|
||||
mutable uint32_t vptr;
|
||||
public:
|
||||
ClassNameCheck() : vptr(0) {};
|
||||
ClassNameCheck(std::string _name) : name(_name), vptr(0) {};
|
||||
ClassNameCheck &operator= (const ClassNameCheck &b)
|
||||
{
|
||||
name = b.name; vptr = b.vptr; return *this;
|
||||
}
|
||||
bool operator() (Process *p, uint32_t ptr) const {
|
||||
if (vptr == 0 && p->readClassName(ptr) == name)
|
||||
vptr = ptr;
|
||||
return (vptr && vptr == ptr);
|
||||
};
|
||||
};
|
||||
}
|
||||
#endif
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef PROCESSMANAGER_H_INCLUDED
|
||||
#define PROCESSMANAGER_H_INCLUDED
|
||||
|
||||
#include "DFPragma.h"
|
||||
#include "DFExport.h"
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
class VersionInfo;
|
||||
class Process;
|
||||
class BadProcesses;
|
||||
/**
|
||||
* Process enumerator
|
||||
* Used to enumerate, create and destroy Processes.
|
||||
* @see DFHack::Process
|
||||
* \ingroup grp_context
|
||||
*/
|
||||
class DFHACK_EXPORT ProcessEnumerator
|
||||
{
|
||||
class Private;
|
||||
Private * const d;
|
||||
public:
|
||||
/**
|
||||
* Constructs the ProcessEnumerator.
|
||||
* @param path_to_xml the path to the file that defines memory offsets. (Memory.xml)
|
||||
*/
|
||||
ProcessEnumerator( string path_to_xml );
|
||||
|
||||
/**
|
||||
* Destroys the ProcessEnumerator.
|
||||
*/
|
||||
~ProcessEnumerator();
|
||||
|
||||
/**
|
||||
* Refresh the internal list of valid Process objects.
|
||||
* @param invalidated_processes pointer to a BadProcesses object. Not required. All processes are automatically destroyed if the object is not provided.
|
||||
* @see DFHack::BadProcesses
|
||||
* @return true if there's at least one valit Process
|
||||
*/
|
||||
bool Refresh(BadProcesses * invalidated_processes = 0);
|
||||
|
||||
/**
|
||||
* @return Number of tracked processes
|
||||
*/
|
||||
uint32_t size();
|
||||
|
||||
/**
|
||||
* Get a Process by index
|
||||
* @param index index of the Process to be returned
|
||||
* @return pointer to a Process. 0 if the index is out of range.
|
||||
*/
|
||||
Process * operator[](uint32_t index);
|
||||
|
||||
/**
|
||||
* Destroy all tracked Process objects
|
||||
* Normally called during object destruction. Calling this from outside ProcessManager is nasty.
|
||||
*/
|
||||
void purge(void);
|
||||
};
|
||||
|
||||
/**
|
||||
* Class used for holding a set of invalidated Process objects temporarily and destroy them safely.
|
||||
* @see DFHack::Process
|
||||
* \ingroup grp_context
|
||||
*/
|
||||
class DFHACK_EXPORT BadProcesses
|
||||
{
|
||||
class Private;
|
||||
Private * const d;
|
||||
void push_back(Process * p);
|
||||
friend class ProcessEnumerator;
|
||||
void clear();
|
||||
public:
|
||||
BadProcesses();
|
||||
/**
|
||||
* Destructor.
|
||||
* All Processes tracked by the BadProcesses object will be destroyed also.
|
||||
*/
|
||||
~BadProcesses();
|
||||
|
||||
/**
|
||||
* Test if a Process is among the invalidated Processes
|
||||
* @param p pointer to a Process to be checked
|
||||
* @return true if the Process is among the invalidated. false otherwise.
|
||||
*/
|
||||
bool Contains(Process* p);
|
||||
|
||||
/**
|
||||
* Remove a Process from the tracked invalidated Processes. Used by BadContexts.
|
||||
* @param p pointer to a Process to be excised
|
||||
* @see DFHack::BadContexts
|
||||
* @return true if the Process was among the invalidated. false otherwise.
|
||||
*/
|
||||
bool excise (Process* p);
|
||||
|
||||
/**
|
||||
* Get the number of tracked invalid contexts.
|
||||
* @return Number of tracked invalid contexts
|
||||
*/
|
||||
uint32_t size();
|
||||
|
||||
/**
|
||||
* Get an invalid Process by index
|
||||
* @param index index of the invalid Process to be returned
|
||||
* @return pointer to an invalid Process
|
||||
*/
|
||||
Process * operator[](uint32_t index);
|
||||
};
|
||||
}
|
||||
#endif // PROCESSMANAGER_H_INCLUDED
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef DFVECTOR_H_INCLUDED
|
||||
#define DFVECTOR_H_INCLUDED
|
||||
|
||||
#include "DFPragma.h"
|
||||
#include "DFExport.h"
|
||||
#include "VersionInfo.h"
|
||||
#include "DFProcess.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
template <class T>
|
||||
class DFHACK_EXPORT DfVector
|
||||
{
|
||||
private:
|
||||
Process *_p;
|
||||
uint32_t _address;
|
||||
t_vecTriplet t;
|
||||
t_vecTriplet t_read;
|
||||
uint32_t _size;// vector size
|
||||
|
||||
T * data; // cached data
|
||||
|
||||
bool isMetadataInSync()
|
||||
{
|
||||
t_vecTriplet t2;
|
||||
_p->readSTLVector(_address,t2);
|
||||
return (t2.start == t.start || t2.end == t.end || t2.alloc_end == t.alloc_end);
|
||||
}
|
||||
public:
|
||||
DfVector(Process *p, uint32_t address) : _p(p), _address(address)
|
||||
{
|
||||
p->readSTLVector(address,t);
|
||||
t_read = t;
|
||||
uint32_t byte_size = t.end - t.start;
|
||||
_size = byte_size / sizeof(T);
|
||||
data = new T[_size];
|
||||
p->read(t.start,byte_size, (uint8_t *)data);
|
||||
};
|
||||
DfVector()
|
||||
{
|
||||
data = 0;
|
||||
};
|
||||
~DfVector()
|
||||
{
|
||||
if(data)
|
||||
delete [] data;
|
||||
};
|
||||
// get offset of the specified index
|
||||
inline const T& operator[] (uint32_t index)
|
||||
{
|
||||
// FIXME: vector out of bounds exception
|
||||
//assert(index < size);
|
||||
return data[index];
|
||||
};
|
||||
// get offset of the specified index
|
||||
inline const T& at (uint32_t index)
|
||||
{
|
||||
//assert(index < size);
|
||||
return data[index];
|
||||
};
|
||||
// update value at index
|
||||
bool set(uint32_t index, T value)
|
||||
{
|
||||
if (index >= _size)
|
||||
return false;
|
||||
data[index] = value;
|
||||
_p->write(t.start + sizeof(T)*index, sizeof(T), (uint8_t *)&data[index]);
|
||||
return true;
|
||||
}
|
||||
// remove value
|
||||
bool remove(uint32_t index)
|
||||
{
|
||||
if (index >= _size || !isMetadataInSync())
|
||||
return false;
|
||||
// Remove the item
|
||||
_size--;
|
||||
t.end -= sizeof(T);
|
||||
int tail = (_size-index)*sizeof(T);
|
||||
memmove(&data[index], &data[index+1], tail);
|
||||
// Write back the data
|
||||
if (tail)
|
||||
_p->write(t.start + sizeof(T)*index, tail, (uint8_t *)&data[index]);
|
||||
_p->writeSTLVector(_address,t);
|
||||
return true;
|
||||
}
|
||||
// get vector size
|
||||
inline uint32_t size ()
|
||||
{
|
||||
return _size;
|
||||
};
|
||||
// get vector start
|
||||
inline uint32_t start ()
|
||||
{
|
||||
return t.start;
|
||||
};
|
||||
// get vector end
|
||||
inline uint32_t end ()
|
||||
{
|
||||
return t.end;
|
||||
};
|
||||
// get vector start
|
||||
inline const uint32_t alloc_end ()
|
||||
{
|
||||
return t.alloc_end;
|
||||
};
|
||||
};
|
||||
}
|
||||
#endif // DFVECTOR_H_INCLUDED
|
@ -1,247 +0,0 @@
|
||||
// ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2008 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The name of the author may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_STDINT_H_ // [
|
||||
#define _MSC_STDINT_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
|
||||
// or compiler give many errors like this:
|
||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// Define _W64 macros to mark types changing their size, like intptr_t.
|
||||
#ifndef _W64
|
||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||
# define _W64 __w64
|
||||
# else
|
||||
# define _W64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// 7.18.1 Integer types
|
||||
|
||||
// 7.18.1.1 Exact-width integer types
|
||||
|
||||
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||
// realize that, e.g. char has the same size as __int8
|
||||
// so we give up on __intX for them.
|
||||
#if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#endif
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
|
||||
// 7.18.1.2 Minimum-width integer types
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
|
||||
// 7.18.1.3 Fastest minimum-width integer types
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
// 7.18.1.4 Integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
typedef signed __int64 intptr_t;
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else // _WIN64 ][
|
||||
typedef _W64 signed int intptr_t;
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.1.5 Greatest-width integer types
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
|
||||
// 7.18.2 Limits of specified-width integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
||||
|
||||
// 7.18.2.1 Limits of exact-width integer types
|
||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||
#define INT8_MAX _I8_MAX
|
||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define UINT8_MAX _UI8_MAX
|
||||
#define UINT16_MAX _UI16_MAX
|
||||
#define UINT32_MAX _UI32_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
|
||||
// 7.18.2.2 Limits of minimum-width integer types
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.3 Limits of fastest minimum-width integer types
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.4 Limits of integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
# define INTPTR_MIN INT64_MIN
|
||||
# define INTPTR_MAX INT64_MAX
|
||||
# define UINTPTR_MAX UINT64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define INTPTR_MIN INT32_MIN
|
||||
# define INTPTR_MAX INT32_MAX
|
||||
# define UINTPTR_MAX UINT32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.2.5 Limits of greatest-width integer types
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
// 7.18.3 Limits of other integer types
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define PTRDIFF_MIN _I64_MIN
|
||||
# define PTRDIFF_MAX _I64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define PTRDIFF_MIN _I32_MIN
|
||||
# define PTRDIFF_MAX _I32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#define SIG_ATOMIC_MIN INT_MIN
|
||||
#define SIG_ATOMIC_MAX INT_MAX
|
||||
|
||||
#ifndef SIZE_MAX // [
|
||||
# ifdef _WIN64 // [
|
||||
# define SIZE_MAX _UI64_MAX
|
||||
# else // _WIN64 ][
|
||||
# define SIZE_MAX _UI32_MAX
|
||||
# endif // _WIN64 ]
|
||||
#endif // SIZE_MAX ]
|
||||
|
||||
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
|
||||
#ifndef WCHAR_MIN // [
|
||||
# define WCHAR_MIN 0
|
||||
#endif // WCHAR_MIN ]
|
||||
#ifndef WCHAR_MAX // [
|
||||
# define WCHAR_MAX _UI16_MAX
|
||||
#endif // WCHAR_MAX ]
|
||||
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX _UI16_MAX
|
||||
|
||||
#endif // __STDC_LIMIT_MACROS ]
|
||||
|
||||
|
||||
// 7.18.4 Limits of other integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||
|
||||
// 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
#define INTMAX_C INT64_C
|
||||
#define UINTMAX_C UINT64_C
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
|
||||
#endif // _MSC_STDINT_H_ ]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue