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.cpp
develop
Petr Mrázek 2011-07-23 17:29:05 +02:00
commit bd9643c8cc
237 changed files with 10733 additions and 23085 deletions

10
.gitignore vendored

@ -1,6 +1,9 @@
# linux backup files
*~
#Kdevelop project file
*.kdev4
# compiled binaries
output/*
@ -13,6 +16,9 @@ library/private/config.h
# any build folders
build*/
nix
buntu
build/VC2010
#except for the real one
!build/
@ -26,6 +32,7 @@ build/doc
build/bin
build/library
build/tools
build/plugins
#ignore Kdevelop stuff
.kdev4
@ -40,4 +47,7 @@ dfhack/python/PyDFHack.egg-info
dfhack/python/build
dfhack/python/dist
# CPack stuff
build/CPack*Config.cmake
/cmakeall.bat

@ -1,287 +1,97 @@
# main project file. use it from a build sub-folder, see COMPILE for details
## some generic CMake magic
cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
PROJECT (dfhack)
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(dfhack)
SET(CMAKE_MODULE_PATH
${dfhack_SOURCE_DIR}/CMake/Modules
${CMAKE_MODULE_PATH}
)
if("${dfhack_SOURCE_DIR}" STREQUAL "${dfhack_BINARY_DIR}")
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(FATAL_ERROR "In-source builds are not allowed.")
endif()
SET(DFHACK_CONSISTENCY 1)
set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "5")
set(CPACK_PACKAGE_VERSION_PATCH "15")
set(DFHACK_VERSION_MAJOR "0")
set(DFHACK_VERSION_MINOR "31")
set(DFHACK_VERSION_PATCH "25")
set(DFHACK_REVISION "1")
set(DFHACK_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
set(CPACK_PACKAGE_VERSION ${DFHACK_VERSION})
set(CPACK_PACKAGE_NAME "dfhack")
SET(CPACK_PACKAGE_VENDOR "dethware.org")
SET(CPACK_PACKAGE_CONTACT "peterix@dethware.org")
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Memory hacks for Dwarf Fortress")
SET(CPACK_PACKAGE_DESCRIPTION
"DFHack is a Dwarf Fortress memory access library and a set of basic
tools using this library. The library is a work in progress, so things
might change as more tools are written for it.
.
It is an attempt to unite the various ways tools access DF memory and
allow for easier development of new tools.")
set(DFHACK_VERSION "${DFHACK_VERSION_MAJOR}.${DFHACK_VERSION_MINOR}.${DFHACK_VERSION_PATCH}")
## setting the build type
IF(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel.")
SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Release RelWithDebInfo.")
ENDIF()
## put everything in one big ugly directory to make MSVC and KDevelop debuggers happy
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${dfhack_BINARY_DIR}/bin")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${dfhack_BINARY_DIR}/bin")
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${dfhack_BINARY_DIR}/bin")
SET(DFHACK_OUTPUT_DIR "${dfhack_BINARY_DIR}/bin" CACHE STRING "Where should be the produced libraries and binaries stored.")
SET(DFHACK_PLUGIN_OUTPUT_DIR "${DFHACK_OUTPUT_DIR}/plugins")
## where to put things during the build (force MSVC to behave)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${DFHACK_OUTPUT_DIR})
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${DFHACK_OUTPUT_DIR})
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${DFHACK_OUTPUT_DIR})
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${DFHACK_OUTPUT_DIR})
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${DFHACK_OUTPUT_DIR})
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${DFHACK_OUTPUT_DIR})
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${DFHACK_OUTPUT_DIR})
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL ${DFHACK_OUTPUT_DIR})
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL ${DFHACK_OUTPUT_DIR})
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${DFHACK_OUTPUT_DIR})
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${DFHACK_OUTPUT_DIR})
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${DFHACK_OUTPUT_DIR})
## where to install things (after the build is done, classic 'make install' or package structure)
# the dfhack libraries will be installed here:
SET(DFHACK_LIBRARY_DESTINATION .)
# the dfhack tools will be installed here:
SET(DFHACK_BINARY_DESTINATION .)
# Memory.xml goes here:
SET(DFHACK_DATA_DESTINATION .)
# Plugins go here
SET(DFHACK_PLUGIN_DESTINATION plugins)
# Includes go here:
SET(DFHACK_INCLUDES_DESTINATION dev/include)
# the Windows .lib files go here:
IF(WIN32)
set (DFHACK_INST_DEFAULT "portable")
ELSE()
set (DFHACK_INST_DEFAULT "linux")
ENDIF()
SET( DFHACK_INSTALL ${DFHACK_INST_DEFAULT} CACHE STRING
"Choose the install type:
'portable' for a portable zip or tar.gz package (windows default)
'linux' for generic packaging and system installs on linux (linux default)
'ubuntu-10.10' for ubuntu maverick package.")
SET( MEMXML_DATA_PATH . CACHE PATH
"Path to a valid Memory.xml file.
This is baked into the library, so when you package DFHack for linux, set it to the right path.")
IF(${DFHACK_INSTALL} STREQUAL "portable")
# the dfhack libraries will be installed here:
SET(DFHACK_LIBRARY_DESTINATION .)
# the dfhack tools will be installed here:
SET(DFHACK_BINARY_DESTINATION .)
# Memory.xml goes here:
SET(DFHACK_DATA_DESTINATION .)
# Includes go here:
SET(DFHACK_INCLUDES_DESTINATION dev/include)
# the Windows .lib files go here:
IF(WIN32)
SET(DFHACK_DEVLIB_DESTINATION dev)
SET(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION .)
ENDIF()
IF(UNIX)
SET(CMAKE_INSTALL_RPATH "$ORIGIN")
ENDIF()
# documentation goes here:
SET(DFHACK_USERDOC_DESTINATION .)
SET(DFHACK_DEVDOC_DESTINATION dev)
SET(DFHACK_DOXYGEN_DESTINATION dev/doxygen)
ENDIF()
# generic linux package in a .tar.gz
IF(${DFHACK_INSTALL} STREQUAL "linux")
if(WIN32)
MESSAGE(FATAL_ERROR "WTF are you doing?")
endif()
# set RPATH to always point at the dfhack lib using relative path.
SET(CMAKE_INSTALL_RPATH "$ORIGIN/../lib/")
# the dfhack libraries will be installed here:
SET(DFHACK_LIBRARY_DESTINATION lib)
# the dfhack tools will be installed here:
SET(DFHACK_BINARY_DESTINATION bin)
# Memory.xml goes here:
SET(DFHACK_DATA_DESTINATION share/dfhack)
# Includes go here:
SET(DFHACK_INCLUDES_DESTINATION include)
# documentation goes here:
SET(DFHACK_USERDOC_DESTINATION share/dfhack/doc)
SET(DFHACK_DEVDOC_DESTINATION share/dfhack/doc)
SET(DFHACK_DOXYGEN_DESTINATION share/dfhack/doc/doxygen)
ENDIF()
IF(${DFHACK_INSTALL} STREQUAL "ubuntu-10.10" OR ${DFHACK_INSTALL} STREQUAL "debian")
if(WIN32)
MESSAGE(FATAL_ERROR "WTF are you doing?")
endif()
# set RPATH to always point at the dfhack lib using relative path.
SET(CMAKE_INSTALL_RPATH "$ORIGIN/../lib/")
# the dfhack libraries will be installed here:
SET(DFHACK_LIBRARY_DESTINATION usr/lib)
# the dfhack tools will be installed here:
SET(DFHACK_BINARY_DESTINATION usr/bin)
# Memory.xml goes here:
SET(DFHACK_DATA_DESTINATION usr/share/dfhack)
# Includes go here:
SET(DFHACK_INCLUDES_DESTINATION usr/include)
# documentation goes here:
SET(DFHACK_USERDOC_DESTINATION usr/share/dfhack/doc)
SET(DFHACK_DEVDOC_DESTINATION usr/share/dfhack/doc)
SET(DFHACK_DOXYGEN_DESTINATION usr/share/dfhack/doc/doxygen)
INSTALL(FILES
"${CMAKE_CURRENT_SOURCE_DIR}/package/${DFHACK_INSTALL}/99-dfhack.conf"
DESTINATION etc/sysctl.d)
ENDIF()
## some options for the user/developer to play with
OPTION(BUILD_DFHACK_LIBRARY "Build the library. Needed for all the tools." ON)
OPTION(BUILD_DFHACK_C_BINDINGS "Build the C portion of the library." ON)
OPTION(BUILD_DFHACK_PYTHON_BINDINGS "Build/install the python wrapper." ON)
IF(WIN32)
OPTION(BUILD_DFHACK_DEVEL "Build the developer stuff." OFF)
ENDIF()
IF(UNIX)
OPTION(BUILD_DFHACK_DEVEL "Build the developer stuff." ON)
ENDIF()
OPTION(BUILD_DFHACK_DOXYGEN "Create doxygen documentation for developers" ON)
OPTION(BUILD_DFHACK_SUPPORTED "Build the supported tools." ON)
OPTION(BUILD_DFHACK_EXAMPLES "Build example tools" OFF)
OPTION(BUILD_DFHACK_PLAYGROUND "Build tools from the playground folder" OFF)
OPTION(BUILD_NO_CURSES "Don't build tools requiring curses" OFF)
include_directories (${dfhack_SOURCE_DIR}/library/include/)
include_directories (${dfhack_SOURCE_DIR}/library/shm/)
include_directories (${dfhack_SOURCE_DIR}/library/depends/argstream/)
include_directories (${dfhack_SOURCE_DIR}/library/depends/xgetopt/)
# handle curses library bull**** on multiple platforms.
IF(UNIX)
find_package(Curses QUIET)
if(Curses_FOUND)
add_library(curses SHARED IMPORTED)
set_property(TARGET curses PROPERTY IMPORTED_LOCATION ${Curses_LIBRARY})
include_directories (${Curses_INCLUDE_PATH})
endif()
ELSE()
add_library(curses SHARED IMPORTED)
set_property(TARGET curses PROPERTY IMPORTED_LOCATION ${dfhack_SOURCE_DIR}/pdcurses/pdcurses.dll)
set_property(TARGET curses PROPERTY IMPORTED_IMPLIB ${dfhack_SOURCE_DIR}/pdcurses/pdcurses.lib)
include_directories (${dfhack_SOURCE_DIR}/pdcurses)
add_custom_target( curses-copy
COMMAND "${CMAKE_COMMAND}" -E make_directory ${dfhack_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/
COMMAND "${CMAKE_COMMAND}" -E copy "${dfhack_SOURCE_DIR}/pdcurses/pdcurses.dll" ${dfhack_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/
DEPENDS "${dfhack_SOURCE_DIR}/pdcurses/pdcurses.dll")
SET(Curses_FOUND TRUE)
INSTALL(FILES "${dfhack_SOURCE_DIR}/pdcurses/pdcurses.dll" DESTINATION ${DFHACK_BINARY_DESTINATION})
SET(CMAKE_INSTALL_RPATH "$ORIGIN")
ENDIF()
# macro to save on typing in the tool subdirs
# builds a tool, links it to the dfhack lib and makes sure the dependency
# LOCAL_DEPNAME is built first, in case there is one
MACRO(DFHACK_TOOL TOOL_NAME TOOL_SOURCES)
ADD_EXECUTABLE(${TOOL_NAME} ${TOOL_SOURCES})
TARGET_LINK_LIBRARIES(${TOOL_NAME} dfhack)
if(DEFINED LOCAL_DEPNAME)
ADD_DEPENDENCIES(${TOOL_NAME} ${LOCAL_DEPNAME})
endif()
install(TARGETS
${TOOL_NAME}
RUNTIME DESTINATION ${DFHACK_BINARY_DESTINATION})
ENDMACRO()
# same as above builds a curses tool instead of plain terminal one.
MACRO(DFHACK_CURSES_TOOL TOOL_NAME TOOL_SOURCES)
IF(Curses_FOUND AND NOT BUILD_NO_CURSES)
ADD_EXECUTABLE(${TOOL_NAME} ${TOOL_SOURCES})
TARGET_LINK_LIBRARIES(${TOOL_NAME} dfhack curses)
if(DEFINED LOCAL_DEPNAME)
ADD_DEPENDENCIES(${TOOL_NAME} ${LOCAL_DEPNAME})
endif()
if(WIN32)
ADD_DEPENDENCIES(${TOOL_NAME} curses-copy)
ENDIF()
install(TARGETS
${TOOL_NAME}
RUNTIME DESTINATION ${DFHACK_BINARY_DESTINATION})
ELSE()
MESSAGE(STATUS "Wide-character ncurses library not found - " ${TOOL_NAME} "can't be built")
ENDIF()
ENDMACRO()
# documentation goes here:
SET(DFHACK_USERDOC_DESTINATION .)
SET(DFHACK_DEVDOC_DESTINATION dev)
SET(DFHACK_DOXYGEN_DESTINATION dev/doxygen)
## some options for the user/developer to play with
OPTION(BUILD_LIBRARY "Build the library that goes into DF." ON)
OPTION(BUILD_PLUGINS "Build the plugins." ON)
IF(BUILD_DFHACK_LIBRARY)
IF(BUILD_LIBRARY)
add_subdirectory (library)
IF(BUILD_DFHACK_PYTHON_BINDINGS)
MESSAGE("TODO: write CMakeLists.txt for the python things.")
ENDIF()
IF(BUILD_DFHACK_SUPPORTED)
add_subdirectory (tools/supported)
ENDIF()
IF(BUILD_DFHACK_EXAMPLES)
add_subdirectory (tools/examples)
ENDIF()
IF(BUILD_DFHACK_PLAYGROUND)
add_subdirectory (tools/playground)
ENDIF()
## install the default documentation files
install(FILES LICENSE Readme.html DESTINATION ${DFHACK_USERDOC_DESTINATION})
endif()
IF(BUILD_DFHACK_DOXYGEN AND BUILD_DFHACK_DEVEL)
add_subdirectory (doc)
ENDIF()
IF(BUILD_PLUGINS)
add_subdirectory (plugins)
endif()
IF(${DFHACK_INSTALL} STREQUAL "portable")
IF(UNIX)
# Packaging with CPack!
IF(UNIX)
SET(CPACK_GENERATOR "TGZ")
ENDIF()
IF(WIN32)
ENDIF()
IF(WIN32)
SET(CPACK_GENERATOR "ZIP")
# this includes the MSVC C++ DLLs in the package. Doesn't work with Express versions in general.
INCLUDE(InstallRequiredSystemLibraries)
ENDIF()
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${DFHACK_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
INCLUDE(CPack)
# we should be fine with the stuff DF already has packaged... so, commenting out
# INCLUDE(InstallRequiredSystemLibraries)
ENDIF()
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${DFHACK_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
INCLUDE(CPack)
#-------------------------------------------------------------------------------
# Figure out debian architecture
#-------------------------------------------------------------------------------
FUNCTION(GET_DEBIAN_ARCHITECTURE arch)
SET(dpkgarch)
FIND_PROGRAM(DPKG_CMD dpkg)
IF(NOT DPKG_CMD)
MESSAGE(STATUS "Can not find dpkg in your path, default to i386.")
SET(${arch} i386 PARENT_SCOPE)
ENDIF()
EXECUTE_PROCESS(COMMAND "${DPKG_CMD}" --print-architecture
OUTPUT_VARIABLE dpkgarch
OUTPUT_STRIP_TRAILING_WHITESPACE )
SET(${arch} ${dpkgarch} PARENT_SCOPE)
ENDFUNCTION()
IF(${DFHACK_INSTALL} STREQUAL "ubuntu-10.10" OR ${DFHACK_INSTALL} STREQUAL "debian")
SET(CPACK_GENERATOR "DEB")
#wtf, wtf, wtf. force them to be empty
set(CMAKE_INSTALL_PREFIX "" FORCE)
set(CPACK_INSTALL_PREFIX "")
SET(CPACK_PACKAGING_INSTALL_PREFIX "")
set(CPACK_SET_DESTDIR true)
SET(CPACK_DEBIAN_PACKAGE_SECTION "Games") # yep. magma.
SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") # very.
SET(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) # find deps automatically! hopefully... maybe...
SET(INSTSCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/package/${DFHACK_INSTALL}")
SET(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${INSTSCRIPT}/postinst;${INSTSCRIPT}/preinst;${INSTSCRIPT}/postrm")
GET_DEBIAN_ARCHITECTURE(PKG_ARCHITECTURE)
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${DFHACK_VERSION}-${DFHACK_REVISION}_${DFHACK_INSTALL}-${PKG_ARCHITECTURE}")
INCLUDE(CPack)
ENDIF()

@ -1,7 +1,8 @@
----------------------------------------------------------------------
License of dfhack
github.com/peterix/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
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
@ -22,62 +23,6 @@ must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
----------------------------------------------------------------------
License of library/include/dfhack/DFstdint_win.h
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.
----------------------------------------------------------------------------
License of argstream (used by some utilities for parsing command line params)
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
This library is used by:
tools/playground/catsplosion.cpp
tools/playground/digger.cpp
tools/supported/vdig.cpp
----------------------------------------------------------------------------
License of "RSA Data Security, Inc. MD5 Message-Digest Algorithm"
Used to identify DF binaries.
@ -171,3 +116,69 @@ 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.
------------------------------------------------------------------
* dirent.h - dirent API for Microsoft Visual Studio
*
* Copyright (C) 2006 Toni Ronkko
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* ``Software''), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------
Parts of dfhack are based on linenoise:
linenoise.c -- 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>
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.

File diff suppressed because it is too large Load Diff

@ -803,8 +803,9 @@
<Group name="GUI" description="Offsets used by the GUI module.">
<Address name="pause_state" description="a flag that determines if the game is paused."/>
<Address name="current_cursor_creature" description="A vector? of creatures currently under the cursor."/>
<Address name="interface" description="Pointer to the global interfacest object (gview symbol on Linux)."/>
<Address name="current_menu_state" description="A numeric value that describes the state of the current GUI element (switching between menus will change this)."/>
<Address name="view_screen" description="Pointer to the current view screen object (GUI screen)."/>
<Address name="hotkeys" description="Address where the array of hotkeys starts." />
</Group>
<Group name="Maps" description="Offsets used by the Maps module.">
<Address name="map_data" description="Pointer to the start of the map structure."/>
@ -927,6 +928,15 @@
</Group>
<Group name="Materials" description="Offsets used by the Materials module.">
<Address name="inorganics" description="Soil, stone, gems and metal."/>
<Group name="inorganic_extras">
<Offset name="ore_types" description="Vector of indexes of metals produced when ore is smelted"/>
<Offset name="ore_chances" description="Vector of percent chance of each type of metal being produced on smelting"/>
<Offset name="strand_types" description="Vector of indexes of metals produced when ore undergoes strand extraction"/>
<Offset name="strand_chances" description="Vector of percent chance of each type of metal being produced on strand extraction"/>
<Offset name="value" description="Meterial value"/>
<Offset name="wall_tile" description="Tile when material is a natural wall"/>
<Offset name="boulder_tile" description="Tile when material is a dug out stone"/>
</Group>
<Address name="organics_all" description="Wood and plant matter, mixed" />
<Address name="organics_plants" description="plant matter" />
<Address name="organics_trees" description="just wood" />
@ -989,11 +999,16 @@
<Offset name="custom_workshop_name"/>
<Offset name="custom_workshop_type"/>
</Group>
<Group name="Hotkeys">
<Address name="start"/>
<Offset name="mode"/>
<Offset name="coords"/>
<HexValue name="sizeof"/>
<Group name="Vermin">
<Group name="Spawn Points" description="vermin spawn points, including colonies">
<Address name="vector"/>
<Offset name="race"/>
<Offset name="type"/>
<Offset name="position"/>
<Offset name="in_use"/>
<Offset name="unknown"/>
<Offset name="countdown"/> to what???
</Group>
</Group>
<Group name="Items">
<!-- most of those seem completely unused! -->
@ -1022,6 +1037,7 @@
<Address name="current_weather" description="5x5 array of bytes for surrounding biomes. For each: 0=clear, 1=raining, 2=snowing." />
<Address name="game_mode" description="Current game mode" />
<Address name="control_mode" description="Current control mode" />
<Address name="save_folder" descript="Name of save folder of current game"/>
<!--<Address name="control_mode_copy" description="Copy of the control mode in DF memory" />-->
</Group>
<Group name="Legends">
@ -1057,6 +1073,9 @@
</Group>
</Group>
</Group>
<Group name="Notes" description="In-game notes">
<Address name="vector"/>
</Group>
</Offsets>
</Base>
@ -1132,8 +1151,7 @@
<Group name="GUI">
<Address name="pause_state" value="0x146e45f" />
<Address name="current_cursor_creature" value="0xae82cc" valid="false" />
<Address name="current_menu_state" value="0x017f6f38" />
<Address name="view_screen" value="0xae82cc" valid="false" />
<Address name="hotkeys" value="0x01476ecc" />
</Group>
<Group name="Maps">
<Address name="map_data" value="0x016AD718" />
@ -1305,18 +1323,12 @@
<Offset name="custom_workshop_name" value="0x4" />
<Offset name="custom_workshop_type" value="0x20" />
</Group>
<Group name="Hotkeys">
<Address name="start" value="0x01476ecc" />
<Offset name="mode" value="0x1C" />
<Offset name="coords" value="0x20" />
<HexValue name="sizeof" value="0x2C" />
</Group>
<!-- addresses from belal: vectors might need 8 subtracted from them
buildings 0x0166f9a8
constructions 0xffffffff
creatures 0x0166eccc
current_cursor_creature 0x00ae82cc
current_menu_state 0x017f6f38
cursor_xyz 0x0166ecd4
effects_vector 0x017f6da0
hotkey_start 0x01476ecc
@ -1332,7 +1344,6 @@
settlement_current 0xffffffff
settlements 0x016af4a4
translation_vector 0x016b0010
view_screen 0xffffffff
window_dims 0x017f5abc
window_x 0x00e32798
window_y 0x00e60838
@ -2216,7 +2227,8 @@
<Address name="control_mode" value="0xb33814" />
<Address name="game_mode" value="0xb33818"/>
<Address name="current_year" value="0xef6268" />
<Address name="current_tick" value="0xe17180" />
<!--<Address name="current_tick" value="0xe17180" />-->
<Address name="current_tick" value="0xec3170" />
<Address name="current_weather" value="0x14eb7a0" />
</Group>
<Group name="GUI">
@ -2244,11 +2256,27 @@
<PETimeStamp value="0x4D90764F" />
<MD5 value="6ada05fc94785b53efe6aa5728b3756b" />
<Offsets>
<Group name="GUI">
<Address name="hotkeys" value="0x14f5cc8" />
<Address name="interface" value="0x14f6070" />
<Address name="current_menu_state" value="0x14f5fac" />
</Group>
<Group name="Creatures">
<Group name="creature">
<Offset name="flags3" value="0xE8"/>
</Group>
</Group>
<Group name="Materials">
<Group name="inorganic_extras">
<Offset name="ore_types" value="0x18"/>
<Offset name="ore_chances" value="0x24"/>
<Offset name="strand_types" value="0x3c"/>
<Offset name="strand_chances" value="0x48"/>
<Offset name="value" value="0x17c"/>
<Offset name="wall_tile" value="0x20c"/>
<Offset name="boulder_tile" value="0x21e"/>
</Group>
</Group>
<Group name="Items" valid="true">
<Address name="items_vector" value="0x16c4540"/>
<Offset name="id" value="0x14"/>
@ -3022,6 +3050,12 @@
<MD5 value="fc15065c4d1977ca019c6dad220413d1" />
<Offsets>
WORLD: 0x93f77a0
<Group name="GUI">
<Address name="hotkeys" value="0x93f740c" />
<Address name="interface" value="0x8C3E900" />
<Address name="current_menu_state" value="0x93F756C" />
</Group>
<Group name="Creatures">
Maybe, possibly.
<Address name="current_civ" value="0x093f2b50 0x93f2cdc" />
@ -3031,6 +3065,28 @@
<Offset name="flags3" value="0x94"/>
</Group>
</Group>
<Group name="Materials">
<Group name="inorganic_extras">
<Offset name="ore_types" value="0x18"/>
<Offset name="ore_chances" value="0x24"/>
<Offset name="strand_types" value="0x3c"/>
<Offset name="strand_chances" value="0x48"/>
<Offset name="value" value="0x17c"/>
<Offset name="wall_tile" value="0x20c"/>
<Offset name="boulder_tile" value="0x21e"/>
</Group>
</Group>
<Group name="Vermin" valid="true">
<Group name="Spawn Points">
<Address name="vector" value="0x93f77c4"/>
<Offset name="race" value="0x0"/>
<Offset name="type" value="0x2"/>
<Offset name="position" value="0x4"/>
<Offset name="in_use" value="0xa"/>
<Offset name="unknown" value="0xb"/>
<Offset name="countdown" value="0xc"/>
</Group>
</Group>
<Group name="Position" valid="true">
<Address name="cursor_xyz" value="0x8c3de60"/>
</Group>
@ -3038,6 +3094,7 @@
<Address name="control_mode" value="0x8c3de90" />
<Address name="game_mode" value="0x8c3deA0" />
<Address name="current_weather" value="0x93F05E4" />
<Address name="save_folder" value="0x958a378" />
</Group>
<Group name="Items">
<Address name="items_vector" value="0x940b1fc" />
@ -3088,6 +3145,9 @@
<Group name="Vegetation">
<Address name="vector" value="0x940bd70" />
</Group>
<Group name="Notes">
<Address name="vector" value="0x93f635c"/>
</Group>
</Offsets>
</Version>
</DFHack>

@ -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

@ -1,45 +1,42 @@
if(NOT DEFINED DFHACK_CONSISTENCY)
MESSAGE(FATAL_ERROR "Please build the whole thing, not parts. You can turn parts on/off using options.")
ENDIF()
PROJECT (dfhack-library)
PROJECT (dfapi)
cmake_minimum_required(VERSION 2.8)
## build options
OPTION(BUILD_DEVEL "Install/package files required for development (For SDK)." OFF)
OPTION(BUILD_DOXYGEN "Create/install/package doxygen documentation for DFHack (For SDK)." OFF)
include_directories (include)
include_directories (depends/md5)
include_directories (depends/libnoise)
include_directories (depends/tinyxml)
include_directories (depends/argstream)
include_directories (private)
SET(PROJECT_HDRS_INTERNAL
private/ContextShared.h
private/Internal.h
private/SHMProcess.h
private/LinuxProcess.h
private/ProcessFactory.h
private/MicrosoftSTL.h
private/wdirent.h
)
SET(PROJECT_HDRS
include/DFHack.h
include/dfhack/DFContext.h
include/dfhack/DFContextManager.h
include/dfhack/DFError.h
include/dfhack/DFExport.h
include/dfhack/DFIntegers.h
include/dfhack/DFMiscUtils.h
include/dfhack/DFModule.h
include/dfhack/DFPragma.h
include/dfhack/DFProcess.h
include/dfhack/DFProcessEnumerator.h
include/dfhack/DFTileTypes.h
include/dfhack/DFTypes.h
include/dfhack/DFVector.h
include/dfhack/VersionInfoFactory.h
include/dfhack/Console.h
include/dfhack/Core.h
include/dfhack/Error.h
include/dfhack/Export.h
include/dfhack/FakeSDL.h
include/dfhack/MiscUtils.h
include/dfhack/Module.h
include/dfhack/Pragma.h
include/dfhack/Process.h
include/dfhack/TileTypes.h
include/dfhack/Types.h
include/dfhack/Vector.h
include/dfhack/VersionInfo.h
include/dfhack/VersionInfoFactory.h
include/dfhack/Virtual.h
include/dfhack/extra/MapExtras.h
include/dfhack/extra/termutil.h
include/dfhack/extra/stopwatch.h
include/dfhack/extra/termutil.h
include/dfhack/modules/Buildings.h
include/dfhack/modules/Constructions.h
include/dfhack/modules/Creatures.h
@ -48,41 +45,20 @@ include/dfhack/modules/Gui.h
include/dfhack/modules/Items.h
include/dfhack/modules/Maps.h
include/dfhack/modules/Materials.h
include/dfhack/modules/Notes.h
include/dfhack/modules/Translation.h
include/dfhack/modules/Vegetation.h
include/dfhack/modules/WindowIO.h
include/dfhack/modules/Vermin.h
include/dfhack/modules/World.h
)
SET(PROJECT_C_HDRS
include/DFHack_C.h
include/dfhack-c/DFProcess_C.h
include/dfhack-c/DFTypes_C.h
include/dfhack-c/DFTileTypes_C.h
include/dfhack-c/DFContext_C.h
include/dfhack-c/modules/Buildings_C.h
include/dfhack-c/modules/Constructions_C.h
include/dfhack-c/modules/Creatures_C.h
include/dfhack-c/modules/Gui_C.h
include/dfhack-c/modules/Items_C.h
include/dfhack-c/modules/Maps_C.h
include/dfhack-c/modules/Materials_C.h
include/dfhack-c/modules/Translation_C.h
include/dfhack-c/modules/Vegetation_C.h
include/dfhack-c/modules/WindowIO_C.h
include/dfhack-c/modules/World_C.h
)
SET(PROJECT_SRCS
Core.cpp
PluginManager.cpp
TileTypes.cpp
VersionInfo.cpp
VersionInfoFactory.cpp
DFContextManager.cpp
DFContext.cpp
DFTileTypes.cpp
DFProcessEnumerator.cpp
ContextShared.cpp
DFProcess-SHM.cpp
MicrosoftSTL.cpp
Virtual.cpp
depends/md5/md5.cpp
depends/md5/md5wrapper.cpp
@ -100,49 +76,29 @@ modules/Gui.cpp
modules/Items.cpp
modules/Maps.cpp
modules/Materials.cpp
modules/Notes.cpp
modules/Translation.cpp
modules/Vegetation.cpp
modules/Vermin.cpp
modules/World.cpp
)
SET(PROJECT_C_SRCS
DFContext_C.cpp
DFProcess_C.cpp
DFTypes_C.cpp
DFTileTypes_C.cpp
modules/Buildings_C.cpp
modules/Constructions_C.cpp
modules/Creatures_C.cpp
modules/Gui_C.cpp
modules/Items_C.cpp
modules/Maps_C.cpp
modules/Materials_C.cpp
modules/Translation_C.cpp
modules/Vegetation_C.cpp
modules/WindowIO_C.cpp
modules/World_C.cpp
)
SET(PROJECT_HDRS_LINUX
)
SET(PROJECT_HDRS_WINDOWS
include/dfhack/DFstdint_win.h
)
SET(PROJECT_SRCS_LINUX
DFProcess-linux.cpp
DFProcess-linux-base.cpp
DFProcess-linux-SHM.cpp
DFProcess-linux-wine.cpp
modules/WindowIO-linux.cpp
Console-linux.cpp
FakeSDL-linux.cpp
Process-linux.cpp
)
SET(PROJECT_SRCS_WINDOWS
DFProcess-windows.cpp
DFProcess-windows-SHM.cpp
modules/WindowIO-windows.cpp
Console-windows.cpp
FakeSDL-windows.cpp
Process-windows.cpp
)
IF(UNIX)
@ -153,30 +109,19 @@ ELSE()
LIST(APPEND PROJECT_SRCS ${PROJECT_SRCS_WINDOWS})
ENDIF()
IF(BUILD_DFHACK_C_BINDINGS)
LIST(APPEND PROJECT_HDRS ${PROJECT_C_HDRS})
LIST(APPEND PROJECT_SRCS ${PROJECT_C_SRCS})
ENDIF()
SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE )
LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS})
# Are we 64bit? (Damn you, ptrace()!)
IF( CMAKE_SIZEOF_VOID_P MATCHES 8 )
ADD_DEFINITIONS(-DHAVE_64_BIT)
ENDIF()
ADD_DEFINITIONS(-DMEMXML_DATA_PATH="${MEMXML_DATA_PATH}")
ADD_DEFINITIONS(-DBUILD_DFHACK_LIB)
IF(UNIX)
add_definitions(-DLINUX_BUILD)
find_library(X11_LIBRARY X11)
SET(CMAKE_CXX_FLAGS_DEBUG "-g -Wall")
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden")
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -m32")
SET(CMAKE_C_FLAGS "-fvisibility=hidden -m32")
SET(PROJECT_LIBS ${X11_LIBRARY} rt )
SET(PROJECT_LIBS rt )
ELSE()
IF(MSVC)
SET(PROJECT_LIBS psapi ${dfhack_SOURCE_DIR}/library/depends/ntdll/ntdll.lib)
@ -187,15 +132,40 @@ ENDIF()
ADD_LIBRARY(dfhack SHARED ${PROJECT_SRCS})
IF(WIN32)
SET_TARGET_PROPERTIES(dfhack PROPERTIES OUTPUT_NAME "SDL" )
ENDIF()
SET_TARGET_PROPERTIES(dfhack PROPERTIES DEBUG_POSTFIX "-debug" )
TARGET_LINK_LIBRARIES(dfhack ${PROJECT_LIBS})
ADD_CUSTOM_TARGET( memxmlcopy
ADD_CUSTOM_TARGET( prepare
DEPENDS ${dfhack_SOURCE_DIR}/Memory.xml
COMMAND ${CMAKE_COMMAND} -E make_directory ${dfhack_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/
COMMAND ${CMAKE_COMMAND} -E copy ${dfhack_SOURCE_DIR}/Memory.xml ${dfhack_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/)
ADD_DEPENDENCIES(dfhack memxmlcopy)
COMMAND ${CMAKE_COMMAND} -E make_directory ${DFHACK_OUTPUT_DIR}
COMMAND ${CMAKE_COMMAND} -E make_directory ${DFHACK_PLUGIN_OUTPUT_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${dfhack_SOURCE_DIR}/Memory.xml ${DFHACK_OUTPUT_DIR})
ADD_DEPENDENCIES(dfhack prepare)
# On linux, copy our version of the df launch script which sets LD_PRELOAD
IF(UNIX)
ADD_CUSTOM_TARGET( prepare_UNIX
DEPENDS ${dfhack_SOURCE_DIR}/package/linux/dfhack
COMMAND ${CMAKE_COMMAND} -E make_directory ${DFHACK_OUTPUT_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${dfhack_SOURCE_DIR}/package/linux/dfhack ${DFHACK_OUTPUT_DIR})
ADD_DEPENDENCIES(dfhack prepare_UNIX)
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/linux/dfhack
DESTINATION ${DFHACK_LIBRARY_DESTINATION})
ELSE()
# On windows, copy the renamed SDL so DF can still run.
ADD_CUSTOM_TARGET( prepare_WINDOWS
DEPENDS ${dfhack_SOURCE_DIR}/package/windows/SDLreal.dll
COMMAND ${CMAKE_COMMAND} -E make_directory ${DFHACK_OUTPUT_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${dfhack_SOURCE_DIR}/package/windows/SDLreal.dll ${DFHACK_OUTPUT_DIR})
ADD_DEPENDENCIES(dfhack prepare_WINDOWS)
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/windows/SDLreal.dll
DESTINATION ${DFHACK_LIBRARY_DESTINATION})
ENDIF()
install(TARGETS dfhack
LIBRARY DESTINATION ${DFHACK_LIBRARY_DESTINATION}
@ -203,14 +173,18 @@ install(TARGETS dfhack
install(FILES ${dfhack_SOURCE_DIR}/Memory.xml
DESTINATION ${DFHACK_DATA_DESTINATION}) #linux: share/dfhack
if(BUILD_DFHACK_DEVEL)
if(BUILD_DEVEL)
if(WIN32)
install(TARGETS dfhack
ARCHIVE DESTINATION ${DFHACK_DEVLIB_DESTINATION})
endif()
# note the ending '/'. This means *constents* of the directory are installed
# note the ending '/'. This means *contents* of the directory are installed
# without the '/', the directory itself is installed
install(DIRECTORY include/
DESTINATION ${DFHACK_INCLUDES_DESTINATION}
FILES_MATCHING PATTERN "*.h" ) #linux: include
# Building the docs
IF(BUILD_DOXYGEN)
add_subdirectory (doc)
ENDIF()
endif()

@ -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 *)&sections );
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,6 +1,6 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix)
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
@ -22,239 +22,42 @@ must not be misrepresented as being the original software.
distribution.
*/
/**
* This is the source for the DF <-> dfhack shm bridge,
* to be used with SDL 1.2 and DF 40d16. Windows sucks
* using hacks like this sucks even more
*/
#include <windows.h>
#include <stdarg.h>
#define DFhackCExport extern "C" __declspec(dllexport)
#include "dfhack/DFIntegers.h"
#include <windows.h>
#include <stdint.h>
#include <vector>
#include <string>
#include "shms.h"
#include "mod-core.h"
#include "dfhack/Core.h"
#include "dfhack/FakeSDL.h"
#include <stdio.h>
int errorstate = 0;
char *shm = 0;
int shmid = 0;
bool inited = 0;
HANDLE shmHandle = 0;
HANDLE DFSVMutex = 0;
HANDLE DFCLMutex[SHM_MAX_CLIENTS];
HANDLE DFCLSuspendMutex[SHM_MAX_CLIENTS];
int held_DFCLSuspendMutex[SHM_MAX_CLIENTS];
int numheld = SHM_MAX_CLIENTS;
bool FirstCall();
void OS_lockSuspendLock(int which)
{
if(numheld == SHM_MAX_CLIENTS)
return;
// lock not held by server and can be picked up. OK.
if(held_DFCLSuspendMutex[which] == 0)
{
uint32_t state = WaitForSingleObject(DFCLSuspendMutex[which],INFINITE);
if(state == WAIT_ABANDONED || state == WAIT_OBJECT_0)
{
held_DFCLSuspendMutex[which] = 1;
numheld++;
return;
}
// lock couldn't be picked up!
errorstate = 1;
MessageBox(0,"Suspend lock locking failed. Further communication disabled!","Error", MB_OK);
return;
}
errorstate = 1;
MessageBox(0,"Server tried to lock already locked suspend lock? Further communication disabled!","Error", MB_OK);
return;
}
void OS_releaseSuspendLock(int which)
{
/*
if(which >=0 && which < SHM_MAX_CLIENTS)
return;
/*
* Plugin loading functions
*/
if(numheld != SHM_MAX_CLIENTS)
{
MessageBox(0,"Locking system failure. Further communication disabled!","Error", MB_OK);
errorstate = 1;
return;
}
// lock hel by server and can be released -> OK
if(held_DFCLSuspendMutex[which] == 1 && ReleaseMutex(DFCLSuspendMutex[which]))
{
numheld--;
held_DFCLSuspendMutex[which] = 0;
}
// locked and not can't be released? FAIL!
else if (held_DFCLSuspendMutex[which] == 1)
{
MessageBox(0,"Suspend lock failed to unlock. Further communication disabled!","Error", MB_OK);
return;
}
}
void SHM_Init ( void )
{
// check that we do this only once per process
if(inited)
{
MessageBox(0,"SHM_Init was called twice or more!","FUN", MB_OK);
return;
}
inited = true;
char clmutexname [256];
char clsmutexname [256];
char shmname [256];
sprintf(shmname,"DFShm-%d",OS_getPID());
// create a locked server mutex
char svmutexname [256];
sprintf(svmutexname,"DFSVMutex-%d",OS_getPID());
DFSVMutex = CreateMutex( 0, 1, svmutexname);
if(DFSVMutex == 0)
{
MessageBox(0,"Server mutex creation failed. Further communication disabled!","Error", MB_OK);
errorstate = 1;
return;
}
// the mutex already existed. we don't want to know.
if(GetLastError() == ERROR_ALREADY_EXISTS)
{
MessageBox(0,"Server mutex already existed. Further communication disabled!","Error", MB_OK);
errorstate = 1;
return;
}
// create client and suspend mutexes
for(int i = 0; i < SHM_MAX_CLIENTS; i++)
{
sprintf(clmutexname,"DFCLMutex-%d-%d",OS_getPID(),i);
sprintf(clsmutexname,"DFCLSuspendMutex-%d-%d",OS_getPID(),i);
DFCLMutex[i] = CreateMutex( 0, 0, clmutexname); // client mutex, not held
DFCLSuspendMutex[i] = CreateMutex( 0, 1, clsmutexname); // suspend mutexes held on start
held_DFCLSuspendMutex[i] = 1;
if(DFCLMutex[i] == 0 || DFCLSuspendMutex[i] == 0 || GetLastError() == ERROR_ALREADY_EXISTS)
{
MessageBox(0,"Client mutex creation failed. Close all tools before starting DF.","Error", MB_OK);
errorstate = 1;
return;
}
}
// create virtual memory mapping
shmHandle = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,SHM_SIZE,shmname);
// if can't create or already exists -> nothing happens
if(GetLastError() == ERROR_ALREADY_EXISTS)
{
MessageBox(0,"SHM bridge already in use","Error", MB_OK);
errorstate = 1;
return;
}
if(!shmHandle)
{
MessageBox(0,"Couldn't create SHM bridge","Error", MB_OK);
errorstate = 1;
return;
}
// attempt to attach the created mapping
shm = (char *) MapViewOfFile(shmHandle,FILE_MAP_ALL_ACCESS, 0,0, SHM_SIZE);
if(shm)
{
// make sure we don't stall or do crazy stuff
for(int i = 0; i < SHM_MAX_CLIENTS;i++)
{
((uint32_t *)shm)[i] = CORE_RUNNING;
}
// init modules :)
InitModules();
}
else
{
MessageBox(0,"Couldn't attach SHM bridge","Error", MB_OK);
errorstate = 1;
return;
}
}
void SHM_Destroy ( void )
{
if(errorstate)
return;
KillModules();
// get rid of all the locks
CloseHandle(DFSVMutex);
for(int i=0; i < SHM_MAX_CLIENTS; i++)
{
CloseHandle(DFCLSuspendMutex[i]);
CloseHandle(DFCLMutex[i]);
}
}
uint32_t OS_getPID()
{
return GetCurrentProcessId();
}
// TODO: move to some utils file
uint32_t OS_getAffinity()
{
HANDLE hProcess = GetCurrentProcess();
DWORD dwProcessAffinityMask, dwSystemAffinityMask;
GetProcessAffinityMask( hProcess, &dwProcessAffinityMask, &dwSystemAffinityMask );
return dwProcessAffinityMask;
}
// is the other side still there?
bool isValidSHM(int which)
namespace DFHack
{
// try if CL mutex is free (by locking client mutex)
uint32_t result = WaitForSingleObject(DFCLMutex[which],0);
switch (result)
DFLibrary * OpenPlugin (const char * filename)
{
case WAIT_ABANDONED:
case WAIT_OBJECT_0:
{
OS_lockSuspendLock(which);
ReleaseMutex(DFCLMutex[which]);
return false;
return (DFLibrary *) LoadLibrary(filename);
}
case WAIT_TIMEOUT:
void * LookupPlugin (DFLibrary * plugin ,const char * function)
{
// mutex is held by a process already
return true;
return (DFLibrary *) GetProcAddress((HMODULE)plugin, function);
}
default:
case WAIT_FAILED:
void ClosePlugin (DFLibrary * plugin)
{
// TODO: now how do I respond to this?
return false;
}
FreeLibrary((HMODULE) plugin);
}
}
/*************************************************************************/
// boring wrappers beyond this point. Only fix when broken
// extremely boring wrappers beyond this point. Only fix when broken
// function and variable pointer... we don't try to understand what SDL does here
typedef void * fPtr;
typedef void * vPtr;
// we don't know which of the SDL functions will be called first... so we
// just catch the first one and init all our function pointers at that time
bool FirstCall(void);
bool inited = false;
bool started_joysticks = false;
/// wrappers for SDL 1.2 functions used in 40d16
/***** Condition variables
@ -268,26 +71,26 @@ SDL_CondWait
SDL_DestroyCond
void SDLCALL SDL_DestroyCond(SDL_cond *cond);
*/
static vPtr (*_SDL_CreateCond)() = 0;
DFhackCExport vPtr SDL_CreateCond()
static SDL::Cond * (*_SDL_CreateCond)() = 0;
DFhackCExport SDL::Cond * SDL_CreateCond()
{
return _SDL_CreateCond();
}
static int (*_SDL_CondSignal)(vPtr cond) = 0;
DFhackCExport int SDL_CondSignal(vPtr cond)
static int (*_SDL_CondSignal)(SDL::Cond *) = 0;
DFhackCExport int SDL_CondSignal(SDL::Cond * cond)
{
return _SDL_CondSignal(cond);
}
static int (*_SDL_CondWait)(vPtr cond, vPtr mutex) = 0;
DFhackCExport int SDL_CondWait(vPtr cond, vPtr mutex)
static int (*_SDL_CondWait)(SDL::Cond *,SDL::Mutex *) = 0;
DFhackCExport int SDL_CondWait(SDL::Cond * cond, SDL::Mutex * mutex)
{
return _SDL_CondWait(cond, mutex);
}
static void (*_SDL_DestroyCond)(vPtr cond) = 0;
DFhackCExport void SDL_DestroyCond(vPtr cond)
static void (*_SDL_DestroyCond)(SDL::Cond * ) = 0;
DFhackCExport void SDL_DestroyCond(SDL::Cond * cond)
{
_SDL_DestroyCond(cond);
}
@ -301,20 +104,26 @@ SDL_mutexP
SDL_DestroyMutex
void SDLCALL SDL_DestroyMutex(SDL_mutex *mutex);
*/
static vPtr (*_SDL_CreateMutex)(void) = 0;
DFhackCExport vPtr SDL_CreateMutex(void)
static SDL::Mutex * (*_SDL_CreateMutex)(void) = 0;
DFhackCExport SDL::Mutex * SDL_CreateMutex(void)
{
return _SDL_CreateMutex();
}
static int (*_SDL_mutexP)(vPtr mutex) = 0;
DFhackCExport int SDL_mutexP(vPtr mutex)
static int (*_SDL_mutexP)(SDL::Mutex * mutex) = 0;
DFhackCExport int SDL_mutexP(SDL::Mutex * mutex)
{
return _SDL_mutexP(mutex);
}
static void (*_SDL_DestroyMutex)(vPtr mutex) = 0;
DFhackCExport void SDL_DestroyMutex(vPtr 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);
}
@ -585,10 +394,19 @@ DFhackCExport uint8_t * SDL_GetKeyState(int* numkeys)
return _SDL_GetKeyState(numkeys);
}
static int (*_SDL_PollEvent)(vPtr event) = 0;
DFhackCExport int SDL_PollEvent(vPtr event)
static int (*_SDL_PollEvent)(SDL::Event *) = 0;
DFhackCExport int SDL_PollEvent(SDL::Event * event)
{
return _SDL_PollEvent(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.
if(started_joysticks && event != 0)
{
DFHack::Core & c = DFHack::Core::getInstance();
return c.SDL_Event(event, orig_return);
}
return orig_return;
}
/***** error handling
@ -640,20 +458,20 @@ SDL_UnloadObject
extern DECLSPEC void SDLCALL SDL_UnloadObject(void *handle);
*/
static vPtr (*_SDL_LoadFunction)(void *handle, const char *name) = 0;
DFhackCExport vPtr SDL_LoadFunction(void *handle, const char *name)
static void * (*_SDL_LoadFunction)(SDL::Library *handle, const char *name) = 0;
DFhackCExport void * SDL_LoadFunction(SDL::Library *handle, const char *name)
{
return _SDL_LoadFunction(handle, name);
}
static vPtr (*_SDL_LoadObject)(const char *sofile) = 0;
DFhackCExport vPtr SDL_LoadObject(const char *sofile)
extern "C" static SDL::Library * (*_SDL_LoadObject)(const char *sofile) = 0;
DFhackCExport SDL::Library * SDL_LoadObject(const char *sofile)
{
return _SDL_LoadObject(sofile);
}
static void (*_SDL_UnloadObject)(vPtr handle) = 0;
DFhackCExport void SDL_UnloadObject(vPtr handle)
static void (*_SDL_UnloadObject)(SDL::Library * handle) = 0;
DFhackCExport void SDL_UnloadObject(SDL::Library * handle)
{
_SDL_UnloadObject(handle);
}
@ -720,6 +538,10 @@ DFhackCExport size_t SDL_strlcpy(char *dst, const char *src, size_t maxlen)
if(!_SDL_strlcpy)
{
HMODULE realSDLlib = LoadLibrary("SDLreal.dll");
if(!realSDLlib)
{
exit(-111);
}
_SDL_strlcpy = (size_t (*)(char*, const char*, size_t))GetProcAddress(realSDLlib,"SDL_strlcpy");
}
return _SDL_strlcpy(dst,src,maxlen);
@ -737,12 +559,8 @@ SDL_GL_SwapBuffers
static void (*_SDL_Quit)(void) = 0;
DFhackCExport void SDL_Quit(void)
{
fprintf(stderr,"Quitting!\n");
if(!errorstate)
{
SHM_Destroy();
errorstate = true;
}
DFHack::Core & c = DFHack::Core::getInstance();
c.Shutdown();
if(_SDL_Quit)
{
_SDL_Quit();
@ -751,15 +569,10 @@ DFhackCExport void SDL_Quit(void)
// this is supported from 0.31.04 forward
DFhackCExport int SDL_NumJoysticks(void)
{
if(errorstate)
return -1;
if(!inited)
{
SHM_Init();
return -2;
}
SHM_Act();
return -3;
DFHack::Core & c = DFHack::Core::getInstance();
int ret = c.Update();
started_joysticks = true;
return ret;
}
static void (*_SDL_GL_SwapBuffers)(void) = 0;
@ -798,8 +611,8 @@ DFhackCExport void *SDL_CreateSemaphore(uint32_t initial_value)
return _SDL_CreateSemaphore(initial_value);
}
static void * (*_SDL_CreateThread)(int (*fn)(void *), void *data) = 0;
DFhackCExport void *SDL_CreateThread(int (*fn)(void *), void *data)
static SDL::Thread * (*_SDL_CreateThread)(int (*fn)(void *), void *data) = 0;
DFhackCExport SDL::Thread *SDL_CreateThread(int (*fn)(void *), void *data)
{
if(!inited)
FirstCall();
@ -879,7 +692,7 @@ DFhackCExport uint32_t SDL_ThreadID(void)
return _SDL_ThreadID();
}
// this has to be thread-safe. Let's hope it is.
// FIXME: this has to be thread-safe.
bool FirstCall()
{
HMODULE realSDLlib = LoadLibrary("SDLreal.dll");
@ -889,17 +702,18 @@ bool FirstCall()
fprintf(stderr, "Can't load SDLreal.dll\n");
return 0;
}
fprintf(stderr, "FirstCall()\n");
// stuff for DF
_SDL_AddTimer = (void*(*)(uint32_t, void*, void*)) GetProcAddress(realSDLlib,"SDL_AddTimer");
_SDL_CondSignal = (int (*)(void*))GetProcAddress(realSDLlib,"SDL_CondSignal");
_SDL_CondWait = (int (*)(void*, void*))GetProcAddress(realSDLlib,"SDL_CondWait");
_SDL_CondSignal = (int (*)(SDL::Cond*))GetProcAddress(realSDLlib,"SDL_CondSignal");
_SDL_CondWait = (int (*)(SDL::Cond*, SDL::Mutex*))GetProcAddress(realSDLlib,"SDL_CondWait");
_SDL_ConvertSurface = (void*(*)(void*, void*, uint32_t))GetProcAddress(realSDLlib,"SDL_ConvertSurface");
_SDL_CreateCond = (void*(*)())GetProcAddress(realSDLlib,"SDL_CreateCond");
_SDL_CreateMutex = (void*(*)())GetProcAddress(realSDLlib,"SDL_CreateMutex");
_SDL_CreateCond = (SDL::Cond*(*)())GetProcAddress(realSDLlib,"SDL_CreateCond");
_SDL_CreateMutex = (SDL::Mutex*(*)())GetProcAddress(realSDLlib,"SDL_CreateMutex");
_SDL_CreateRGBSurface = (void*(*)(uint32_t, int, int, int, uint32_t, uint32_t, uint32_t, uint32_t))GetProcAddress(realSDLlib,"SDL_CreateRGBSurface");
_SDL_CreateRGBSurfaceFrom = (void*(*)(void*, int, int, int, int, uint32_t, uint32_t, uint32_t, uint32_t))GetProcAddress(realSDLlib,"SDL_CreateRGBSurfaceFrom");
_SDL_DestroyCond = (void (*)(void*))GetProcAddress(realSDLlib,"SDL_DestroyCond");
_SDL_DestroyMutex = (void (*)(void*))GetProcAddress(realSDLlib,"SDL_DestroyMutex");
_SDL_DestroyCond = (void (*)(SDL::Cond*))GetProcAddress(realSDLlib,"SDL_DestroyCond");
_SDL_DestroyMutex = (void (*)(SDL::Mutex*))GetProcAddress(realSDLlib,"SDL_DestroyMutex");
_SDL_EnableKeyRepeat = (int (*)(int, int))GetProcAddress(realSDLlib,"SDL_EnableKeyRepeat");
_SDL_EnableUNICODE = (int (*)(int))GetProcAddress(realSDLlib,"SDL_EnableUNICODE");
_SDL_GetVideoSurface = (void*(*)())GetProcAddress(realSDLlib,"SDL_GetVideoSurface");
@ -918,7 +732,7 @@ bool FirstCall()
_SDL_Flip = (int (*)( void * )) GetProcAddress(realSDLlib, "SDL_Flip");
_SDL_LockSurface = (int (*)(void*))GetProcAddress(realSDLlib,"SDL_LockSurface");
_SDL_MapRGB = (uint32_t (*)(void*, uint8_t, uint8_t, uint8_t))GetProcAddress(realSDLlib,"SDL_MapRGB");
_SDL_PollEvent = (int (*)(void*))GetProcAddress(realSDLlib,"SDL_PollEvent");
_SDL_PollEvent = (int (*)(SDL::Event*))GetProcAddress(realSDLlib,"SDL_PollEvent");
_SDL_Quit = (void (*)())GetProcAddress(realSDLlib,"SDL_Quit");
_SDL_RWFromFile = (void*(*)(const char*, const char*))GetProcAddress(realSDLlib,"SDL_RWFromFile");
_SDL_RemoveTimer = (bool (*)(void*))GetProcAddress(realSDLlib,"SDL_RemoveTimer");
@ -932,24 +746,25 @@ bool FirstCall()
_SDL_UpperBlit = (int (*)(void*, void*, void*, void*))GetProcAddress(realSDLlib,"SDL_UpperBlit");
_SDL_WM_SetCaption = (void (*)(const char*, const char*))GetProcAddress(realSDLlib,"SDL_WM_SetCaption");
_SDL_WM_SetIcon = (void (*)(void*, uint8_t*))GetProcAddress(realSDLlib,"SDL_WM_SetIcon");
_SDL_mutexP = (int (*)(void*))GetProcAddress(realSDLlib,"SDL_mutexP");
_SDL_mutexP = (int (*)(SDL::Mutex*))GetProcAddress(realSDLlib,"SDL_mutexP");
_SDL_mutexV = (int (*)(SDL::Mutex*))GetProcAddress(realSDLlib,"SDL_mutexV");
_SDL_strlcpy = (size_t (*)(char*, const char*, size_t))GetProcAddress(realSDLlib,"SDL_strlcpy");
// stuff for SDL_Image
_SDL_ClearError = (void (*)())GetProcAddress(realSDLlib,"SDL_ClearError");
_SDL_Error = (void (*)(int))GetProcAddress(realSDLlib,"SDL_Error");
_SDL_LoadFunction = (void*(*)(void*, const char*))GetProcAddress(realSDLlib,"SDL_LoadFunction");
_SDL_LoadObject = (void*(*)(const char*))GetProcAddress(realSDLlib,"SDL_LoadObject");
_SDL_LoadFunction = (void*(*)(SDL::Library*, const char*))GetProcAddress(realSDLlib,"SDL_LoadFunction");
_SDL_LoadObject = (SDL::Library*(*)(const char*))GetProcAddress(realSDLlib,"SDL_LoadObject");
_SDL_ReadBE32 = (uint32_t (*)(void*))GetProcAddress(realSDLlib,"SDL_ReadBE32");
_SDL_ReadLE16 = (uint16_t (*)(void*))GetProcAddress(realSDLlib,"SDL_ReadLE16");
_SDL_ReadLE32 = (uint32_t (*)(void*))GetProcAddress(realSDLlib,"SDL_ReadLE32");
_SDL_SetError = (void (*)(const char*, ...))GetProcAddress(realSDLlib,"SDL_SetError");
_SDL_UnloadObject = (void (*)(void*))GetProcAddress(realSDLlib,"SDL_UnloadObject");
_SDL_UnloadObject = (void (*)(SDL::Library*))GetProcAddress(realSDLlib,"SDL_UnloadObject");
_SDL_FillRect = (int (*)(void*,void*,uint32_t))GetProcAddress(realSDLlib,"SDL_FillRect");
// new in DF 0.31.04
_SDL_CreateSemaphore = (void* (*)(uint32_t))GetProcAddress(realSDLlib,"SDL_CreateSemaphore");
_SDL_CreateThread = (void* (*)(int (*fn)(void *), void *data))GetProcAddress(realSDLlib,"SDL_CreateThread");
_SDL_CreateThread = (SDL::Thread* (*)(int (*fn)(void *), void *data))GetProcAddress(realSDLlib,"SDL_CreateThread");
_SDL_Delay = (void (*)(uint32_t))GetProcAddress(realSDLlib,"SDL_Delay");
_SDL_DestroySemaphore = (void (*)(void *))GetProcAddress(realSDLlib,"SDL_DestroySemaphore");
_SDL_GetAppState = (uint8_t (*)(void))GetProcAddress(realSDLlib,"SDL_GetAppState");
@ -961,5 +776,7 @@ bool FirstCall()
_SDL_ThreadID = (uint32_t (*)(void))GetProcAddress(realSDLlib,"SDL_ThreadID");
fprintf(stderr,"Initized HOOKS!\n");
inited = true;
return 1;
}

@ -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();
}

@ -0,0 +1,358 @@
/*
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"
#define _WIN32_WINNT 0x0501 // needed for INPUT struct
#define WINVER 0x0501 // OpenThread(), PSAPI, Toolhelp32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winnt.h>
#include <psapi.h>
#include <tlhelp32.h>
typedef LONG NTSTATUS;
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
// FIXME: it is uncertain how these map to 64bit
typedef struct _DEBUG_BUFFER
{
HANDLE SectionHandle;
PVOID SectionBase;
PVOID RemoteSectionBase;
ULONG SectionBaseDelta;
HANDLE EventPairHandle;
ULONG Unknown[2];
HANDLE RemoteThreadHandle;
ULONG InfoClassMask;
ULONG SizeOfInfo;
ULONG AllocatedSize;
ULONG SectionSize;
PVOID ModuleInformation;
PVOID BackTraceInformation;
PVOID HeapInformation;
PVOID LockInformation;
PVOID Reserved[8];
} DEBUG_BUFFER, *PDEBUG_BUFFER;
typedef struct _DEBUG_HEAP_INFORMATION
{
ULONG Base; // 0×00
ULONG Flags; // 0×04
USHORT Granularity; // 0×08
USHORT Unknown; // 0x0A
ULONG Allocated; // 0x0C
ULONG Committed; // 0×10
ULONG TagCount; // 0×14
ULONG BlockCount; // 0×18
ULONG Reserved[7]; // 0x1C
PVOID Tags; // 0×38
PVOID Blocks; // 0x3C
} DEBUG_HEAP_INFORMATION, *PDEBUG_HEAP_INFORMATION;
// RtlQueryProcessDebugInformation.DebugInfoClassMask constants
#define PDI_MODULES 0x01
#define PDI_BACKTRACE 0x02
#define PDI_HEAPS 0x04
#define PDI_HEAP_TAGS 0x08
#define PDI_HEAP_BLOCKS 0x10
#define PDI_LOCKS 0x20
extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlQueryProcessDebugInformation( IN ULONG ProcessId, IN ULONG DebugInfoClassMask, IN OUT PDEBUG_BUFFER DebugBuffer);
extern "C" __declspec(dllimport) PDEBUG_BUFFER __stdcall RtlCreateQueryDebugBuffer( IN ULONG Size, IN BOOLEAN EventPair);
extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlDestroyQueryDebugBuffer( IN PDEBUG_BUFFER DebugBuffer);
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <string>
#include <map>
using namespace std;
#include "dfhack/VersionInfo.h"
#include "dfhack/VersionInfoFactory.h"
#include "dfhack/Error.h"
#include "dfhack/Process.h"
using namespace DFHack;
namespace DFHack
{
class PlatformSpecific
{
public:
PlatformSpecific()
{
base = 0;
sections = 0;
};
HANDLE my_handle;
vector <HANDLE> threads;
vector <HANDLE> stoppedthreads;
uint32_t my_pid;
IMAGE_NT_HEADERS pe_header;
IMAGE_SECTION_HEADER * sections;
uint32_t base;
};
}
Process::Process(VersionInfoFactory * factory)
{
HMODULE hmod = NULL;
DWORD needed;
bool found = false;
identified = false;
my_descriptor = NULL;
d = new PlatformSpecific();
// open process
d->my_pid = GetCurrentProcessId();
d->my_handle = GetCurrentProcess();
// try getting the first module of the process
if(EnumProcessModules(d->my_handle, &hmod, sizeof(hmod), &needed) == 0)
{
return; //if enumprocessModules fails, give up
}
// got base ;)
d->base = (uint32_t)hmod;
// read from this process
try
{
uint32_t pe_offset = Process::readDWord(d->base+0x3C);
read(d->base + pe_offset, sizeof(d->pe_header), (uint8_t *)&(d->pe_header));
const size_t sectionsSize = sizeof(IMAGE_SECTION_HEADER) * d->pe_header.FileHeader.NumberOfSections;
d->sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize);
read(d->base + pe_offset + sizeof(d->pe_header), sectionsSize, (uint8_t *)(d->sections));
}
catch (exception &)
{
return;
}
VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(d->pe_header.FileHeader.TimeDateStamp);
if(vinfo)
{
vector<uint32_t> threads_ids;
if(!getThreadIDs( threads_ids ))
{
// thread enumeration failed.
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(d->base);
// keep track of created memory_info object so we can destroy it later
my_descriptor->setParentProcess(this);
for(size_t i = 0; i < threads_ids.size();i++)
{
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads_ids[i]);
if(hThread)
d->threads.push_back(hThread);
else
cerr << "Unable to open thread :" << hex << (DWORD) threads_ids[i] << endl;
}
}
}
Process::~Process()
{
// destroy our rebased copy of the memory descriptor
delete my_descriptor;
for(size_t i = 0; i < d->threads.size(); i++)
CloseHandle(d->threads[i]);
if(d->sections != NULL)
free(d->sections);
}
bool Process::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->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 Process::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(d->my_pid, heaps);
// go through all the VM regions, convert them to our internal format
while (VirtualQueryEx(d->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(d->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(d->base == temp.start)
{
for(int i = 0; i < d->pe_header.FileHeader.NumberOfSections; i++)
{
char sectionName[9];
memcpy(sectionName,d->sections[i].Name,8);
sectionName[8] = 0;
string nm;
nm.append(temp.name);
nm.append(" : ");
nm.append(sectionName);
nameMap[temp.start + d->sections[i].VirtualAddress] = nm;
}
}
else
continue;
}
ranges.push_back(temp);
}
}
uint32_t Process::getBase()
{
if(d)
return d->base;
return 0x400000;
}
string Process::doReadClassName (void * vptr)
{
int rtti = readDWord((uint32_t)vptr - 0x4);
int typeinfo = readDWord(rtti + 0xC);
string raw = readCString(typeinfo + 0xC); // skips the .?AV
raw.resize(raw.length() - 2);// trim @@ from end
return raw;
}
string Process::getPath()
{
HMODULE hmod;
DWORD junk;
char String[255];
EnumProcessModules(d->my_handle, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle
GetModuleFileNameEx(d->my_handle,hmod,String,sizeof(String)); //get the filename from the module
string out(String);
return(out.substr(0,out.find_last_of("\\")));
}

@ -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
{

@ -1,6 +1,6 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
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
@ -22,6 +22,7 @@ must not be misrepresented as being the original software.
distribution.
*/
#include "Internal.h"
#include <string>
@ -31,8 +32,8 @@ distribution.
using namespace std;
#include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h"
#include "dfhack/DFProcess.h"
#include "dfhack/Error.h"
#include "dfhack/Process.h"
using namespace DFHack;
//Inital amount of space in levels vector (since we usually know the number, efficient!)
@ -972,7 +973,7 @@ void VersionInfo::setClassChild (t_class * parent, const char * name, const char
}
// FIXME: stupid. we need a better container
// FIXME: This in now DEPRECATED!
bool VersionInfo::resolveObjectToClassID(const uint32_t address, int32_t & classid)
{
uint32_t vtable = d->p->readDWord(address);
@ -989,7 +990,8 @@ bool VersionInfo::resolveObjectToClassID(const uint32_t address, int32_t & class
else// couldn't find?
{
// we set up the class for the first time
string classname = d->p->readClassName(vtable);
//FIXME: use actual pointers everywhere.
string classname = d->p->readClassName((void*)vtable);
d->classIDs[vtable] = cl = setClass(classname.c_str(),vtable);
}
// and isn't a multi-class
@ -1026,7 +1028,7 @@ bool VersionInfo::resolveObjectToClassID(const uint32_t address, int32_t & class
//ALERT: doesn't care about multiclasses
bool VersionInfo::resolveClassnameToVPtr(const string classname, uint32_t & vptr)
bool VersionInfo::resolveClassnameToVPtr(const string classname, void * & vptr)
{
// FIXME: another stupid search.
for(uint32_t i = 0;i< d->classes.size();i++)
@ -1034,7 +1036,7 @@ bool VersionInfo::resolveClassnameToVPtr(const string classname, uint32_t & vptr
//if(classes[i].)
if(d->classes[i]->classname == classname) // got class
{
vptr = d->classes[i]->vtable;
vptr = (void *) d->classes[i]->vtable;
return true;
}
}

@ -1,6 +1,6 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
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
@ -32,7 +32,7 @@ using namespace std;
#include "dfhack/VersionInfoFactory.h"
#include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h"
#include "dfhack/Error.h"
using namespace DFHack;
#include <tinyxml.h>
@ -168,13 +168,13 @@ void VersionInfoFactory::ParseVTable(TiXmlElement* vtable, VersionInfo* mem)
string type = pClassEntry->Value();
const char *cstr_name = pClassEntry->Attribute("name");
const char *cstr_vtable = pClassEntry->Attribute("vtable");
uint32_t vtable = 0;
uint32_t vtable_num = 0;
if(cstr_vtable)
vtable = strtol(cstr_vtable, NULL, 16);
vtable_num = strtol(cstr_vtable, NULL, 16);
// it's a simple class
if(type== "class")
{
mem->setClass(cstr_name, vtable);
mem->setClass(cstr_name, vtable_num);
}
// it's a multi-type class
else if (type == "multiclass")
@ -184,7 +184,7 @@ void VersionInfoFactory::ParseVTable(TiXmlElement* vtable, VersionInfo* mem)
uint32_t typeoffset = 0;
if(cstr_typeoffset)
typeoffset = strtol(cstr_typeoffset, NULL, 16);
t_class * mclass = mem->setClass(cstr_name, vtable, typeoffset);
t_class * mclass = mem->setClass(cstr_name, vtable_num, typeoffset);
// parse class sub-entries
pClassSubEntry = pClassEntry->FirstChildElement();
for(;pClassSubEntry;pClassSubEntry=pClassSubEntry->NextSiblingElement())

@ -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

@ -45,7 +45,7 @@
//----------------------------------------------------------------------
//STL includes
#include <string>
#include <dfhack/DFIntegers.h>
#include <stdint.h>
//----------------------------------------------------------------------
//typedefs
typedef unsigned char *POINTER;

@ -35,12 +35,7 @@ IF(DOXYGEN_FOUND)
# with DOXYGEN_SOURCE_DIR we fill a list of directories and later we write it into
# the Doxyfile with a REGEX REPLACE (see below)
SET( DOXYGEN_SOURCE_DIR
"${dfhack_SOURCE_DIR}/doc/index.dxgen"
"${dfhack_SOURCE_DIR}/library/include"
"${dfhack_SOURCE_DIR}/library/include/dfhack"
"${dfhack_SOURCE_DIR}/library/include/dfhack/modules"
"${dfhack_SOURCE_DIR}/library/include/dfhack-c"
"${dfhack_SOURCE_DIR}/library/include/dfhack-c/modules"
"${dfhack_SOURCE_DIR}/library"
)
STRING(REGEX REPLACE ";" " " CMAKE_DOXYGEN_INPUT_LIST "${DOXYGEN_SOURCE_DIR}")

@ -600,7 +600,7 @@ FILE_PATTERNS = *.cpp \
# should be searched for input files as well. Possible values are YES and NO.
# If left blank NO is used.
RECURSIVE = NO
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should
# excluded from the INPUT source files. This way you can easily exclude a
@ -628,7 +628,7 @@ EXCLUDE_PATTERNS =
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
EXCLUDE_SYMBOLS =
EXCLUDE_SYMBOLS = Private
# The EXAMPLE_PATH tag can be used to specify one or more files or
# directories that contain example code fragments that are included (see

@ -1,3 +1,27 @@
/*
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.
*/
#ifndef DFHACK_API_H
#define DFHACK_API_H
@ -19,14 +43,14 @@
#define DEPRECATED(func) func
#endif
// C99 integer types (used everywhere)
#include <stdint.h>
// DFHack core classes and types
#include "dfhack/DFIntegers.h"
#include "dfhack/DFError.h"
#include "dfhack/DFContextManager.h"
#include "dfhack/DFContext.h"
#include "dfhack/Error.h"
#include "dfhack/VersionInfo.h"
#include "dfhack/DFProcess.h"
#include "dfhack/DFTypes.h"
#include "dfhack/Process.h"
#include "dfhack/Types.h"
// DFHack modules
#include "dfhack/modules/Buildings.h"
@ -46,11 +70,11 @@
* Only for use of official DFHack tools!
*/
#ifdef DFHACK_WANT_MISCUTILS
#include "dfhack/DFMiscUtils.h"
#include "dfhack/MiscUtils.h"
#endif
// define this to get the static tiletype->properties mapping
#ifdef DFHACK_WANT_TILETYPES
#include "dfhack/DFTileTypes.h"
#include "dfhack/TileTypes.h"
#endif
#endif

@ -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