Merge branch 'master' of github.com:JapaMala/dfhack

develop
JapaMala 2014-06-13 21:16:31 +05:30
commit 2779290b70
164 changed files with 6297 additions and 1570 deletions

3
.gitignore vendored

@ -64,3 +64,6 @@ build/CPack*Config.cmake
# ctags file # ctags file
tags tags
# Mac OS X .DS_Store files
.DS_Store

10
.gitmodules vendored

@ -1,15 +1,15 @@
[submodule "plugins/stonesense"] [submodule "plugins/stonesense"]
path = plugins/stonesense path = plugins/stonesense
url = git://github.com/peterix/stonesense.git url = git://github.com/DFHack/stonesense.git
[submodule "plugins/isoworld"] [submodule "plugins/isoworld"]
path = plugins/isoworld path = plugins/isoworld
url = git://github.com/peterix/isoworld.git url = git://github.com/DFHack/isoworld.git
[submodule "plugins/df2mc"] [submodule "plugins/df2mc"]
path = plugins/df2mc path = plugins/df2mc
url = git://github.com/peterix/DF2MC.git url = git://github.com/DFHack/DF2MC.git
[submodule "library/xml"] [submodule "library/xml"]
path = library/xml path = library/xml
url = git://github.com/peterix/df-structures.git url = git://github.com/DFHack/df-structures.git
[submodule "depends/clsocket"] [submodule "depends/clsocket"]
path = depends/clsocket path = depends/clsocket
url = git://github.com/peterix/clsocket.git url = git://github.com/DFHack/clsocket.git

@ -3,13 +3,13 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.10: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils 0.11: http://docutils.sourceforge.net/" />
<title>Building DFHACK</title> <title>Building DFHACK</title>
<style type="text/css"> <style type="text/css">
/* /*
:Author: David Goodger (goodger@python.org) :Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7514 2012-09-14 14:27:12Z milde $ :Id: $Id: html4css1.css 7614 2013-02-21 15:55:51Z milde $
:Copyright: This stylesheet has been placed in the public domain. :Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils. Default cascading style sheet for the HTML output of Docutils.
@ -313,6 +313,21 @@ table.docutils th.field-name, table.docinfo th.docinfo-name {
white-space: nowrap ; white-space: nowrap ;
padding-left: 0 } padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% } font-size: 100% }
@ -333,26 +348,27 @@ ul.auto-toc {
<li><a class="reference internal" href="#how-to-get-the-code" id="id5">How to get the code</a></li> <li><a class="reference internal" href="#how-to-get-the-code" id="id5">How to get the code</a></li>
<li><a class="reference internal" href="#dependencies" id="id6">Dependencies</a></li> <li><a class="reference internal" href="#dependencies" id="id6">Dependencies</a></li>
<li><a class="reference internal" href="#build" id="id7">Build</a></li> <li><a class="reference internal" href="#build" id="id7">Build</a></li>
<li><a class="reference internal" href="#fixing-the-libstdc-version-bug" id="id8">Fixing the libstdc++ version bug</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#mac-os-x" id="id8">Mac OS X</a><ul> <li><a class="reference internal" href="#mac-os-x" id="id9">Mac OS X</a><ul>
<li><a class="reference internal" href="#snow-leopard-changes" id="id9">Snow Leopard Changes</a></li> <li><a class="reference internal" href="#snow-leopard-changes" id="id10">Snow Leopard Changes</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#windows" id="id10">Windows</a><ul> <li><a class="reference internal" href="#windows" id="id11">Windows</a><ul>
<li><a class="reference internal" href="#id1" id="id11">How to get the code</a></li> <li><a class="reference internal" href="#id1" id="id12">How to get the code</a></li>
<li><a class="reference internal" href="#id2" id="id12">Dependencies</a></li> <li><a class="reference internal" href="#id2" id="id13">Dependencies</a></li>
<li><a class="reference internal" href="#id3" id="id13">Build</a></li> <li><a class="reference internal" href="#id3" id="id14">Build</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#build-types" id="id14">Build types</a></li> <li><a class="reference internal" href="#build-types" id="id15">Build types</a></li>
<li><a class="reference internal" href="#using-the-library-as-a-developer" id="id15">Using the library as a developer</a><ul> <li><a class="reference internal" href="#using-the-library-as-a-developer" id="id16">Using the library as a developer</a><ul>
<li><a class="reference internal" href="#df-data-structure-definitions" id="id16">DF data structure definitions</a></li> <li><a class="reference internal" href="#df-data-structure-definitions" id="id17">DF data structure definitions</a></li>
<li><a class="reference internal" href="#remote-access-interface" id="id17">Remote access interface</a></li> <li><a class="reference internal" href="#remote-access-interface" id="id18">Remote access interface</a></li>
<li><a class="reference internal" href="#contributing-to-dfhack" id="id18">Contributing to DFHack</a><ul> <li><a class="reference internal" href="#contributing-to-dfhack" id="id19">Contributing to DFHack</a><ul>
<li><a class="reference internal" href="#coding-style" id="id19">Coding style</a></li> <li><a class="reference internal" href="#coding-style" id="id20">Coding style</a></li>
<li><a class="reference internal" href="#how-to-get-new-code-into-dfhack" id="id20">How to get new code into DFHack</a></li> <li><a class="reference internal" href="#how-to-get-new-code-into-dfhack" id="id21">How to get new code into DFHack</a></li>
<li><a class="reference internal" href="#memory-research" id="id21">Memory research</a></li> <li><a class="reference internal" href="#memory-research" id="id22">Memory research</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -407,9 +423,26 @@ extra options.</p>
<p>You can also use a cmake-friendly IDE like KDevelop 4 or the cmake-gui <p>You can also use a cmake-friendly IDE like KDevelop 4 or the cmake-gui
program.</p> program.</p>
</div> </div>
<div class="section" id="fixing-the-libstdc-version-bug">
<h2><a class="toc-backref" href="#id8">Fixing the libstdc++ version bug</a></h2>
<p>When compiling dfhack yourself, it builds against your system libc.
When Dwarf Fortress runs, it uses a libstdc++ shipped with the binary, which
is usually way older, and incompatible with your dfhack. This manifests with
the error message:</p>
<pre class="literal-block">
./libs/Dwarf_Fortress: /pathToDF/libs/libstdc++.so.6: version
`GLIBCXX_3.4.15' not found (required by ./hack/libdfhack.so)
</pre>
<p>To fix this, simply remove the libstdc++ shipped with DF, it will fall back
to your system lib and everything will work fine:</p>
<pre class="literal-block">
cd /path/to/DF/
rm libs/libstdc++.so.6
</pre>
</div>
</div> </div>
<div class="section" id="mac-os-x"> <div class="section" id="mac-os-x">
<h1><a class="toc-backref" href="#id8">Mac OS X</a></h1> <h1><a class="toc-backref" href="#id9">Mac OS X</a></h1>
<p>If you are building on 10.6, please read the subsection below titled &quot;Snow Leopard Changes&quot; FIRST.</p> <p>If you are building on 10.6, please read the subsection below titled &quot;Snow Leopard Changes&quot; FIRST.</p>
<ol class="arabic"> <ol class="arabic">
<li><p class="first">Download and unpack a copy of the latest DF</p> <li><p class="first">Download and unpack a copy of the latest DF</p>
@ -418,16 +451,27 @@ program.</p>
</li> </li>
<li><p class="first">Open Xcode, go to Preferences &gt; Downloads, and install the Command Line Tools.</p> <li><p class="first">Open Xcode, go to Preferences &gt; Downloads, and install the Command Line Tools.</p>
</li> </li>
<li><p class="first">Install MacPorts.</p> <li><p class="first">Install dependencies</p>
</li> <blockquote>
<li><p class="first">Install dependencies from MacPorts:</p> <p>Option 1: Using MacPorts:</p>
<ul> <blockquote>
<li><p class="first"><tt class="docutils literal">sudo port install gcc45 +universal cmake +universal <span class="pre">git-core</span> +universal</tt></p> <ul class="simple">
<p>This will take some time—maybe hours, depending on your machine.</p> <li><a class="reference external" href="http://www.macports.org/">Install MacPorts</a></li>
</li> <li>Run <tt class="docutils literal">sudo port install gcc45 +universal cmake +universal <span class="pre">git-core</span> +universal</tt>
<li><p class="first">At some point during this process, it may ask you to install a Java environment; let it do so.</p> This will take some time—maybe hours, depending on your machine.</li>
</li>
</ul> </ul>
<p>At some point during this process, it may ask you to install a Java environment; let it do so.</p>
</blockquote>
<p>Option 2: Using Homebrew:</p>
<blockquote>
<ul class="simple">
<li><a class="reference external" href="http://brew.sh/">Install Homebrew</a> and run:</li>
<li><tt class="docutils literal">brew install git</tt></li>
<li><tt class="docutils literal">brew install cmake</tt></li>
<li><tt class="docutils literal">brew install gcc45 <span class="pre">--enable-multilib</span></tt></li>
</ul>
</blockquote>
</blockquote>
</li> </li>
<li><p class="first">Install perl dependencies</p> <li><p class="first">Install perl dependencies</p>
<blockquote> <blockquote>
@ -451,12 +495,26 @@ git submodule init
git submodule update git submodule update
</pre> </pre>
</li> </li>
<li><p class="first">Set environment variables:</p>
</li>
</ol>
<blockquote>
<p>Macports:</p>
<pre class="literal-block">
export CC=/opt/local/bin/gcc-mp-4.5
export CXX=/opt/local/bin/g++-mp-4.5
</pre>
<p>Homebrew:</p>
<pre class="literal-block">
export CC=/usr/local/bin/gcc-4.5
export CXX=/usr/local/bin/g++-4.5
</pre>
</blockquote>
<ol class="arabic" start="8">
<li><p class="first">Build dfhack:</p> <li><p class="first">Build dfhack:</p>
<pre class="literal-block"> <pre class="literal-block">
mkdir build-osx mkdir build-osx
cd build-osx cd build-osx
export CC=/opt/local/bin/gcc-mp-4.5
export CXX=/opt/local/bin/g++-mp-4.5
cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/path/to/DF/directory cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/path/to/DF/directory
make make
make install make install
@ -464,7 +522,7 @@ make install
</li> </li>
</ol> </ol>
<div class="section" id="snow-leopard-changes"> <div class="section" id="snow-leopard-changes">
<h2><a class="toc-backref" href="#id9">Snow Leopard Changes</a></h2> <h2><a class="toc-backref" href="#id10">Snow Leopard Changes</a></h2>
<ol class="arabic"> <ol class="arabic">
<li><dl class="first docutils"> <li><dl class="first docutils">
<dt>Add a step 6.2a (before Install XML::LibXSLT)::</dt> <dt>Add a step 6.2a (before Install XML::LibXSLT)::</dt>
@ -487,10 +545,10 @@ make install
</div> </div>
</div> </div>
<div class="section" id="windows"> <div class="section" id="windows">
<h1><a class="toc-backref" href="#id10">Windows</a></h1> <h1><a class="toc-backref" href="#id11">Windows</a></h1>
<p>On Windows, DFHack replaces the SDL library distributed with DF.</p> <p>On Windows, DFHack replaces the SDL library distributed with DF.</p>
<div class="section" id="id1"> <div class="section" id="id1">
<h2><a class="toc-backref" href="#id11">How to get the code</a></h2> <h2><a class="toc-backref" href="#id12">How to get the code</a></h2>
<p>DFHack doesn't have any kind of system of code snapshots in place, so you will have to get code from the github repository using git. <p>DFHack doesn't have any kind of system of code snapshots in place, so you will have to get code from the github repository using git.
You will need some sort of Windows port of git, or a GUI. Some examples:</p> You will need some sort of Windows port of git, or a GUI. Some examples:</p>
<blockquote> <blockquote>
@ -511,13 +569,14 @@ git submodule update
<p>If you want to get really involved with the development, create an account on github, make a clone there and then use that as your remote repository instead. Detailed instructions are beyond the scope of this document. If you need help, join us on IRC (#dfhack channel on freenode).</p> <p>If you want to get really involved with the development, create an account on github, make a clone there and then use that as your remote repository instead. Detailed instructions are beyond the scope of this document. If you need help, join us on IRC (#dfhack channel on freenode).</p>
</div> </div>
<div class="section" id="id2"> <div class="section" id="id2">
<h2><a class="toc-backref" href="#id12">Dependencies</a></h2> <h2><a class="toc-backref" href="#id13">Dependencies</a></h2>
<p>First, you need <tt class="docutils literal">cmake</tt>. Get the win32 installer version from the official <p>First, you need <tt class="docutils literal">cmake</tt>. Get the win32 installer version from the official
site: <a class="reference external" href="http://www.cmake.org/cmake/resources/software.html">http://www.cmake.org/cmake/resources/software.html</a></p> site: <a class="reference external" href="http://www.cmake.org/cmake/resources/software.html">http://www.cmake.org/cmake/resources/software.html</a></p>
<p>It has the usual installer wizard. Make sure you let it add its binary folder <p>It has the usual installer wizard. Make sure you let it add its binary folder
to your binary search PATH so the tool can be later run from anywhere.</p> to your binary search PATH so the tool can be later run from anywhere.</p>
<p>You'll need a copy of Microsoft Visual C++ 2010. The Express version is sufficient. <p>You'll need a copy of Microsoft Visual C++ 2010. The Express version is sufficient.
Grab it from Microsoft's site.</p> Grab it from Microsoft's site.</p>
<p>You'll also need the Visual Studio 2010 SP1 update.</p>
<p>For the code generation parts, you'll need perl and XML::LibXML. You can install them like this:</p> <p>For the code generation parts, you'll need perl and XML::LibXML. You can install them like this:</p>
<ul class="simple"> <ul class="simple">
<li>download and install strawberry perl from <a class="reference external" href="http://strawberryperl.com/">http://strawberryperl.com/</a></li> <li>download and install strawberry perl from <a class="reference external" href="http://strawberryperl.com/">http://strawberryperl.com/</a></li>
@ -528,7 +587,7 @@ Grab it from Microsoft's site.</p>
<p>If you already have a different version of perl (for example the one from cygwin), you can run into some trouble. Either remove the other perl install from PATH, or install libxml and libxslt for it instead. Strawberry perl works though and has all the required packages.</p> <p>If you already have a different version of perl (for example the one from cygwin), you can run into some trouble. Either remove the other perl install from PATH, or install libxml and libxslt for it instead. Strawberry perl works though and has all the required packages.</p>
</div> </div>
<div class="section" id="id3"> <div class="section" id="id3">
<h2><a class="toc-backref" href="#id13">Build</a></h2> <h2><a class="toc-backref" href="#id14">Build</a></h2>
<p>There are several different batch files in the <tt class="docutils literal">build</tt> folder along with a script that's used for picking the DF path.</p> <p>There are several different batch files in the <tt class="docutils literal">build</tt> folder along with a script that's used for picking the DF path.</p>
<p>First, run set_df_path.vbs and point the dialog that pops up at your DF folder that you want to use for development. <p>First, run set_df_path.vbs and point the dialog that pops up at your DF folder that you want to use for development.
Next, run one of the scripts with <tt class="docutils literal">generate</tt> prefix. These create the MSVC solution file(s):</p> Next, run one of the scripts with <tt class="docutils literal">generate</tt> prefix. These create the MSVC solution file(s):</p>
@ -550,7 +609,7 @@ So pick either Release or RelWithDebInfo build and build the INSTALL target.</p>
</div> </div>
</div> </div>
<div class="section" id="build-types"> <div class="section" id="build-types">
<h1><a class="toc-backref" href="#id14">Build types</a></h1> <h1><a class="toc-backref" href="#id15">Build types</a></h1>
<p><tt class="docutils literal">cmake</tt> allows you to pick a build type by changing this <p><tt class="docutils literal">cmake</tt> allows you to pick a build type by changing this
variable: <tt class="docutils literal">CMAKE_BUILD_TYPE</tt></p> variable: <tt class="docutils literal">CMAKE_BUILD_TYPE</tt></p>
<pre class="literal-block"> <pre class="literal-block">
@ -562,7 +621,7 @@ cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE
'RelWithDebInfo'. 'Debug' is not available on Windows.</p> 'RelWithDebInfo'. 'Debug' is not available on Windows.</p>
</div> </div>
<div class="section" id="using-the-library-as-a-developer"> <div class="section" id="using-the-library-as-a-developer">
<h1><a class="toc-backref" href="#id15">Using the library as a developer</a></h1> <h1><a class="toc-backref" href="#id16">Using the library as a developer</a></h1>
<p>Currently, the most direct way to use the library is to write a plugin that can be loaded by it. <p>Currently, the most direct way to use the library is to write a plugin that can be loaded by it.
All the plugins can be found in the 'plugins' folder. There's no in-depth documentation All the plugins can be found in the 'plugins' folder. There's no in-depth documentation
on how to write one yet, but it should be easy enough to copy one and just follow the pattern.</p> on how to write one yet, but it should be easy enough to copy one and just follow the pattern.</p>
@ -580,29 +639,29 @@ The main license is zlib/libpng, some bits are MIT licensed, and some are BSD li
<p>Feel free to add your own extensions and plugins. Contributing back to <p>Feel free to add your own extensions and plugins. Contributing back to
the dfhack repository is welcome and the right thing to do :)</p> the dfhack repository is welcome and the right thing to do :)</p>
<div class="section" id="df-data-structure-definitions"> <div class="section" id="df-data-structure-definitions">
<h2><a class="toc-backref" href="#id16">DF data structure definitions</a></h2> <h2><a class="toc-backref" href="#id17">DF data structure definitions</a></h2>
<p>DFHack uses information about the game data structures, represented via xml files in the library/xml/ submodule.</p> <p>DFHack uses information about the game data structures, represented via xml files in the library/xml/ submodule.</p>
<p>Data structure layouts are described in files following the df.*.xml name pattern. This information is transformed by a perl script into C++ headers describing the structures, and associated metadata for the Lua wrapper. These headers and data are then compiled into the DFHack libraries, thus necessitating a compatibility break every time layouts change; in return it significantly boosts the efficiency and capabilities of DFHack code.</p> <p>Data structure layouts are described in files following the df.*.xml name pattern. This information is transformed by a perl script into C++ headers describing the structures, and associated metadata for the Lua wrapper. These headers and data are then compiled into the DFHack libraries, thus necessitating a compatibility break every time layouts change; in return it significantly boosts the efficiency and capabilities of DFHack code.</p>
<p>Global object addresses are stored in symbols.xml, which is copied to the dfhack release package and loaded as data at runtime.</p> <p>Global object addresses are stored in symbols.xml, which is copied to the dfhack release package and loaded as data at runtime.</p>
</div> </div>
<div class="section" id="remote-access-interface"> <div class="section" id="remote-access-interface">
<h2><a class="toc-backref" href="#id17">Remote access interface</a></h2> <h2><a class="toc-backref" href="#id18">Remote access interface</a></h2>
<p>DFHack supports remote access by exchanging Google protobuf messages via a TCP socket. Both the core and plugins can define remotely accessible methods. The <tt class="docutils literal"><span class="pre">dfhack-run</span></tt> command uses this interface to invoke ordinary console commands.</p> <p>DFHack supports remote access by exchanging Google protobuf messages via a TCP socket. Both the core and plugins can define remotely accessible methods. The <tt class="docutils literal"><span class="pre">dfhack-run</span></tt> command uses this interface to invoke ordinary console commands.</p>
<p>Currently the supported set of requests is limited, because the developers don't know what exactly is most useful.</p> <p>Currently the supported set of requests is limited, because the developers don't know what exactly is most useful.</p>
<p>Protocol client implementations exist for Java and C#.</p> <p>Protocol client implementations exist for Java and C#.</p>
</div> </div>
<div class="section" id="contributing-to-dfhack"> <div class="section" id="contributing-to-dfhack">
<h2><a class="toc-backref" href="#id18">Contributing to DFHack</a></h2> <h2><a class="toc-backref" href="#id19">Contributing to DFHack</a></h2>
<p>Several things should be kept in mind when contributing to DFHack.</p> <p>Several things should be kept in mind when contributing to DFHack.</p>
<div class="section" id="coding-style"> <div class="section" id="coding-style">
<h3><a class="toc-backref" href="#id19">Coding style</a></h3> <h3><a class="toc-backref" href="#id20">Coding style</a></h3>
<p>DFhack uses ANSI formatting and four spaces as indentation. Line <p>DFhack uses ANSI formatting and four spaces as indentation. Line
endings are UNIX. The files use UTF-8 encoding. Code not following this endings are UNIX. The files use UTF-8 encoding. Code not following this
won't make me happy, because I'll have to fix it. There's a good chance won't make me happy, because I'll have to fix it. There's a good chance
I'll make <em>you</em> fix it ;)</p> I'll make <em>you</em> fix it ;)</p>
</div> </div>
<div class="section" id="how-to-get-new-code-into-dfhack"> <div class="section" id="how-to-get-new-code-into-dfhack">
<h3><a class="toc-backref" href="#id20">How to get new code into DFHack</a></h3> <h3><a class="toc-backref" href="#id21">How to get new code into DFHack</a></h3>
<p>You can send patches or make a clone of the github repo and ask me on <p>You can send patches or make a clone of the github repo and ask me on
the IRC channel to pull your code in. I'll review it and see if there the IRC channel to pull your code in. I'll review it and see if there
are any problems. I'll fix them if they are minor.</p> are any problems. I'll fix them if they are minor.</p>
@ -612,7 +671,7 @@ this is also a good place to dump new ideas and/or bugs that need
fixing.</p> fixing.</p>
</div> </div>
<div class="section" id="memory-research"> <div class="section" id="memory-research">
<h3><a class="toc-backref" href="#id21">Memory research</a></h3> <h3><a class="toc-backref" href="#id22">Memory research</a></h3>
<p>If you want to do memory research, you'll need some tools and some knowledge. <p>If you want to do memory research, you'll need some tools and some knowledge.
In general, you'll need a good memory viewer and optionally something In general, you'll need a good memory viewer and optionally something
to look at machine code without getting crazy :)</p> to look at machine code without getting crazy :)</p>

@ -89,16 +89,24 @@ If you are building on 10.6, please read the subsection below titled "Snow Leopa
1. Download and unpack a copy of the latest DF 1. Download and unpack a copy of the latest DF
2. Install Xcode from Mac App Store 2. Install Xcode from Mac App Store
3. Open Xcode, go to Preferences > Downloads, and install the Command Line Tools. 3. Open Xcode, go to Preferences > Downloads, and install the Command Line Tools.
4. Install MacPorts. 4. Install dependencies
5. Install dependencies from MacPorts:
* ``sudo port install gcc45 +universal cmake +universal git-core +universal`` Option 1: Using MacPorts:
* `Install MacPorts <http://www.macports.org/>`_
* Run ``sudo port install gcc45 +universal cmake +universal git-core +universal``
This will take some time—maybe hours, depending on your machine. This will take some time—maybe hours, depending on your machine.
* At some point during this process, it may ask you to install a Java environment; let it do so. At some point during this process, it may ask you to install a Java environment; let it do so.
6. Install perl dependencies Option 2: Using Homebrew:
* `Install Homebrew <http://brew.sh/>`_ and run:
* ``brew install git``
* ``brew install cmake``
* ``brew install gcc45 --enable-multilib``
5. Install perl dependencies
1. ``sudo cpan`` 1. ``sudo cpan``
@ -108,19 +116,29 @@ If you are building on 10.6, please read the subsection below titled "Snow Leopa
2. ``install XML::LibXML`` 2. ``install XML::LibXML``
3. ``install XML::LibXSLT`` 3. ``install XML::LibXSLT``
7. Get the dfhack source:: 6. Get the dfhack source::
git clone https://github.com/danaris/dfhack.git git clone https://github.com/danaris/dfhack.git
cd dfhack cd dfhack
git submodule init git submodule init
git submodule update git submodule update
7. Set environment variables:
Macports::
export CC=/opt/local/bin/gcc-mp-4.5
export CXX=/opt/local/bin/g++-mp-4.5
Homebrew::
export CC=/usr/local/bin/gcc-4.5
export CXX=/usr/local/bin/g++-4.5
8. Build dfhack:: 8. Build dfhack::
mkdir build-osx mkdir build-osx
cd build-osx cd build-osx
export CC=/opt/local/bin/gcc-mp-4.5
export CXX=/opt/local/bin/g++-mp-4.5
cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/path/to/DF/directory cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/path/to/DF/directory
make make
make install make install
@ -174,6 +192,8 @@ to your binary search PATH so the tool can be later run from anywhere.
You'll need a copy of Microsoft Visual C++ 2010. The Express version is sufficient. You'll need a copy of Microsoft Visual C++ 2010. The Express version is sufficient.
Grab it from Microsoft's site. Grab it from Microsoft's site.
You'll also need the Visual Studio 2010 SP1 update.
For the code generation parts, you'll need perl and XML::LibXML. You can install them like this: For the code generation parts, you'll need perl and XML::LibXML. You can install them like this:
* download and install strawberry perl from http://strawberryperl.com/ * download and install strawberry perl from http://strawberryperl.com/

@ -3,13 +3,13 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.9.1: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils 0.11: http://docutils.sourceforge.net/" />
<title>Contributors</title> <title>Contributors</title>
<style type="text/css"> <style type="text/css">
/* /*
:Author: David Goodger (goodger@python.org) :Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7434 2012-05-11 21:06:27Z milde $ :Id: $Id: html4css1.css 7614 2013-02-21 15:55:51Z milde $
:Copyright: This stylesheet has been placed in the public domain. :Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils. Default cascading style sheet for the HTML output of Docutils.
@ -77,7 +77,7 @@ div.tip p.admonition-title {
div.attention p.admonition-title, div.caution p.admonition-title, div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title, div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title { div.warning p.admonition-title, .code .error {
color: red ; color: red ;
font-weight: bold ; font-weight: bold ;
font-family: sans-serif } font-family: sans-serif }
@ -253,13 +253,14 @@ pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ; margin-left: 2em ;
margin-right: 2em } margin-right: 2em }
pre.code .ln { /* line numbers */ pre.code .ln { color: grey; } /* line numbers */
color: grey; pre.code, code { background-color: #eeeeee }
} pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
.code { pre.code .literal.string, code .literal.string { color: #0C5404 }
background-color: #eeeeee pre.code .name.builtin, code .name.builtin { color: #352B84 }
} pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier { span.classifier {
font-family: sans-serif ; font-family: sans-serif ;
@ -312,6 +313,21 @@ table.docutils th.field-name, table.docinfo th.docinfo-name {
white-space: nowrap ; white-space: nowrap ;
padding-left: 0 } padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% } font-size: 100% }

@ -344,92 +344,97 @@ ul.auto-toc {
<div class="contents topic" id="contents"> <div class="contents topic" id="contents">
<p class="topic-title first">Contents</p> <p class="topic-title first">Contents</p>
<ul class="simple"> <ul class="simple">
<li><a class="reference internal" href="#df-data-structure-wrapper" id="id1">DF data structure wrapper</a><ul> <li><a class="reference internal" href="#df-data-structure-wrapper" id="id3">DF data structure wrapper</a><ul>
<li><a class="reference internal" href="#typed-object-references" id="id2">Typed object references</a><ul> <li><a class="reference internal" href="#typed-object-references" id="id4">Typed object references</a><ul>
<li><a class="reference internal" href="#primitive-references" id="id3">Primitive references</a></li> <li><a class="reference internal" href="#primitive-references" id="id5">Primitive references</a></li>
<li><a class="reference internal" href="#struct-references" id="id4">Struct references</a></li> <li><a class="reference internal" href="#struct-references" id="id6">Struct references</a></li>
<li><a class="reference internal" href="#container-references" id="id5">Container references</a></li> <li><a class="reference internal" href="#container-references" id="id7">Container references</a></li>
<li><a class="reference internal" href="#bitfield-references" id="id6">Bitfield references</a></li> <li><a class="reference internal" href="#bitfield-references" id="id8">Bitfield references</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#named-types" id="id7">Named types</a></li> <li><a class="reference internal" href="#named-types" id="id9">Named types</a></li>
<li><a class="reference internal" href="#global-functions" id="id8">Global functions</a></li> <li><a class="reference internal" href="#global-functions" id="id10">Global functions</a></li>
<li><a class="reference internal" href="#recursive-table-assignment" id="id9">Recursive table assignment</a></li> <li><a class="reference internal" href="#recursive-table-assignment" id="id11">Recursive table assignment</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#dfhack-api" id="id10">DFHack API</a><ul> <li><a class="reference internal" href="#dfhack-api" id="id12">DFHack API</a><ul>
<li><a class="reference internal" href="#native-utilities" id="id11">Native utilities</a><ul> <li><a class="reference internal" href="#native-utilities" id="id13">Native utilities</a><ul>
<li><a class="reference internal" href="#input-output" id="id12">Input &amp; Output</a></li> <li><a class="reference internal" href="#input-output" id="id14">Input &amp; Output</a></li>
<li><a class="reference internal" href="#exception-handling" id="id13">Exception handling</a></li> <li><a class="reference internal" href="#exception-handling" id="id15">Exception handling</a></li>
<li><a class="reference internal" href="#miscellaneous" id="id14">Miscellaneous</a></li> <li><a class="reference internal" href="#miscellaneous" id="id16">Miscellaneous</a></li>
<li><a class="reference internal" href="#locking-and-finalization" id="id15">Locking and finalization</a></li> <li><a class="reference internal" href="#locking-and-finalization" id="id17">Locking and finalization</a></li>
<li><a class="reference internal" href="#persistent-configuration-storage" id="id16">Persistent configuration storage</a></li> <li><a class="reference internal" href="#persistent-configuration-storage" id="id18">Persistent configuration storage</a></li>
<li><a class="reference internal" href="#material-info-lookup" id="id17">Material info lookup</a></li> <li><a class="reference internal" href="#material-info-lookup" id="id19">Material info lookup</a></li>
<li><a class="reference internal" href="#random-number-generation" id="id18">Random number generation</a></li> <li><a class="reference internal" href="#random-number-generation" id="id20">Random number generation</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#c-function-wrappers" id="id19">C++ function wrappers</a><ul> <li><a class="reference internal" href="#c-function-wrappers" id="id21">C++ function wrappers</a><ul>
<li><a class="reference internal" href="#gui-module" id="id20">Gui module</a></li> <li><a class="reference internal" href="#gui-module" id="id22">Gui module</a></li>
<li><a class="reference internal" href="#job-module" id="id21">Job module</a></li> <li><a class="reference internal" href="#job-module" id="id23">Job module</a></li>
<li><a class="reference internal" href="#units-module" id="id22">Units module</a></li> <li><a class="reference internal" href="#units-module" id="id24">Units module</a></li>
<li><a class="reference internal" href="#items-module" id="id23">Items module</a></li> <li><a class="reference internal" href="#items-module" id="id25">Items module</a></li>
<li><a class="reference internal" href="#maps-module" id="id24">Maps module</a></li> <li><a class="reference internal" href="#maps-module" id="id26">Maps module</a></li>
<li><a class="reference internal" href="#burrows-module" id="id25">Burrows module</a></li> <li><a class="reference internal" href="#burrows-module" id="id27">Burrows module</a></li>
<li><a class="reference internal" href="#buildings-module" id="id26">Buildings module</a></li> <li><a class="reference internal" href="#buildings-module" id="id28">Buildings module</a></li>
<li><a class="reference internal" href="#constructions-module" id="id27">Constructions module</a></li> <li><a class="reference internal" href="#constructions-module" id="id29">Constructions module</a></li>
<li><a class="reference internal" href="#screen-api" id="id28">Screen API</a></li> <li><a class="reference internal" href="#screen-api" id="id30">Screen API</a></li>
<li><a class="reference internal" href="#internal-api" id="id29">Internal API</a></li> <li><a class="reference internal" href="#internal-api" id="id31">Internal API</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#core-interpreter-context" id="id30">Core interpreter context</a><ul> <li><a class="reference internal" href="#core-interpreter-context" id="id32">Core interpreter context</a><ul>
<li><a class="reference internal" href="#event-type" id="id31">Event type</a></li> <li><a class="reference internal" href="#event-type" id="id33">Event type</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#lua-modules" id="id32">Lua Modules</a><ul> <li><a class="reference internal" href="#lua-modules" id="id34">Lua Modules</a><ul>
<li><a class="reference internal" href="#global-environment" id="id33">Global environment</a></li> <li><a class="reference internal" href="#global-environment" id="id35">Global environment</a></li>
<li><a class="reference internal" href="#utils" id="id34">utils</a></li> <li><a class="reference internal" href="#utils" id="id36">utils</a></li>
<li><a class="reference internal" href="#dumper" id="id35">dumper</a></li> <li><a class="reference internal" href="#dumper" id="id37">dumper</a></li>
<li><a class="reference internal" href="#class" id="id36">class</a></li> <li><a class="reference internal" href="#class" id="id38">class</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#in-game-ui-library" id="id37">In-game UI Library</a><ul> <li><a class="reference internal" href="#in-game-ui-library" id="id39">In-game UI Library</a><ul>
<li><a class="reference internal" href="#gui" id="id38">gui</a><ul> <li><a class="reference internal" href="#gui" id="id40">gui</a><ul>
<li><a class="reference internal" href="#misc" id="id39">Misc</a></li> <li><a class="reference internal" href="#misc" id="id41">Misc</a></li>
<li><a class="reference internal" href="#viewrect-class" id="id40">ViewRect class</a></li> <li><a class="reference internal" href="#viewrect-class" id="id42">ViewRect class</a></li>
<li><a class="reference internal" href="#painter-class" id="id41">Painter class</a></li> <li><a class="reference internal" href="#painter-class" id="id43">Painter class</a></li>
<li><a class="reference internal" href="#view-class" id="id42">View class</a></li> <li><a class="reference internal" href="#view-class" id="id44">View class</a></li>
<li><a class="reference internal" href="#screen-class" id="id43">Screen class</a></li> <li><a class="reference internal" href="#screen-class" id="id45">Screen class</a></li>
<li><a class="reference internal" href="#framedscreen-class" id="id44">FramedScreen class</a></li> <li><a class="reference internal" href="#framedscreen-class" id="id46">FramedScreen class</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#gui-widgets" id="id45">gui.widgets</a><ul> <li><a class="reference internal" href="#gui-widgets" id="id47">gui.widgets</a><ul>
<li><a class="reference internal" href="#widget-class" id="id46">Widget class</a></li> <li><a class="reference internal" href="#widget-class" id="id48">Widget class</a></li>
<li><a class="reference internal" href="#panel-class" id="id47">Panel class</a></li> <li><a class="reference internal" href="#panel-class" id="id49">Panel class</a></li>
<li><a class="reference internal" href="#pages-class" id="id48">Pages class</a></li> <li><a class="reference internal" href="#pages-class" id="id50">Pages class</a></li>
<li><a class="reference internal" href="#editfield-class" id="id49">EditField class</a></li> <li><a class="reference internal" href="#editfield-class" id="id51">EditField class</a></li>
<li><a class="reference internal" href="#label-class" id="id50">Label class</a></li> <li><a class="reference internal" href="#label-class" id="id52">Label class</a></li>
<li><a class="reference internal" href="#list-class" id="id51">List class</a></li> <li><a class="reference internal" href="#list-class" id="id53">List class</a></li>
<li><a class="reference internal" href="#filteredlist-class" id="id52">FilteredList class</a></li> <li><a class="reference internal" href="#filteredlist-class" id="id54">FilteredList class</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#plugins" id="id53">Plugins</a><ul> <li><a class="reference internal" href="#plugins" id="id55">Plugins</a><ul>
<li><a class="reference internal" href="#burrows" id="id54">burrows</a></li> <li><a class="reference internal" href="#burrows" id="id56">burrows</a></li>
<li><a class="reference internal" href="#sort" id="id55">sort</a></li> <li><a class="reference internal" href="#sort" id="id57">sort</a></li>
<li><a class="reference internal" href="#eventful" id="id56">Eventful</a><ul> <li><a class="reference internal" href="#eventful" id="id58">Eventful</a><ul>
<li><a class="reference internal" href="#list-of-events" id="id57">List of events</a></li> <li><a class="reference internal" href="#list-of-events" id="id59">List of events</a></li>
<li><a class="reference internal" href="#events-from-eventmanager" id="id58">Events from EventManager</a></li> <li><a class="reference internal" href="#events-from-eventmanager" id="id60">Events from EventManager</a></li>
<li><a class="reference internal" href="#functions" id="id59">Functions</a></li> <li><a class="reference internal" href="#functions" id="id61">Functions</a></li>
<li><a class="reference internal" href="#examples" id="id60">Examples</a></li> <li><a class="reference internal" href="#examples" id="id62">Examples</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#building-hacks" id="id63">Building-hacks</a><ul>
<li><a class="reference internal" href="#id1" id="id64">Functions</a></li>
<li><a class="reference internal" href="#id2" id="id65">Examples</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#scripts" id="id61">Scripts</a><ul> </ul>
<li><a class="reference internal" href="#save-init-script" id="id62">Save init script</a></li> </li>
<li><a class="reference internal" href="#scripts" id="id66">Scripts</a><ul>
<li><a class="reference internal" href="#save-init-script" id="id67">Save init script</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -449,10 +454,11 @@ native C++ commands, and invoked by plugins written in c++.</p>
It does not describe all of the utility functions It does not describe all of the utility functions
implemented by Lua files located in hack/lua/...</p> implemented by Lua files located in hack/lua/...</p>
<div class="section" id="df-data-structure-wrapper"> <div class="section" id="df-data-structure-wrapper">
<h1><a class="toc-backref" href="#id1">DF data structure wrapper</a></h1> <h1><a class="toc-backref" href="#id3">DF data structure wrapper</a></h1>
<p>DF structures described by the xml files in library/xml are exported <p>Data structures of the game are defined in XML files located in library/xml
to lua code as a tree of objects and functions under the <tt class="docutils literal">df</tt> global, (and online at <a class="reference external" href="http://github.com/DFHack/df-structures">http://github.com/DFHack/df-structures</a>), and automatically exported
which broadly maps to the <tt class="docutils literal">df</tt> namespace in C++.</p> to lua code as a tree of objects and functions under the <tt class="docutils literal">df</tt> global, which
also broadly maps to the <tt class="docutils literal">df</tt> namespace in the headers generated for C++.</p>
<p><strong>WARNING</strong>: The wrapper provides almost raw access to the memory <p><strong>WARNING</strong>: The wrapper provides almost raw access to the memory
of the game, so mistakes in manipulating objects are as likely to of the game, so mistakes in manipulating objects are as likely to
crash the game as equivalent plain C++ code would be. E.g. NULL crash the game as equivalent plain C++ code would be. E.g. NULL
@ -485,7 +491,7 @@ both nested types and fields corresponding to global symbols.</p>
<p>In addition to the <tt class="docutils literal">global</tt> object and top-level types the <tt class="docutils literal">df</tt> <p>In addition to the <tt class="docutils literal">global</tt> object and top-level types the <tt class="docutils literal">df</tt>
global also contains a few global builtin utility functions.</p> global also contains a few global builtin utility functions.</p>
<div class="section" id="typed-object-references"> <div class="section" id="typed-object-references">
<h2><a class="toc-backref" href="#id2">Typed object references</a></h2> <h2><a class="toc-backref" href="#id4">Typed object references</a></h2>
<p>The underlying primitive lua object is userdata with a metatable. <p>The underlying primitive lua object is userdata with a metatable.
Every structured field access produces a new userdata instance.</p> Every structured field access produces a new userdata instance.</p>
<p>All typed objects have the following built-in features:</p> <p>All typed objects have the following built-in features:</p>
@ -534,7 +540,7 @@ Step defaults to the natural object size.</p>
</li> </li>
</ul> </ul>
<div class="section" id="primitive-references"> <div class="section" id="primitive-references">
<h3><a class="toc-backref" href="#id3">Primitive references</a></h3> <h3><a class="toc-backref" href="#id5">Primitive references</a></h3>
<p>References of the <em>_kind</em> <tt class="docutils literal">'primitive'</tt> are used for objects <p>References of the <em>_kind</em> <tt class="docutils literal">'primitive'</tt> are used for objects
that don't fit any of the other reference types. Such that don't fit any of the other reference types. Such
references can only appear as a value of a pointer field, references can only appear as a value of a pointer field,
@ -546,7 +552,7 @@ no bound checking is performed, since buffer length is not available.
Index 0 is equivalent to the <tt class="docutils literal">value</tt> field.</p> Index 0 is equivalent to the <tt class="docutils literal">value</tt> field.</p>
</div> </div>
<div class="section" id="struct-references"> <div class="section" id="struct-references">
<h3><a class="toc-backref" href="#id4">Struct references</a></h3> <h3><a class="toc-backref" href="#id6">Struct references</a></h3>
<p>Struct references are used for class and struct objects.</p> <p>Struct references are used for class and struct objects.</p>
<p>They implement the following features:</p> <p>They implement the following features:</p>
<ul> <ul>
@ -580,7 +586,7 @@ shadowing rules.</p>
</ul> </ul>
</div> </div>
<div class="section" id="container-references"> <div class="section" id="container-references">
<h3><a class="toc-backref" href="#id5">Container references</a></h3> <h3><a class="toc-backref" href="#id7">Container references</a></h3>
<p>Containers represent vectors and arrays, possibly resizable.</p> <p>Containers represent vectors and arrays, possibly resizable.</p>
<p>A container field can associate an enum to the container <p>A container field can associate an enum to the container
reference, which allows accessing elements using string keys reference, which allows accessing elements using string keys
@ -624,7 +630,7 @@ use <tt class="docutils literal">#ref</tt>, or just <tt class="docutils literal"
</ul> </ul>
</div> </div>
<div class="section" id="bitfield-references"> <div class="section" id="bitfield-references">
<h3><a class="toc-backref" href="#id6">Bitfield references</a></h3> <h3><a class="toc-backref" href="#id8">Bitfield references</a></h3>
<p>Bitfields behave like special fixed-size containers. <p>Bitfields behave like special fixed-size containers.
Consider them to be something in between structs and Consider them to be something in between structs and
fixed-size vectors.</p> fixed-size vectors.</p>
@ -640,7 +646,7 @@ them, e.g. <tt class="docutils literal">matinfo:matches{metal=true}</tt>.</p>
</div> </div>
</div> </div>
<div class="section" id="named-types"> <div class="section" id="named-types">
<h2><a class="toc-backref" href="#id7">Named types</a></h2> <h2><a class="toc-backref" href="#id9">Named types</a></h2>
<p>Named types are exposed in the <tt class="docutils literal">df</tt> tree with names identical <p>Named types are exposed in the <tt class="docutils literal">df</tt> tree with names identical
to the C++ version, except for the <tt class="docutils literal">::</tt> vs <tt class="docutils literal">.</tt> difference.</p> to the C++ version, except for the <tt class="docutils literal">::</tt> vs <tt class="docutils literal">.</tt> difference.</p>
<p>All types and the global object have the following features:</p> <p>All types and the global object have the following features:</p>
@ -678,7 +684,7 @@ xml have a <tt class="docutils literal">type.find(key)</tt> function that wraps
method provided in C++.</p> method provided in C++.</p>
</div> </div>
<div class="section" id="global-functions"> <div class="section" id="global-functions">
<h2><a class="toc-backref" href="#id8">Global functions</a></h2> <h2><a class="toc-backref" href="#id10">Global functions</a></h2>
<p>The <tt class="docutils literal">df</tt> table itself contains the following functions and values:</p> <p>The <tt class="docutils literal">df</tt> table itself contains the following functions and values:</p>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">NULL</tt>, <tt class="docutils literal">df.NULL</tt></p> <li><p class="first"><tt class="docutils literal">NULL</tt>, <tt class="docutils literal">df.NULL</tt></p>
@ -723,7 +729,7 @@ a lightuserdata, or a number.</p>
</ul> </ul>
</div> </div>
<div class="section" id="recursive-table-assignment"> <div class="section" id="recursive-table-assignment">
<h2><a class="toc-backref" href="#id9">Recursive table assignment</a></h2> <h2><a class="toc-backref" href="#id11">Recursive table assignment</a></h2>
<p>Recursive assignment is invoked when a lua table is assigned <p>Recursive assignment is invoked when a lua table is assigned
to a C++ object or field, i.e. one of:</p> to a C++ object or field, i.e. one of:</p>
<ul class="simple"> <ul class="simple">
@ -805,12 +811,12 @@ cleanup.</p>
</div> </div>
</div> </div>
<div class="section" id="dfhack-api"> <div class="section" id="dfhack-api">
<h1><a class="toc-backref" href="#id10">DFHack API</a></h1> <h1><a class="toc-backref" href="#id12">DFHack API</a></h1>
<p>DFHack utility functions are placed in the <tt class="docutils literal">dfhack</tt> global tree.</p> <p>DFHack utility functions are placed in the <tt class="docutils literal">dfhack</tt> global tree.</p>
<div class="section" id="native-utilities"> <div class="section" id="native-utilities">
<h2><a class="toc-backref" href="#id11">Native utilities</a></h2> <h2><a class="toc-backref" href="#id13">Native utilities</a></h2>
<div class="section" id="input-output"> <div class="section" id="input-output">
<h3><a class="toc-backref" href="#id12">Input &amp; Output</a></h3> <h3><a class="toc-backref" href="#id14">Input &amp; Output</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.print(args...)</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.print(args...)</span></tt></p>
<p>Output tab-separated args as standard lua print would do, <p>Output tab-separated args as standard lua print would do,
@ -846,7 +852,7 @@ string, global environment and command-line history file.</p>
</ul> </ul>
</div> </div>
<div class="section" id="exception-handling"> <div class="section" id="exception-handling">
<h3><a class="toc-backref" href="#id13">Exception handling</a></h3> <h3><a class="toc-backref" href="#id15">Exception handling</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.error(msg[,level[,verbose]])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.error(msg[,level[,verbose]])</span></tt></p>
<p>Throws a dfhack exception object with location and stack trace. <p>Throws a dfhack exception object with location and stack trace.
@ -902,7 +908,7 @@ following properties:</p>
</ul> </ul>
</div> </div>
<div class="section" id="miscellaneous"> <div class="section" id="miscellaneous">
<h3><a class="toc-backref" href="#id14">Miscellaneous</a></h3> <h3><a class="toc-backref" href="#id16">Miscellaneous</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">dfhack.VERSION</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.VERSION</tt></p>
<p>DFHack version string constant.</p> <p>DFHack version string constant.</p>
@ -915,7 +921,7 @@ both from the curry call and the closure call itself. I.e.
</ul> </ul>
</div> </div>
<div class="section" id="locking-and-finalization"> <div class="section" id="locking-and-finalization">
<h3><a class="toc-backref" href="#id15">Locking and finalization</a></h3> <h3><a class="toc-backref" href="#id17">Locking and finalization</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_suspend(f[,args...])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_suspend(f[,args...])</span></tt></p>
<p>Calls <tt class="docutils literal">f</tt> with arguments after grabbing the DF core suspend lock. <p>Calls <tt class="docutils literal">f</tt> with arguments after grabbing the DF core suspend lock.
@ -948,7 +954,7 @@ Implemented using <tt class="docutils literal"><span class="pre">call_with_final
</ul> </ul>
</div> </div>
<div class="section" id="persistent-configuration-storage"> <div class="section" id="persistent-configuration-storage">
<h3><a class="toc-backref" href="#id16">Persistent configuration storage</a></h3> <h3><a class="toc-backref" href="#id18">Persistent configuration storage</a></h3>
<p>This api is intended for storing configuration options in the world itself. <p>This api is intended for storing configuration options in the world itself.
It probably should be restricted to data that is world-dependent.</p> It probably should be restricted to data that is world-dependent.</p>
<p>Entries are identified by a string <tt class="docutils literal">key</tt>, but it is also possible to manage <p>Entries are identified by a string <tt class="docutils literal">key</tt>, but it is also possible to manage
@ -998,7 +1004,7 @@ as an all-zero mask.</p>
the persistent entry will <strong>NOT</strong> delete the associated masks.</p> the persistent entry will <strong>NOT</strong> delete the associated masks.</p>
</div> </div>
<div class="section" id="material-info-lookup"> <div class="section" id="material-info-lookup">
<h3><a class="toc-backref" href="#id17">Material info lookup</a></h3> <h3><a class="toc-backref" href="#id19">Material info lookup</a></h3>
<p>A material info record has fields:</p> <p>A material info record has fields:</p>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">type</tt>, <tt class="docutils literal">index</tt>, <tt class="docutils literal">material</tt></p> <li><p class="first"><tt class="docutils literal">type</tt>, <tt class="docutils literal">index</tt>, <tt class="docutils literal">material</tt></p>
@ -1042,7 +1048,7 @@ Accept dfhack_material_category auto-assign table.</p>
</ul> </ul>
</div> </div>
<div class="section" id="random-number-generation"> <div class="section" id="random-number-generation">
<h3><a class="toc-backref" href="#id18">Random number generation</a></h3> <h3><a class="toc-backref" href="#id20">Random number generation</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.random.new([seed[,perturb_count]])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.random.new([seed[,perturb_count]])</span></tt></p>
<p>Creates a new random number generator object. Without any <p>Creates a new random number generator object. Without any
@ -1086,7 +1092,7 @@ Dimension may be 1, 2 or 3 (default).</p>
</div> </div>
</div> </div>
<div class="section" id="c-function-wrappers"> <div class="section" id="c-function-wrappers">
<h2><a class="toc-backref" href="#id19">C++ function wrappers</a></h2> <h2><a class="toc-backref" href="#id21">C++ function wrappers</a></h2>
<p>Thin wrappers around C++ functions, similar to the ones for virtual methods. <p>Thin wrappers around C++ functions, similar to the ones for virtual methods.
One notable difference is that these explicit wrappers allow argument count One notable difference is that these explicit wrappers allow argument count
adjustment according to the usual lua rules, so trailing false/nil arguments adjustment according to the usual lua rules, so trailing false/nil arguments
@ -1119,9 +1125,15 @@ can be omitted.</p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.TranslateName(name[,in_english,only_last_name])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.TranslateName(name[,in_english,only_last_name])</span></tt></p>
<p>Convert a language_name or only the last name part to string.</p> <p>Convert a language_name or only the last name part to string.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">dfhack.df2utf(string)</tt></p>
<p>Convert a string from DF's CP437 encoding to UTF-8.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.utf2df(string)</tt></p>
<p>Convert a string from UTF-8 to DF's CP437 encoding.</p>
</li>
</ul> </ul>
<div class="section" id="gui-module"> <div class="section" id="gui-module">
<h3><a class="toc-backref" href="#id20">Gui module</a></h3> <h3><a class="toc-backref" href="#id22">Gui module</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getCurViewscreen([skip_dismissed])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getCurViewscreen([skip_dismissed])</span></tt></p>
<p>Returns the topmost viewscreen. If <tt class="docutils literal">skip_dismissed</tt> is <em>true</em>, <p>Returns the topmost viewscreen. If <tt class="docutils literal">skip_dismissed</tt> is <em>true</em>,
@ -1154,6 +1166,26 @@ the container itself.</p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getSelectedBuilding([silent])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getSelectedBuilding([silent])</span></tt></p>
<p>Returns the building selected via <em>'q'</em>, <em>'t'</em>, <em>'k'</em> or <em>'i'</em>.</p> <p>Returns the building selected via <em>'q'</em>, <em>'t'</em>, <em>'k'</em> or <em>'i'</em>.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.writeToGamelog(text)</tt></p>
<p>Writes a string to gamelog.txt without doing an announcement.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.makeAnnouncement(type,flags,pos,text,color[,is_bright])</span></tt></p>
<p>Adds an announcement with given announcement_type, text, color, and brightness.
The is_bright boolean actually seems to invert the brightness.</p>
<p>The announcement is written to gamelog.txt. The announcement_flags
argument provides a custom set of announcements.txt options,
which specify if the message should actually be displayed in the
announcement list, and whether to recenter or show a popup.</p>
<p>Returns the index of the new announcement in <tt class="docutils literal">df.global.world.status.reports</tt>, or -1.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.addCombatReport(unit,slot,report_index)</tt></p>
<p>Adds the report with the given index (returned by makeAnnouncement)
to the specified group of the given unit. Returns <em>true</em> on success.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.addCombatReportAuto(unit,flags,report_index)</tt></p>
<p>Adds the report with the given index to the appropriate group(s)
of the given unit, as requested by the flags.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showAnnouncement(text,color[,is_bright])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showAnnouncement(text,color[,is_bright])</span></tt></p>
<p>Adds a regular announcement with given text, color, and brightness. <p>Adds a regular announcement with given text, color, and brightness.
The is_bright boolean actually seems to invert the brightness.</p> The is_bright boolean actually seems to invert the brightness.</p>
@ -1164,14 +1196,14 @@ The is_bright boolean actually seems to invert the brightness.</p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showPopupAnnouncement(text,color[,is_bright])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showPopupAnnouncement(text,color[,is_bright])</span></tt></p>
<p>Pops up a titan-style modal announcement window.</p> <p>Pops up a titan-style modal announcement window.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright])</span></tt></p> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright,unit1,unit2])</span></tt></p>
<p>Uses the type to look up options from announcements.txt, and calls the <p>Uses the type to look up options from announcements.txt, and calls the above
above operations accordingly. If enabled, pauses and zooms to position.</p> operations accordingly. The units are used to call <tt class="docutils literal">addCombatReportAuto</tt>.</p>
</li> </li>
</ul> </ul>
</div> </div>
<div class="section" id="job-module"> <div class="section" id="job-module">
<h3><a class="toc-backref" href="#id21">Job module</a></h3> <h3><a class="toc-backref" href="#id23">Job module</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">dfhack.job.cloneJobStruct(job)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.job.cloneJobStruct(job)</tt></p>
<p>Creates a deep copy of the given job.</p> <p>Creates a deep copy of the given job.</p>
@ -1194,6 +1226,14 @@ above operations accordingly. If enabled, pauses and zooms to position.</p>
<li><p class="first"><tt class="docutils literal">dfhack.job.getWorker(job)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.job.getWorker(job)</tt></p>
<p>Returns the unit performing the job.</p> <p>Returns the unit performing the job.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">dfhack.job.setJobCooldown(building,worker,timeout)</tt></p>
<p>Prevent the worker from taking jobs at the specified workshop for the specified time.
This doesn't decrease the timeout in any circumstances.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.job.removeWorker(job,timeout)</tt></p>
<p>Removes the worker from the specified workshop job, and sets the cooldown.
Returns <em>true</em> on success.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.job.checkBuildingsNow()</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.job.checkBuildingsNow()</tt></p>
<p>Instructs the game to check buildings for jobs next frame and assign workers.</p> <p>Instructs the game to check buildings for jobs next frame and assign workers.</p>
</li> </li>
@ -1218,10 +1258,13 @@ the flags in the job item.</p>
<li><p class="first"><tt class="docutils literal">dfhack.job.isSuitableMaterial(job_item, mat_type, mat_index)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.job.isSuitableMaterial(job_item, mat_type, mat_index)</tt></p>
<p>Likewise, if replacing material.</p> <p>Likewise, if replacing material.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">dfhack.job.getName(job)</tt></p>
<p>Returns the job's description, as seen in the Units and Jobs screens.</p>
</li>
</ul> </ul>
</div> </div>
<div class="section" id="units-module"> <div class="section" id="units-module">
<h3><a class="toc-backref" href="#id22">Units module</a></h3> <h3><a class="toc-backref" href="#id24">Units module</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">dfhack.units.getPosition(unit)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.units.getPosition(unit)</tt></p>
<p>Returns true <em>x,y,z</em> of the unit, or <em>nil</em> if invalid; may be not equal to unit.pos if caged.</p> <p>Returns true <em>x,y,z</em> of the unit, or <em>nil</em> if invalid; may be not equal to unit.pos if caged.</p>
@ -1300,6 +1343,10 @@ is <em>true</em>, subtracts the rust penalty.</p>
<li><p class="first"><tt class="docutils literal">dfhack.units.computeMovementSpeed(unit)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.units.computeMovementSpeed(unit)</tt></p>
<p>Computes number of frames * 100 it takes the unit to move in its current state of mind and body.</p> <p>Computes number of frames * 100 it takes the unit to move in its current state of mind and body.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">dfhack.units.computeSlowdownFactor(unit)</tt></p>
<p>Meandering and floundering in liquid introduces additional slowdown. It is
random, but the function computes and returns the expected mean factor as a float.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.units.getNoblePositions(unit)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.units.getNoblePositions(unit)</tt></p>
<p>Returns a list of tables describing noble position assignments, or <em>nil</em>. <p>Returns a list of tables describing noble position assignments, or <em>nil</em>.
Every table has fields <tt class="docutils literal">entity</tt>, <tt class="docutils literal">assignment</tt> and <tt class="docutils literal">position</tt>.</p> Every table has fields <tt class="docutils literal">entity</tt>, <tt class="docutils literal">assignment</tt> and <tt class="docutils literal">position</tt>.</p>
@ -1321,7 +1368,7 @@ or raws. The <tt class="docutils literal">ignore_noble</tt> boolean disables the
</ul> </ul>
</div> </div>
<div class="section" id="items-module"> <div class="section" id="items-module">
<h3><a class="toc-backref" href="#id23">Items module</a></h3> <h3><a class="toc-backref" href="#id25">Items module</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">dfhack.items.getPosition(item)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.items.getPosition(item)</tt></p>
<p>Returns true <em>x,y,z</em> of the item, or <em>nil</em> if invalid; may be not equal to item.pos if in inventory.</p> <p>Returns true <em>x,y,z</em> of the item, or <em>nil</em> if invalid; may be not equal to item.pos if in inventory.</p>
@ -1382,10 +1429,16 @@ Returns <em>false</em> in case of error.</p>
<li><p class="first"><tt class="docutils literal">dfhack.items.getSubtypeDef(item_type, subtype)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.items.getSubtypeDef(item_type, subtype)</tt></p>
<p>Returns the raw definition for the given item type and subtype, or <em>nil</em> if invalid.</p> <p>Returns the raw definition for the given item type and subtype, or <em>nil</em> if invalid.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">dfhack.items.getItemBaseValue(item_type, subtype, material, mat_index)</tt></p>
<p>Calculates the base value for an item of the specified type and material.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.items.getValue(item)</tt></p>
<p>Calculates the Basic Value of an item, as seen in the View Item screen.</p>
</li>
</ul> </ul>
</div> </div>
<div class="section" id="maps-module"> <div class="section" id="maps-module">
<h3><a class="toc-backref" href="#id24">Maps module</a></h3> <h3><a class="toc-backref" href="#id26">Maps module</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">dfhack.maps.getSize()</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.maps.getSize()</tt></p>
<p>Returns map size in blocks: <em>x, y, z</em></p> <p>Returns map size in blocks: <em>x, y, z</em></p>
@ -1454,7 +1507,7 @@ burrows, or the presence of invaders.</p>
</ul> </ul>
</div> </div>
<div class="section" id="burrows-module"> <div class="section" id="burrows-module">
<h3><a class="toc-backref" href="#id25">Burrows module</a></h3> <h3><a class="toc-backref" href="#id27">Burrows module</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">dfhack.burrows.findByName(name)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.burrows.findByName(name)</tt></p>
<p>Returns the burrow pointer or <em>nil</em>.</p> <p>Returns the burrow pointer or <em>nil</em>.</p>
@ -1489,7 +1542,7 @@ burrows, or the presence of invaders.</p>
</ul> </ul>
</div> </div>
<div class="section" id="buildings-module"> <div class="section" id="buildings-module">
<h3><a class="toc-backref" href="#id26">Buildings module</a></h3> <h3><a class="toc-backref" href="#id28">Buildings module</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">dfhack.buildings.getGeneralRef(building, type)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.buildings.getGeneralRef(building, type)</tt></p>
<p>Searches for a general_ref with the given type.</p> <p>Searches for a general_ref with the given type.</p>
@ -1639,7 +1692,7 @@ can be determined this way, <tt class="docutils literal">constructBuilding</tt>
</ul> </ul>
</div> </div>
<div class="section" id="constructions-module"> <div class="section" id="constructions-module">
<h3><a class="toc-backref" href="#id27">Constructions module</a></h3> <h3><a class="toc-backref" href="#id29">Constructions module</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">dfhack.constructions.designateNew(pos,type,item_type,mat_index)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.constructions.designateNew(pos,type,item_type,mat_index)</tt></p>
<p>Designates a new construction at given position. If there already is <p>Designates a new construction at given position. If there already is
@ -1655,7 +1708,7 @@ Returns <em>true, was_only_planned</em> if removed; or <em>false</em> if none fo
</ul> </ul>
</div> </div>
<div class="section" id="screen-api"> <div class="section" id="screen-api">
<h3><a class="toc-backref" href="#id28">Screen API</a></h3> <h3><a class="toc-backref" href="#id30">Screen API</a></h3>
<p>The screen module implements support for drawing to the tiled screen of the game. <p>The screen module implements support for drawing to the tiled screen of the game.
Note that drawing only has any effect when done from callbacks, so it can only Note that drawing only has any effect when done from callbacks, so it can only
be feasibly used in the core context.</p> be feasibly used in the core context.</p>
@ -1843,7 +1896,7 @@ options; if multiple interpretations exist, the table will contain multiple keys
</ul> </ul>
</div> </div>
<div class="section" id="internal-api"> <div class="section" id="internal-api">
<h3><a class="toc-backref" href="#id29">Internal API</a></h3> <h3><a class="toc-backref" href="#id31">Internal API</a></h3>
<p>These functions are intended for the use by dfhack developers, <p>These functions are intended for the use by dfhack developers,
and are only documented here for completeness:</p> and are only documented here for completeness:</p>
<ul> <ul>
@ -1904,11 +1957,15 @@ Returns: <em>step_idx, sum_idx, found_ptr</em>, or <em>nil</em> if not found.</p
The oldval, newval or delta arguments may be used to specify additional constraints. The oldval, newval or delta arguments may be used to specify additional constraints.
Returns: <em>found_index</em>, or <em>nil</em> if end reached.</p> Returns: <em>found_index</em>, or <em>nil</em> if end reached.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">dfhack.internal.getDir(path)</tt></p>
<p>List files in a directory.
Returns: <em>file_names</em> or empty table if not found.</p>
</li>
</ul> </ul>
</div> </div>
</div> </div>
<div class="section" id="core-interpreter-context"> <div class="section" id="core-interpreter-context">
<h2><a class="toc-backref" href="#id30">Core interpreter context</a></h2> <h2><a class="toc-backref" href="#id32">Core interpreter context</a></h2>
<p>While plugins can create any number of interpreter instances, <p>While plugins can create any number of interpreter instances,
there is one special context managed by dfhack core. It is the there is one special context managed by dfhack core. It is the
only context that can receive events from DF and plugins.</p> only context that can receive events from DF and plugins.</p>
@ -1939,7 +1996,7 @@ Using <tt class="docutils literal">timeout_active(id,nil)</tt> cancels the timer
</li> </li>
</ul> </ul>
<div class="section" id="event-type"> <div class="section" id="event-type">
<h3><a class="toc-backref" href="#id31">Event type</a></h3> <h3><a class="toc-backref" href="#id33">Event type</a></h3>
<p>An event is a native object transparently wrapping a lua table, <p>An event is a native object transparently wrapping a lua table,
and implementing a __call metamethod. When it is invoked, it loops and implementing a __call metamethod. When it is invoked, it loops
through the table with next and calls all contained values. through the table with next and calls all contained values.
@ -1971,7 +2028,7 @@ order using <tt class="docutils literal">dfhack.safecall</tt>.</p>
</div> </div>
</div> </div>
<div class="section" id="lua-modules"> <div class="section" id="lua-modules">
<h1><a class="toc-backref" href="#id32">Lua Modules</a></h1> <h1><a class="toc-backref" href="#id34">Lua Modules</a></h1>
<p>DFHack sets up the lua interpreter so that the built-in <tt class="docutils literal">require</tt> <p>DFHack sets up the lua interpreter so that the built-in <tt class="docutils literal">require</tt>
function can be used to load shared lua code from hack/lua/. function can be used to load shared lua code from hack/lua/.
The <tt class="docutils literal">dfhack</tt> namespace reference itself may be obtained via The <tt class="docutils literal">dfhack</tt> namespace reference itself may be obtained via
@ -2000,7 +2057,7 @@ in this document.</p>
</li> </li>
</ul> </ul>
<div class="section" id="global-environment"> <div class="section" id="global-environment">
<h2><a class="toc-backref" href="#id33">Global environment</a></h2> <h2><a class="toc-backref" href="#id35">Global environment</a></h2>
<p>A number of variables and functions are provided in the base global <p>A number of variables and functions are provided in the base global
environment by the mandatory init file dfhack.lua:</p> environment by the mandatory init file dfhack.lua:</p>
<ul> <ul>
@ -2063,7 +2120,7 @@ Returns <em>nil</em> if any of obj or indices is <em>nil</em>, or a numeric inde
</ul> </ul>
</div> </div>
<div class="section" id="utils"> <div class="section" id="utils">
<h2><a class="toc-backref" href="#id34">utils</a></h2> <h2><a class="toc-backref" href="#id36">utils</a></h2>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">utils.compare(a,b)</tt></p> <li><p class="first"><tt class="docutils literal">utils.compare(a,b)</tt></p>
<p>Comparator function; returns <em>-1</em> if a&lt;b, <em>1</em> if a&gt;b, <em>0</em> otherwise.</p> <p>Comparator function; returns <em>-1</em> if a&lt;b, <em>1</em> if a&gt;b, <em>0</em> otherwise.</p>
@ -2115,6 +2172,9 @@ for i = 1,#order do output[i] = data[order[i]] end
way enables applying the same permutation to multiple arrays. way enables applying the same permutation to multiple arrays.
This function is used by the sort plugin.</p> This function is used by the sort plugin.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">for link,item in utils.listpairs(list)</tt></p>
<p>Iterates a df-list structure, for example <tt class="docutils literal">df.global.world.job_list</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">utils.assign(tgt, src)</tt></p> <li><p class="first"><tt class="docutils literal">utils.assign(tgt, src)</tt></p>
<p>Does a recursive assignment of src into tgt. <p>Does a recursive assignment of src into tgt.
Uses <tt class="docutils literal">df.assign</tt> if tgt is a native object ref; otherwise Uses <tt class="docutils literal">df.assign</tt> if tgt is a native object ref; otherwise
@ -2209,7 +2269,7 @@ throws an error.</p>
</ul> </ul>
</div> </div>
<div class="section" id="dumper"> <div class="section" id="dumper">
<h2><a class="toc-backref" href="#id35">dumper</a></h2> <h2><a class="toc-backref" href="#id37">dumper</a></h2>
<p>A third-party lua table dumper module from <p>A third-party lua table dumper module from
<a class="reference external" href="http://lua-users.org/wiki/DataDumper">http://lua-users.org/wiki/DataDumper</a>. Defines one <a class="reference external" href="http://lua-users.org/wiki/DataDumper">http://lua-users.org/wiki/DataDumper</a>. Defines one
function:</p> function:</p>
@ -2222,7 +2282,7 @@ the other arguments see the original documentation link above.</p>
</ul> </ul>
</div> </div>
<div class="section" id="class"> <div class="section" id="class">
<h2><a class="toc-backref" href="#id36">class</a></h2> <h2><a class="toc-backref" href="#id38">class</a></h2>
<p>Implements a trivial single-inheritance class system.</p> <p>Implements a trivial single-inheritance class system.</p>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">Foo = defclass(Foo[, ParentClass])</tt></p> <li><p class="first"><tt class="docutils literal">Foo = defclass(Foo[, ParentClass])</tt></p>
@ -2313,7 +2373,7 @@ library itself uses them for constructors.</p>
</div> </div>
</div> </div>
<div class="section" id="in-game-ui-library"> <div class="section" id="in-game-ui-library">
<h1><a class="toc-backref" href="#id37">In-game UI Library</a></h1> <h1><a class="toc-backref" href="#id39">In-game UI Library</a></h1>
<p>A number of lua modules with names starting with <tt class="docutils literal">gui</tt> are dedicated <p>A number of lua modules with names starting with <tt class="docutils literal">gui</tt> are dedicated
to wrapping the natives of the <tt class="docutils literal">dfhack.screen</tt> module in a way that to wrapping the natives of the <tt class="docutils literal">dfhack.screen</tt> module in a way that
is easy to use. This allows relatively easily and naturally creating is easy to use. This allows relatively easily and naturally creating
@ -2322,12 +2382,12 @@ dialogs that integrate in the main game UI window.</p>
things ranging from the basic <tt class="docutils literal">Painter</tt>, <tt class="docutils literal">View</tt> and <tt class="docutils literal">Screen</tt> things ranging from the basic <tt class="docutils literal">Painter</tt>, <tt class="docutils literal">View</tt> and <tt class="docutils literal">Screen</tt>
classes, to fully functional predefined dialogs.</p> classes, to fully functional predefined dialogs.</p>
<div class="section" id="gui"> <div class="section" id="gui">
<h2><a class="toc-backref" href="#id38">gui</a></h2> <h2><a class="toc-backref" href="#id40">gui</a></h2>
<p>This module defines the most important classes and functions for <p>This module defines the most important classes and functions for
implementing interfaces. This documents those of them that are implementing interfaces. This documents those of them that are
considered stable.</p> considered stable.</p>
<div class="section" id="misc"> <div class="section" id="misc">
<h3><a class="toc-backref" href="#id39">Misc</a></h3> <h3><a class="toc-backref" href="#id41">Misc</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">USE_GRAPHICS</tt></p> <li><p class="first"><tt class="docutils literal">USE_GRAPHICS</tt></p>
<p>Contains the value of <tt class="docutils literal">dfhack.screen.inGraphicsMode()</tt>, which cannot be <p>Contains the value of <tt class="docutils literal">dfhack.screen.inGraphicsMode()</tt>, which cannot be
@ -2366,7 +2426,7 @@ msec. This is intended for rendering blinking interface objects.</p>
</ul> </ul>
</div> </div>
<div class="section" id="viewrect-class"> <div class="section" id="viewrect-class">
<h3><a class="toc-backref" href="#id40">ViewRect class</a></h3> <h3><a class="toc-backref" href="#id42">ViewRect class</a></h3>
<p>This class represents an on-screen rectangle with an associated independent <p>This class represents an on-screen rectangle with an associated independent
clip area rectangle. It is the base of the <tt class="docutils literal">Painter</tt> class, and is used by clip area rectangle. It is the base of the <tt class="docutils literal">Painter</tt> class, and is used by
<tt class="docutils literal">Views</tt> to track their client area.</p> <tt class="docutils literal">Views</tt> to track their client area.</p>
@ -2414,7 +2474,7 @@ it with the clip area of the original object.</p>
</ul> </ul>
</div> </div>
<div class="section" id="painter-class"> <div class="section" id="painter-class">
<h3><a class="toc-backref" href="#id41">Painter class</a></h3> <h3><a class="toc-backref" href="#id43">Painter class</a></h3>
<p>The painting natives in <tt class="docutils literal">dfhack.screen</tt> apply to the whole screen, are <p>The painting natives in <tt class="docutils literal">dfhack.screen</tt> apply to the whole screen, are
completely stateless and don't implement clipping.</p> completely stateless and don't implement clipping.</p>
<p>The Painter class inherits from ViewRect to provide clipping and local <p>The Painter class inherits from ViewRect to provide clipping and local
@ -2485,7 +2545,7 @@ painter:pen(foo):seek(x,y):char(1):advance(1):string('bar')...
</pre> </pre>
</div> </div>
<div class="section" id="view-class"> <div class="section" id="view-class">
<h3><a class="toc-backref" href="#id42">View class</a></h3> <h3><a class="toc-backref" href="#id44">View class</a></h3>
<p>This class is the common abstract base of both the stand-alone screens <p>This class is the common abstract base of both the stand-alone screens
and common widgets to be used inside them. It defines the basic layout, and common widgets to be used inside them. It defines the basic layout,
rendering and event handling framework.</p> rendering and event handling framework.</p>
@ -2609,7 +2669,7 @@ Returns <em>true</em> if any of the subviews handled the event.</p>
</ul> </ul>
</div> </div>
<div class="section" id="screen-class"> <div class="section" id="screen-class">
<h3><a class="toc-backref" href="#id43">Screen class</a></h3> <h3><a class="toc-backref" href="#id45">Screen class</a></h3>
<p>This is a View subclass intended for use as a stand-alone dialog or screen. <p>This is a View subclass intended for use as a stand-alone dialog or screen.
It adds the following methods:</p> It adds the following methods:</p>
<ul> <ul>
@ -2663,7 +2723,7 @@ the screen is removed by any means here.</p>
</ul> </ul>
</div> </div>
<div class="section" id="framedscreen-class"> <div class="section" id="framedscreen-class">
<h3><a class="toc-backref" href="#id44">FramedScreen class</a></h3> <h3><a class="toc-backref" href="#id46">FramedScreen class</a></h3>
<p>A Screen subclass that paints a visible frame around its body. <p>A Screen subclass that paints a visible frame around its body.
Most dialogs should inherit from this class.</p> Most dialogs should inherit from this class.</p>
<p>A framed screen has the following attributes:</p> <p>A framed screen has the following attributes:</p>
@ -2701,10 +2761,10 @@ Most dialogs should inherit from this class.</p>
</div> </div>
</div> </div>
<div class="section" id="gui-widgets"> <div class="section" id="gui-widgets">
<h2><a class="toc-backref" href="#id45">gui.widgets</a></h2> <h2><a class="toc-backref" href="#id47">gui.widgets</a></h2>
<p>This module implements some basic widgets based on the View infrastructure.</p> <p>This module implements some basic widgets based on the View infrastructure.</p>
<div class="section" id="widget-class"> <div class="section" id="widget-class">
<h3><a class="toc-backref" href="#id46">Widget class</a></h3> <h3><a class="toc-backref" href="#id48">Widget class</a></h3>
<p>Base of all the widgets. Inherits from View and has the following attributes:</p> <p>Base of all the widgets. Inherits from View and has the following attributes:</p>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">frame = <span class="pre">{...}</span></tt></p> <li><p class="first"><tt class="docutils literal">frame = <span class="pre">{...}</span></tt></p>
@ -2770,7 +2830,7 @@ inset, or a table with the following fields:</p>
</ul> </ul>
</div> </div>
<div class="section" id="panel-class"> <div class="section" id="panel-class">
<h3><a class="toc-backref" href="#id47">Panel class</a></h3> <h3><a class="toc-backref" href="#id49">Panel class</a></h3>
<p>Inherits from Widget, and intended for grouping a number of subviews.</p> <p>Inherits from Widget, and intended for grouping a number of subviews.</p>
<p>Has attributes:</p> <p>Has attributes:</p>
<ul> <ul>
@ -2783,7 +2843,7 @@ inset, or a table with the following fields:</p>
</ul> </ul>
</div> </div>
<div class="section" id="pages-class"> <div class="section" id="pages-class">
<h3><a class="toc-backref" href="#id48">Pages class</a></h3> <h3><a class="toc-backref" href="#id50">Pages class</a></h3>
<p>Subclass of Panel; keeps exactly one child visible.</p> <p>Subclass of Panel; keeps exactly one child visible.</p>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">Pages{ <span class="pre">...,</span> selected = ... }</tt></p> <li><p class="first"><tt class="docutils literal">Pages{ <span class="pre">...,</span> selected = ... }</tt></p>
@ -2799,7 +2859,7 @@ It is permitted to use the subview object, or its <tt class="docutils literal">v
</ul> </ul>
</div> </div>
<div class="section" id="editfield-class"> <div class="section" id="editfield-class">
<h3><a class="toc-backref" href="#id49">EditField class</a></h3> <h3><a class="toc-backref" href="#id51">EditField class</a></h3>
<p>Subclass of Widget; implements a simple edit field.</p> <p>Subclass of Widget; implements a simple edit field.</p>
<p>Attributes:</p> <p>Attributes:</p>
<table class="docutils field-list" frame="void" rules="none"> <table class="docutils field-list" frame="void" rules="none">
@ -2821,7 +2881,7 @@ If it returns false, the character is ignored.</td>
</table> </table>
</div> </div>
<div class="section" id="label-class"> <div class="section" id="label-class">
<h3><a class="toc-backref" href="#id50">Label class</a></h3> <h3><a class="toc-backref" href="#id52">Label class</a></h3>
<p>This Widget subclass implements flowing semi-static text.</p> <p>This Widget subclass implements flowing semi-static text.</p>
<p>It has the following attributes:</p> <p>It has the following attributes:</p>
<table class="docutils field-list" frame="void" rules="none"> <table class="docutils field-list" frame="void" rules="none">
@ -2917,7 +2977,7 @@ this may be extended with mouse click support.</p>
</ul> </ul>
</div> </div>
<div class="section" id="list-class"> <div class="section" id="list-class">
<h3><a class="toc-backref" href="#id51">List class</a></h3> <h3><a class="toc-backref" href="#id53">List class</a></h3>
<p>The List widget implements a simple list with paging.</p> <p>The List widget implements a simple list with paging.</p>
<p>It has the following attributes:</p> <p>It has the following attributes:</p>
<table class="docutils field-list" frame="void" rules="none"> <table class="docutils field-list" frame="void" rules="none">
@ -3003,7 +3063,7 @@ with the following fields:</p>
</ul> </ul>
</div> </div>
<div class="section" id="filteredlist-class"> <div class="section" id="filteredlist-class">
<h3><a class="toc-backref" href="#id52">FilteredList class</a></h3> <h3><a class="toc-backref" href="#id54">FilteredList class</a></h3>
<p>This widget combines List, EditField and Label into a combo-box like <p>This widget combines List, EditField and Label into a combo-box like
construction that allows filtering the list by subwords of its items.</p> construction that allows filtering the list by subwords of its items.</p>
<p>In addition to passing through all attributes supported by List, it <p>In addition to passing through all attributes supported by List, it
@ -3056,14 +3116,14 @@ index <tt class="docutils literal">pos</tt> in the <em>unfiltered</em> list if p
</div> </div>
</div> </div>
<div class="section" id="plugins"> <div class="section" id="plugins">
<h1><a class="toc-backref" href="#id53">Plugins</a></h1> <h1><a class="toc-backref" href="#id55">Plugins</a></h1>
<p>DFHack plugins may export native functions and events <p>DFHack plugins may export native functions and events
to lua contexts. They are automatically imported by to lua contexts. They are automatically imported by
<tt class="docutils literal"><span class="pre">mkmodule('plugins.&lt;name&gt;')</span></tt>; this means that a lua <tt class="docutils literal"><span class="pre">mkmodule('plugins.&lt;name&gt;')</span></tt>; this means that a lua
module file is still necessary for <tt class="docutils literal">require</tt> to read.</p> module file is still necessary for <tt class="docutils literal">require</tt> to read.</p>
<p>The following plugins have lua support.</p> <p>The following plugins have lua support.</p>
<div class="section" id="burrows"> <div class="section" id="burrows">
<h2><a class="toc-backref" href="#id54">burrows</a></h2> <h2><a class="toc-backref" href="#id56">burrows</a></h2>
<p>Implements extended burrow manipulations.</p> <p>Implements extended burrow manipulations.</p>
<p>Events:</p> <p>Events:</p>
<ul> <ul>
@ -3101,16 +3161,16 @@ set is the same as used by the command line.</p>
<p>The lua module file also re-exports functions from <tt class="docutils literal">dfhack.burrows</tt>.</p> <p>The lua module file also re-exports functions from <tt class="docutils literal">dfhack.burrows</tt>.</p>
</div> </div>
<div class="section" id="sort"> <div class="section" id="sort">
<h2><a class="toc-backref" href="#id55">sort</a></h2> <h2><a class="toc-backref" href="#id57">sort</a></h2>
<p>Does not export any native functions as of now. Instead, it <p>Does not export any native functions as of now. Instead, it
calls lua code to perform the actual ordering of list items.</p> calls lua code to perform the actual ordering of list items.</p>
</div> </div>
<div class="section" id="eventful"> <div class="section" id="eventful">
<h2><a class="toc-backref" href="#id56">Eventful</a></h2> <h2><a class="toc-backref" href="#id58">Eventful</a></h2>
<p>This plugin exports some events to lua thus allowing to run lua functions <p>This plugin exports some events to lua thus allowing to run lua functions
on DF world events.</p> on DF world events.</p>
<div class="section" id="list-of-events"> <div class="section" id="list-of-events">
<h3><a class="toc-backref" href="#id57">List of events</a></h3> <h3><a class="toc-backref" href="#id59">List of events</a></h3>
<ol class="arabic"> <ol class="arabic">
<li><p class="first"><tt class="docutils literal">onReactionComplete(reaction,unit,input_items,input_reagents,output_items,call_native)</tt></p> <li><p class="first"><tt class="docutils literal">onReactionComplete(reaction,unit,input_items,input_reagents,output_items,call_native)</tt></p>
<p>Auto activates if detects reactions starting with <tt class="docutils literal">LUA_HOOK_</tt>. Is called when reaction finishes.</p> <p>Auto activates if detects reactions starting with <tt class="docutils literal">LUA_HOOK_</tt>. Is called when reaction finishes.</p>
@ -3140,7 +3200,7 @@ tweaking (e.g. adding custom reactions)</p>
</ol> </ol>
</div> </div>
<div class="section" id="events-from-eventmanager"> <div class="section" id="events-from-eventmanager">
<h3><a class="toc-backref" href="#id58">Events from EventManager</a></h3> <h3><a class="toc-backref" href="#id60">Events from EventManager</a></h3>
<p>These events are straight from EventManager module. Each of them first needs to be enabled. See functions for more info. If you register a listener before the game is loaded, be aware that no events will be triggered immediately after loading, so you might need to add another event listener for when the game first loads in some cases.</p> <p>These events are straight from EventManager module. Each of them first needs to be enabled. See functions for more info. If you register a listener before the game is loaded, be aware that no events will be triggered immediately after loading, so you might need to add another event listener for when the game first loads in some cases.</p>
<ol class="arabic"> <ol class="arabic">
<li><p class="first"><tt class="docutils literal">onBuildingCreatedDestroyed(building_id)</tt></p> <li><p class="first"><tt class="docutils literal">onBuildingCreatedDestroyed(building_id)</tt></p>
@ -3173,7 +3233,7 @@ tweaking (e.g. adding custom reactions)</p>
</ol> </ol>
</div> </div>
<div class="section" id="functions"> <div class="section" id="functions">
<h3><a class="toc-backref" href="#id59">Functions</a></h3> <h3><a class="toc-backref" href="#id61">Functions</a></h3>
<ol class="arabic"> <ol class="arabic">
<li><p class="first"><tt class="docutils literal">registerReaction(reaction_name,callback)</tt></p> <li><p class="first"><tt class="docutils literal">registerReaction(reaction_name,callback)</tt></p>
<p>Simplified way of using onReactionComplete; the callback is function (same params as event).</p> <p>Simplified way of using onReactionComplete; the callback is function (same params as event).</p>
@ -3187,10 +3247,13 @@ tweaking (e.g. adding custom reactions)</p>
<li><p class="first"><tt class="docutils literal">enableEvent(evType,frequency)</tt></p> <li><p class="first"><tt class="docutils literal">enableEvent(evType,frequency)</tt></p>
<p>Enable event checking for EventManager events. For event types use <tt class="docutils literal">eventType</tt> table. Note that different types of events require different frequencies to be effective. The frequency is how many ticks EventManager will wait before checking if that type of event has happened. If multiple scripts or plugins use the same event type, the smallest frequency is the one that is used, so you might get events triggered more often than the frequency you use here.</p> <p>Enable event checking for EventManager events. For event types use <tt class="docutils literal">eventType</tt> table. Note that different types of events require different frequencies to be effective. The frequency is how many ticks EventManager will wait before checking if that type of event has happened. If multiple scripts or plugins use the same event type, the smallest frequency is the one that is used, so you might get events triggered more often than the frequency you use here.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">registerSidebar(shop_name,callback)</tt></p>
<p>Enable callback when sidebar for <tt class="docutils literal">shop_name</tt> is drawn. Usefull for custom workshop views e.g. using gui.dwarfmode lib.</p>
</li>
</ol> </ol>
</div> </div>
<div class="section" id="examples"> <div class="section" id="examples">
<h3><a class="toc-backref" href="#id60">Examples</a></h3> <h3><a class="toc-backref" href="#id62">Examples</a></h3>
<p>Spawn dragon breath on each item attempt to contaminate wound:</p> <p>Spawn dragon breath on each item attempt to contaminate wound:</p>
<pre class="literal-block"> <pre class="literal-block">
b=require &quot;plugins.eventful&quot; b=require &quot;plugins.eventful&quot;
@ -3202,13 +3265,13 @@ end
<pre class="literal-block"> <pre class="literal-block">
b=require &quot;plugins.eventful&quot; b=require &quot;plugins.eventful&quot;
b.onReactionComplete.one=function(reaction,unit,in_items,in_reag,out_items,call_native) b.registerReaction(&quot;LUA_HOOK_LAY_BOMB&quot;,function(reaction,unit,in_items,in_reag,out_items,call_native)
local pos=copyall(unit.pos) local pos=copyall(unit.pos)
-- spawn dragonbreath after 100 ticks -- spawn dragonbreath after 100 ticks
dfhack.timeout(100,&quot;ticks&quot;,function() dfhack.maps.spawnFlow(pos,6,0,0,50000) end) dfhack.timeout(100,&quot;ticks&quot;,function() dfhack.maps.spawnFlow(pos,6,0,0,50000) end)
--do not call real item creation code --do not call real item creation code
call_native.value=false call_native.value=false
end end)
</pre> </pre>
<p>Grenade example:</p> <p>Grenade example:</p>
<pre class="literal-block"> <pre class="literal-block">
@ -3225,9 +3288,57 @@ b.addReactionToShop(&quot;TAN_A_HIDE&quot;,&quot;LEATHERWORKS&quot;)
</pre> </pre>
</div> </div>
</div> </div>
<div class="section" id="building-hacks">
<h2><a class="toc-backref" href="#id63">Building-hacks</a></h2>
<p>This plugin overwrites some methods in workshop df class so that mechanical workshops are possible. Although
plugin export a function it's recommended to use lua decorated function.</p>
<div class="section" id="id1">
<h3><a class="toc-backref" href="#id64">Functions</a></h3>
<dl class="docutils">
<dt><tt class="docutils literal">registerBuilding(table)</tt> where table must contain name, as a workshop raw name, the rest are optional:</dt>
<dd><ol class="first last arabic simple">
<li>name -- custom workshop id e.g. <tt class="docutils literal">SOAPMAKER</tt></li>
<li>fix_impassible -- if true make impassible tiles impassible to liquids too</li>
<li>consume -- how much machine power is needed to work. Disables reactions if not supplied enough</li>
<li>produce -- how much machine power is produced. Use discouraged as there is no way to change this at runtime</li>
<li>gears -- a table or <tt class="docutils literal"><span class="pre">{x=?,y=?}</span></tt> of connection points for machines</li>
<li>action -- a table of number (how much ticks to skip) and a function which gets called on shop update</li>
<li>animate -- a table of frames which can be a table of:<ol class="loweralpha">
<li>tables of 4 numbers <tt class="docutils literal">{tile,fore,back,bright}</tt> OR</li>
<li>empty table (tile not modified) OR</li>
<li><tt class="docutils literal"><span class="pre">{x=&lt;number&gt;</span> <span class="pre">y=&lt;number&gt;</span> + 4 numbers like in first case}</tt>, this generates full frame useful for animations that change little (1-2 tiles)</li>
</ol>
</li>
</ol>
</dd>
<dt>Animate table also might contain:</dt>
<dd><ol class="first last arabic simple">
<li>frameLenght -- how many ticks does one frame take OR</li>
<li>isMechanical -- a bool that says to try to match to mechanical system (i.e. how gears are turning)</li>
</ol>
</dd>
</dl>
</div>
<div class="section" id="id2">
<h3><a class="toc-backref" href="#id65">Examples</a></h3>
<p>Simple mechanical workshop:</p>
<pre class="literal-block">
require('plugins.building-hacks').registerBuilding{name=&quot;BONE_GRINDER&quot;,
consume=15,
gears={x=0,y=0}, --connection point
animate={
isMechanical=true, --animate the same connection point as vanilla gear
frames={
{{x=0,y=0,42,7,0,0}}, --first frame, 1 changed tile
{{x=0,y=0,15,7,0,0}} -- second frame, same
}
}
</pre>
</div>
</div>
</div> </div>
<div class="section" id="scripts"> <div class="section" id="scripts">
<h1><a class="toc-backref" href="#id61">Scripts</a></h1> <h1><a class="toc-backref" href="#id66">Scripts</a></h1>
<p>Any files with the .lua extension placed into hack/scripts/* <p>Any files with the .lua extension placed into hack/scripts/*
are automatically used by the DFHack core as commands. The are automatically used by the DFHack core as commands. The
matching command name consists of the name of the file sans matching command name consists of the name of the file sans
@ -3258,10 +3369,11 @@ The <tt class="docutils literal">name</tt> argument should be the name stem, as
</ul> </ul>
<p>Note that this function lets errors propagate to the caller.</p> <p>Note that this function lets errors propagate to the caller.</p>
<div class="section" id="save-init-script"> <div class="section" id="save-init-script">
<h2><a class="toc-backref" href="#id62">Save init script</a></h2> <h2><a class="toc-backref" href="#id67">Save init script</a></h2>
<p>If a save directory contains a file called <tt class="docutils literal">raw/init.lua</tt>, it is <p>If a save directory contains a file called <tt class="docutils literal">raw/init.lua</tt>, it is
automatically loaded and executed every time the save is loaded. It automatically loaded and executed every time the save is loaded.
can also define the following functions to be called by dfhack:</p> The same applies to any files called <tt class="docutils literal"><span class="pre">raw/init.d/*.lua</span></tt>. Every
such script can define the following functions to be called by dfhack:</p>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">function onStateChange(op) ... end</tt></p> <li><p class="first"><tt class="docutils literal">function onStateChange(op) ... end</tt></p>
<p>Automatically called from the regular onStateChange event as long <p>Automatically called from the regular onStateChange event as long
@ -3271,7 +3383,8 @@ cleanup concerns.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">function onUnload() ... end</tt></p> <li><p class="first"><tt class="docutils literal">function onUnload() ... end</tt></p>
<p>Called when the save containing the script is unloaded. This function <p>Called when the save containing the script is unloaded. This function
should clean up any global hooks installed by the script.</p> should clean up any global hooks installed by the script. Note that
when this is called, the world is already completely unloaded.</p>
</li> </li>
</ul> </ul>
<p>Within the init script, the path to the save directory is available as <tt class="docutils literal">SAVE_PATH</tt>.</p> <p>Within the init script, the path to the save directory is available as <tt class="docutils literal">SAVE_PATH</tt>.</p>

@ -25,9 +25,10 @@ implemented by Lua files located in hack/lua/...
DF data structure wrapper DF data structure wrapper
========================= =========================
DF structures described by the xml files in library/xml are exported Data structures of the game are defined in XML files located in library/xml
to lua code as a tree of objects and functions under the ``df`` global, (and online at http://github.com/DFHack/df-structures), and automatically exported
which broadly maps to the ``df`` namespace in C++. to lua code as a tree of objects and functions under the ``df`` global, which
also broadly maps to the ``df`` namespace in the headers generated for C++.
**WARNING**: The wrapper provides almost raw access to the memory **WARNING**: The wrapper provides almost raw access to the memory
of the game, so mistakes in manipulating objects are as likely to of the game, so mistakes in manipulating objects are as likely to
@ -812,6 +813,14 @@ can be omitted.
Convert a language_name or only the last name part to string. Convert a language_name or only the last name part to string.
* ``dfhack.df2utf(string)``
Convert a string from DF's CP437 encoding to UTF-8.
* ``dfhack.utf2df(string)``
Convert a string from UTF-8 to DF's CP437 encoding.
Gui module Gui module
---------- ----------
@ -854,6 +863,32 @@ Gui module
Returns the building selected via *'q'*, *'t'*, *'k'* or *'i'*. Returns the building selected via *'q'*, *'t'*, *'k'* or *'i'*.
* ``dfhack.gui.writeToGamelog(text)``
Writes a string to gamelog.txt without doing an announcement.
* ``dfhack.gui.makeAnnouncement(type,flags,pos,text,color[,is_bright])``
Adds an announcement with given announcement_type, text, color, and brightness.
The is_bright boolean actually seems to invert the brightness.
The announcement is written to gamelog.txt. The announcement_flags
argument provides a custom set of announcements.txt options,
which specify if the message should actually be displayed in the
announcement list, and whether to recenter or show a popup.
Returns the index of the new announcement in ``df.global.world.status.reports``, or -1.
* ``dfhack.gui.addCombatReport(unit,slot,report_index)``
Adds the report with the given index (returned by makeAnnouncement)
to the specified group of the given unit. Returns *true* on success.
* ``dfhack.gui.addCombatReportAuto(unit,flags,report_index)``
Adds the report with the given index to the appropriate group(s)
of the given unit, as requested by the flags.
* ``dfhack.gui.showAnnouncement(text,color[,is_bright])`` * ``dfhack.gui.showAnnouncement(text,color[,is_bright])``
Adds a regular announcement with given text, color, and brightness. Adds a regular announcement with given text, color, and brightness.
@ -867,10 +902,10 @@ Gui module
Pops up a titan-style modal announcement window. Pops up a titan-style modal announcement window.
* ``dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright])`` * ``dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright,unit1,unit2])``
Uses the type to look up options from announcements.txt, and calls the Uses the type to look up options from announcements.txt, and calls the above
above operations accordingly. If enabled, pauses and zooms to position. operations accordingly. The units are used to call ``addCombatReportAuto``.
Job module Job module
@ -904,6 +939,16 @@ Job module
Returns the unit performing the job. Returns the unit performing the job.
* ``dfhack.job.setJobCooldown(building,worker,timeout)``
Prevent the worker from taking jobs at the specified workshop for the specified time.
This doesn't decrease the timeout in any circumstances.
* ``dfhack.job.removeWorker(job,timeout)``
Removes the worker from the specified workshop job, and sets the cooldown.
Returns *true* on success.
* ``dfhack.job.checkBuildingsNow()`` * ``dfhack.job.checkBuildingsNow()``
Instructs the game to check buildings for jobs next frame and assign workers. Instructs the game to check buildings for jobs next frame and assign workers.
@ -935,6 +980,10 @@ Job module
Likewise, if replacing material. Likewise, if replacing material.
* ``dfhack.job.getName(job)``
Returns the job's description, as seen in the Units and Jobs screens.
Units module Units module
------------ ------------
@ -1033,6 +1082,11 @@ Units module
Computes number of frames * 100 it takes the unit to move in its current state of mind and body. Computes number of frames * 100 it takes the unit to move in its current state of mind and body.
* ``dfhack.units.computeSlowdownFactor(unit)``
Meandering and floundering in liquid introduces additional slowdown. It is
random, but the function computes and returns the expected mean factor as a float.
* ``dfhack.units.getNoblePositions(unit)`` * ``dfhack.units.getNoblePositions(unit)``
Returns a list of tables describing noble position assignments, or *nil*. Returns a list of tables describing noble position assignments, or *nil*.
@ -1138,6 +1192,14 @@ Items module
Returns the raw definition for the given item type and subtype, or *nil* if invalid. Returns the raw definition for the given item type and subtype, or *nil* if invalid.
* ``dfhack.items.getItemBaseValue(item_type, subtype, material, mat_index)``
Calculates the base value for an item of the specified type and material.
* ``dfhack.items.getValue(item)``
Calculates the Basic Value of an item, as seen in the View Item screen.
Maps module Maps module
----------- -----------
@ -1760,6 +1822,10 @@ and are only documented here for completeness:
The oldval, newval or delta arguments may be used to specify additional constraints. The oldval, newval or delta arguments may be used to specify additional constraints.
Returns: *found_index*, or *nil* if end reached. Returns: *found_index*, or *nil* if end reached.
* ``dfhack.internal.getDir(path)``
List files in a directory.
Returns: *file_names* or empty table if not found.
Core interpreter context Core interpreter context
======================== ========================
@ -1992,6 +2058,10 @@ utils
way enables applying the same permutation to multiple arrays. way enables applying the same permutation to multiple arrays.
This function is used by the sort plugin. This function is used by the sort plugin.
* ``for link,item in utils.listpairs(list)``
Iterates a df-list structure, for example ``df.global.world.job_list``.
* ``utils.assign(tgt, src)`` * ``utils.assign(tgt, src)``
Does a recursive assignment of src into tgt. Does a recursive assignment of src into tgt.
@ -3110,6 +3180,10 @@ Functions
Enable event checking for EventManager events. For event types use ``eventType`` table. Note that different types of events require different frequencies to be effective. The frequency is how many ticks EventManager will wait before checking if that type of event has happened. If multiple scripts or plugins use the same event type, the smallest frequency is the one that is used, so you might get events triggered more often than the frequency you use here. Enable event checking for EventManager events. For event types use ``eventType`` table. Note that different types of events require different frequencies to be effective. The frequency is how many ticks EventManager will wait before checking if that type of event has happened. If multiple scripts or plugins use the same event type, the smallest frequency is the one that is used, so you might get events triggered more often than the frequency you use here.
5. ``registerSidebar(shop_name,callback)``
Enable callback when sidebar for ``shop_name`` is drawn. Usefull for custom workshop views e.g. using gui.dwarfmode lib.
Examples Examples
-------- --------
Spawn dragon breath on each item attempt to contaminate wound:: Spawn dragon breath on each item attempt to contaminate wound::
@ -3123,13 +3197,13 @@ Reaction complete example::
b=require "plugins.eventful" b=require "plugins.eventful"
b.onReactionComplete.one=function(reaction,unit,in_items,in_reag,out_items,call_native) b.registerReaction("LUA_HOOK_LAY_BOMB",function(reaction,unit,in_items,in_reag,out_items,call_native)
local pos=copyall(unit.pos) local pos=copyall(unit.pos)
-- spawn dragonbreath after 100 ticks -- spawn dragonbreath after 100 ticks
dfhack.timeout(100,"ticks",function() dfhack.maps.spawnFlow(pos,6,0,0,50000) end) dfhack.timeout(100,"ticks",function() dfhack.maps.spawnFlow(pos,6,0,0,50000) end)
--do not call real item creation code --do not call real item creation code
call_native.value=false call_native.value=false
end end)
Grenade example:: Grenade example::
@ -3144,6 +3218,48 @@ Integrated tannery::
b=require "plugins.eventful" b=require "plugins.eventful"
b.addReactionToShop("TAN_A_HIDE","LEATHERWORKS") b.addReactionToShop("TAN_A_HIDE","LEATHERWORKS")
Building-hacks
==============
This plugin overwrites some methods in workshop df class so that mechanical workshops are possible. Although
plugin export a function it's recommended to use lua decorated function.
Functions
---------
``registerBuilding(table)`` where table must contain name, as a workshop raw name, the rest are optional:
1. name -- custom workshop id e.g. ``SOAPMAKER``
2. fix_impassible -- if true make impassible tiles impassible to liquids too
3. consume -- how much machine power is needed to work. Disables reactions if not supplied enough
4. produce -- how much machine power is produced. Use discouraged as there is no way to change this at runtime
5. gears -- a table or ``{x=?,y=?}`` of connection points for machines
6. action -- a table of number (how much ticks to skip) and a function which gets called on shop update
7. animate -- a table of frames which can be a table of:
a. tables of 4 numbers ``{tile,fore,back,bright}`` OR
b. empty table (tile not modified) OR
c. ``{x=<number> y=<number> + 4 numbers like in first case}``, this generates full frame useful for animations that change little (1-2 tiles)
Animate table also might contain:
1. frameLenght -- how many ticks does one frame take OR
2. isMechanical -- a bool that says to try to match to mechanical system (i.e. how gears are turning)
Examples
--------
Simple mechanical workshop::
require('plugins.building-hacks').registerBuilding{name="BONE_GRINDER",
consume=15,
gears={x=0,y=0}, --connection point
animate={
isMechanical=true, --animate the same connection point as vanilla gear
frames={
{{x=0,y=0,42,7,0,0}}, --first frame, 1 changed tile
{{x=0,y=0,15,7,0,0}} -- second frame, same
}
}
======= =======
Scripts Scripts
======= =======
@ -3187,8 +3303,9 @@ Save init script
================ ================
If a save directory contains a file called ``raw/init.lua``, it is If a save directory contains a file called ``raw/init.lua``, it is
automatically loaded and executed every time the save is loaded. It automatically loaded and executed every time the save is loaded.
can also define the following functions to be called by dfhack: The same applies to any files called ``raw/init.d/*.lua``. Every
such script can define the following functions to be called by dfhack:
* ``function onStateChange(op) ... end`` * ``function onStateChange(op) ... end``
@ -3200,6 +3317,7 @@ can also define the following functions to be called by dfhack:
* ``function onUnload() ... end`` * ``function onUnload() ... end``
Called when the save containing the script is unloaded. This function Called when the save containing the script is unloaded. This function
should clean up any global hooks installed by the script. should clean up any global hooks installed by the script. Note that
when this is called, the world is already completely unloaded.
Within the init script, the path to the save directory is available as ``SAVE_PATH``. Within the init script, the path to the save directory is available as ``SAVE_PATH``.

31
NEWS

@ -1,6 +1,35 @@
DFHack future DFHack future
- Is not yet known. Internals:
- support for calling a lua function via a protobuf request (demonstrated by dfhack-run --lua).
- Lua API for listing files in directory. Needed for mod-manager.
- Lua API for creating unit combat reports and writing to gamelog.
- support for multiple raw/init.d/*.lua init scripts in one save.
- eventful now has a more friendly way of making custom sidebars
- new plugin: building-hacks. Allows to add custom functionality and/or animations to buildings.
New scripts:
- gui/mod-manager: allows installing/uninstalling mods into df from df/mods directory.
- gui/clone-uniform: duplicates the currently selected uniform in the military screen.
- fix/build-location: partial work-around for bug 5991 (trying to build wall while standing on it)
- undump-buildings: removes dump designation from materials used in buildings.
New commands:
- move the 'grow', 'extirpate' and 'immolate' commands as 'plant' subcommands
- 'plant create' - spawn a new shrub under the cursor
- command-prompt: a dfhack command prompt in df.
Misc improvements:
- digfort: improved csv parsing, add start() comment handling
- exterminate: allow specifying a caste (exterminate gob:male)
- createitem: in adventure mode it now defaults to the controlled unit as maker.
Siege engine plugin:
- engine quality and distance to target now affect accuracy
- firing the siege engine at a target produces a combat report
- improved movement speed computation for meandering units
- operators in Prepare To Fire mode are released from duty once
hungry/thirsty if there is a free replacement
DFHack v0.34.11-r4 DFHack v0.34.11-r4

File diff suppressed because it is too large Load Diff

@ -28,15 +28,15 @@ All new releases are announced in the bay12 thread: http://tinyurl.com/dfhack-ng
============= =============
Compatibility Compatibility
============= =============
DFHack works on Windows XP, Vista, 7 or any modern Linux distribution. DFHack works on Windows XP, Vista, 7, any modern Linux distribution, or OS X
OSX is not supported due to lack of developers with a Mac. 10.6.8-10.9.
Currently, version 0.34.11 is supported (and tested). If you need DFHack Currently, version 0.34.11 is supported (and tested). If you need DFHack
for older versions, look for older releases. for older versions, look for older releases.
On Windows, you have to use the SDL version of DF. On Windows, you have to use the SDL version of DF.
It is possible to use the Windows DFHack under wine/OSX. It is also possible to use the Windows DFHack with Wine under Linux and OS X.
==================== ====================
Installation/Removal Installation/Removal
@ -329,6 +329,13 @@ Options:
The building must be one of stockpile, workshop, furnace, trap, The building must be one of stockpile, workshop, furnace, trap,
siege engine or an activity zone. siege engine or an activity zone.
command-prompt
--------------
A one line command prompt in df. Same as entering command into dfhack console. Best
used as a keybinding. Can be called with optional "entry" that will start prompt with
that pre-filled.
.. image:: images/command-prompt.png
Adventure mode Adventure mode
============== ==============
@ -489,7 +496,7 @@ Options:
createitem createitem
---------- ----------
Allows creating new items of arbitrary types and made of arbitrary materials. Allows creating new items of arbitrary types and made of arbitrary materials.
Any items created are spawned at the feet of the selected unit. By default, items created are spawned at the feet of the selected unit.
Specify the item and material information as you would indicate them in custom reaction raws, with the following differences: Specify the item and material information as you would indicate them in custom reaction raws, with the following differences:
* Separate the item and material with a space rather than a colon * Separate the item and material with a space rather than a colon
@ -506,6 +513,14 @@ Examples:
``createitem FISH FISH_SHAD:MALE 5`` ``createitem FISH FISH_SHAD:MALE 5``
Create a stack of 5 cleaned shad, ready to eat. Create a stack of 5 cleaned shad, ready to eat.
To change where new items are placed, first run the command with a destination type while an appropriate destination is selected.
Options:
:floor: Subsequent items will be placed on the floor beneath the selected unit's feet.
:item: Subsequent items will be stored inside the currently selected item.
:building: Subsequent items will become part of the currently selected building. Best used for loading traps; do not use with workshops, or you will need to deconstruct the building to use the item.
deramp (by zilpin) deramp (by zilpin)
------------------ ------------------
Removes all ramps designated for removal from the map. This is useful for replicating the old channel digging designation. Removes all ramps designated for removal from the map. This is useful for replicating the old channel digging designation.
@ -676,29 +691,39 @@ tile. Can be used from a hotkey.
tubefill tubefill
-------- --------
Fills all the adamantine veins again. Veins that were empty will be filled in Fills all the adamantine veins again. Veins that were hollow will be left
too, but might still trigger a demon invasion (this is a known bug). alone.
extirpate
---------
A tool for getting rid of trees and shrubs. By default, it only kills
a tree/shrub under the cursor. The plants are turned into ashes instantly.
Options: Options:
:hollow: fill in naturally hollow veins too
Beware that filling in hollow veins will trigger a demon invasion on top of
your miner when you dig into the region that used to be hollow.
plant
-----
A tool for creating shrubs, growing, or getting rid of them.
Subcommands:
:create: Create a new shrub/sapling.
:grow: Make saplings grow into trees.
:extirpate: Kills trees and shrubs, turning them into ashes instantly.
:immolate: Similar to extirpate, but sets the plants on fire instead. The fires can and *will* spread ;)
``create`` creates a new sapling under the cursor. Takes a raw ID as
argument (e.g. TOWER_CAP). The cursor must be located on a dirt or grass
floor tile.
``grow`` works on the sapling under the cursor, and turns it into a tree.
Works on all shrubs of the map if the cursor is hidden.
``extirpate`` and ``immolate`` work only on the plant under the cursor.
For mass effects, use one of the additional options:
:shrubs: affect all shrubs on the map :shrubs: affect all shrubs on the map
:trees: affect all trees on the map :trees: affect all trees on the map
:all: affect every plant! :all: affect every plant!
grow
----
Makes all saplings present on the map grow into trees (almost) instantly.
immolate
--------
Very similar to extirpate, but additionally sets the plants on fire. The fires
can and *will* spread ;)
regrass regrass
------- -------
Regrows grass. Not much to it ;) Regrows grass. Not much to it ;)
@ -1959,6 +1984,21 @@ Usage:
:misery disable: stop adding new negative thoughts. This will not remove existing duplicated thoughts. Equivalent to "misery 1" :misery disable: stop adding new negative thoughts. This will not remove existing duplicated thoughts. Equivalent to "misery 1"
:misery clear: remove fake thoughts added in this session of DF. Saving makes them permanent! Does not change factor. :misery clear: remove fake thoughts added in this session of DF. Saving makes them permanent! Does not change factor.
strangemood
-----------
Creates a strange mood job the same way the game itself normally does it.
Options:
:-force: Ignore normal strange mood preconditions (no recent mood, minimum moodable population, artifact limit not reached).
:-unit: Make the strange mood strike the selected unit instead of picking one randomly. Unit eligibility is still enforced.
:-type T: Force the mood to be of a particular type instead of choosing randomly based on happiness.
Valid values are "fey", "secretive", "possessed", "fell", and "macabre".
:-skill S: Force the mood to use a specific skill instead of choosing the highest moodable skill.
Valid values are "miner", "carpenter", "engraver", "mason", "tanner", "weaver", "clothier", "weaponsmith", "armorsmith", "metalsmith", "gemcutter", "gemsetter", "woodcrafter", "stonecrafter", "metalcrafter", "glassmaker", "leatherworker", "bonecarver", "bowyer", and "mechanic".
Known limitations: if the selected unit is currently performing a job, the mood will not be started.
======= =======
Scripts Scripts
======= =======
@ -2009,6 +2049,13 @@ Scripts in this subdirectory fix various bugs and issues, some of them obscure.
every time a save game is loaded; putting ``fix/cloth-stockpile enable`` every time a save game is loaded; putting ``fix/cloth-stockpile enable``
in ``dfhack.init`` makes it run automatically. in ``dfhack.init`` makes it run automatically.
* fix/build-location
Fixes construction jobs that are stuck trying to build a wall while standing
on the same exact tile (bug 5991), designates the tile restricted traffic to
hopefully avoid jamming it again, and unsuspends them.
gui/* gui/*
===== =====
@ -2092,6 +2139,9 @@ With the special argument ``him``, targets only the selected creature.
With the special argument ``undead``, targets all undeads on the map, With the special argument ``undead``, targets all undeads on the map,
regardless of their race. regardless of their race.
When specifying a race, a caste can be specified to further restrict the
targeting. To do that, append and colon and the caste name after the race.
Any non-dead non-caged unit of the specified race gets its ``blood_count`` Any non-dead non-caged unit of the specified race gets its ``blood_count``
set to 0, which means immediate death at the next game tick. For creatures set to 0, which means immediate death at the next game tick. For creatures
such as vampires, it also sets animal.vanish_countdown to 2. such as vampires, it also sets animal.vanish_countdown to 2.
@ -2107,6 +2157,7 @@ but ignore caged/chained creatures.
Ex:: Ex::
exterminate gob exterminate gob
exterminate gob:male
To kill a single creature, select the unit with the 'v' cursor and:: To kill a single creature, select the unit with the 'v' cursor and::
@ -2171,7 +2222,12 @@ Unrecognized characters are ignored (eg the 'skip this tile' in the sample).
Empty lines and data after a ``#`` are ignored as comments. Empty lines and data after a ``#`` are ignored as comments.
To skip a row in your design, use a single ``;``. To skip a row in your design, use a single ``;``.
The script takes the plan filename, starting from the root df folder. One comment in the file may contain the phrase ``start(3,5)``. It is interpreted
as an offset for the pattern: instead of starting at the cursor, it will start
3 tiles left and 5 tiles up from the cursor.
The script takes the plan filename, starting from the root df folder (where
Dwarf Fortress.exe is found).
invasion-now invasion-now
============ ============
@ -2185,6 +2241,7 @@ Triggers an invasion, or several in the near future.
`invasion-now civName start end` trigger an invasion from civName in about 10*start ticks, and continue triggering invasions every ten ticks afterward until about 10*end ticks have passed `invasion-now civName start end` trigger an invasion from civName in about 10*start ticks, and continue triggering invasions every ten ticks afterward until about 10*end ticks have passed
Probably fails if the start time of a triggered invasion is later than the start of the next year. Probably fails if the start time of a triggered invasion is later than the start of the next year.
digmat digmat
====== ======
Designates a tile for digging. Monitors the tile, and when it is dug out, add Designates a tile for digging. Monitors the tile, and when it is dug out, add
@ -2278,6 +2335,10 @@ alternatively pass cage IDs as arguments::
stripcaged weapons 25321 34228 stripcaged weapons 25321 34228
undump-buildings
================
Undesignates building base materials for dumping.
create-items create-items
============ ============
Spawn arbitrary items under the cursor. Spawn arbitrary items under the cursor.
@ -2357,12 +2418,16 @@ are mostly implemented by lua scripts.
As an exception, the tweak plugin described above does not follow this As an exception, the tweak plugin described above does not follow this
guideline because it arguably just fixes small usability bugs in the game UI. guideline because it arguably just fixes small usability bugs in the game UI.
All of these tools are disabled by default - in order to make them available,
you must enable the plugins which provide them.
Dwarf Manipulator Dwarf Manipulator
================= =================
Implemented by the manipulator plugin. To activate, open the unit screen and Implemented by the 'manipulator' plugin.
press 'l'.
To activate, open the unit screen and press 'l'.
.. image:: images/manipulator.png .. image:: images/manipulator.png
@ -2412,6 +2477,8 @@ directly to the main dwarf mode screen.
Search Search
====== ======
Implemented by the 'search' plugin.
The search plugin adds search to the Stocks, Animals, Trading, Stockpile, The search plugin adds search to the Stocks, Animals, Trading, Stockpile,
Noble (assignment candidates), Military (position candidates), Burrows Noble (assignment candidates), Military (position candidates), Burrows
(unit list), Rooms, Announcements, Job List and Unit List screens. (unit list), Rooms, Announcements, Job List and Unit List screens.
@ -2452,9 +2519,11 @@ using Permit Fats again while the list is filtered.
AutoMaterial AutoMaterial
============ ============
The automaterial plugin makes building constructions (walls, floors, fortifications, Implemented by the 'automaterial' plugin.
etc) a little bit easier by saving you from having to trawl through long lists of
materials each time you place one. This makes building constructions (walls, floors, fortifications, etc) a little bit
easier by saving you from having to trawl through long lists of materials each time
you place one.
Firstly, it moves the last used material for a given construction type to the top of Firstly, it moves the last used material for a given construction type to the top of
the list, if there are any left. So if you build a wall with chalk blocks, the next the list, if there are any left. So if you build a wall with chalk blocks, the next
@ -2585,6 +2654,16 @@ Rationale: individual choice seems to be unreliable when there is a weapon short
and may lead to inappropriate weapons being selected. and may lead to inappropriate weapons being selected.
gui/clone-uniform
=================
Bind to a key (the example config uses Ctrl-C), and activate in the Uniforms
page of the military screen with the cursor in the leftmost list.
When invoked, the script duplicates the currently selected uniform template,
and selects the newly created copy.
gui/guide-path gui/guide-path
============== ==============
@ -2739,7 +2818,7 @@ of currently assigned racks for every valid squad.
gui/advfort gui/advfort
============= ===========
This script allows to perform jobs in adventure mode. For more complete help This script allows to perform jobs in adventure mode. For more complete help
press '?' while script is running. It's most confortable to use this as a press '?' while script is running. It's most confortable to use this as a
@ -2754,22 +2833,31 @@ keybinding. (e.g. keybinding set Ctrl-T gui/advfort). Possible arguments:
* job - selects that job (e.g. Dig or FellTree) * job - selects that job (e.g. Dig or FellTree)
An example of player digging in adventure mode:
.. image:: images/advfort.png
.. admonition:: DISCLAIMER
advfort changes only persist in non procedural sites. Namely: player forts, caves, camps.
gui/companion-order gui/companion-order
======================= ===================
A script to issue orders for companions. Select companions with lower case chars, issue orders with upper A script to issue orders for companions. Select companions with lower case chars, issue orders with upper
case. Must be in look or talk mode to issue command on tile. case. Must be in look or talk mode to issue command on tile.
.. image:: images/companion-order.png
* move - orders selected companions to move to location. If companions are following they will move no more than 3 tiles from you. * move - orders selected companions to move to location. If companions are following they will move no more than 3 tiles from you.
* equip - try to equip items on the ground. * equip - try to equip items on the ground.
* pick-up - try to take items into hand (also wield) * pick-up - try to take items into hand (also wield)
* unequip - remove and drop equipment * unequip - remove and drop equipment
* unwield - drop held items * unwield - drop held items
* wait - temporarely remove from party * wait - temporarily remove from party
* follow - rejoin the party after "wait" * follow - rejoin the party after "wait"
* leave - remove from party (can be rejoined by talking) * leave - remove from party (can be rejoined by talking)
gui/gm-editor gui/gm-editor
============= =============
@ -2779,14 +2867,26 @@ There are three ways to open this editor:
or viewed (e.g. unit/item description screen) or viewed (e.g. unit/item description screen)
* using gui/gm-editor <lua command> - executes lua command and opens editor on * using gui/gm-editor <lua command> - executes lua command and opens editor on
it's results (e.g. gui/gm-editor "df.global.world.items.all" shows all items) its results (e.g. gui/gm-editor "df.global.world.items.all" shows all items)
* using gui/gm-editor dialog - shows an in game dialog to input lua command. Works * using gui/gm-editor dialog - shows an in game dialog to input lua command. Works
the same as version above. the same as version above.
.. image:: images/gm-editor.png
This editor allows to change and modify almost anything in df. Press '?' for an This editor allows to change and modify almost anything in df. Press '?' for an
in-game help. in-game help.
gui/mod-manager
===============
A way to simply install and remove small mods. It looks for specially formated mods in
df subfolder 'mods'. Mods are not included, for example mods see: `github mini mod repository <https://github.com/warmist/df-mini-mods>`_
.. image:: images/mod-manager.png
============= =============
Behavior Mods Behavior Mods
============= =============

@ -1,5 +1,5 @@
/* /*
** $Id: lapi.h,v 2.7 2009/11/27 15:37:59 roberto Exp $ ** $Id: lapi.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions from Lua API ** Auxiliary functions from Lua API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lauxlib.h,v 1.120 2011/11/29 15:55:08 roberto Exp $ ** $Id: lauxlib.h,v 1.120.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions for building Lua libraries ** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lcode.h,v 1.58 2011/08/30 16:26:41 roberto Exp $ ** $Id: lcode.h,v 1.58.1.1 2013/04/12 18:48:47 roberto Exp $
** Code generator for Lua ** Code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $ ** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $
** 'ctype' functions for Lua ** 'ctype' functions for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: ldebug.h,v 2.7 2011/10/07 20:45:19 roberto Exp $ ** $Id: ldebug.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions from Debug Interface module ** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: ldo.h,v 2.20 2011/11/29 15:55:08 roberto Exp $ ** $Id: ldo.h,v 2.20.1.1 2013/04/12 18:48:47 roberto Exp $
** Stack and Call structure of Lua ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp $ ** $Id: lfunc.h,v 2.8.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures ** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.h,v 2.56 2012/05/23 15:43:14 roberto Exp $ ** $Id: lgc.h,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -50,16 +50,26 @@
#define isgenerational(g) ((g)->gckind == KGC_GEN) #define isgenerational(g) ((g)->gckind == KGC_GEN)
/* /*
** macro to tell when main invariant (white objects cannot point to black ** macros to tell when main invariant (white objects cannot point to black
** ones) must be kept. During a non-generational collection, the sweep ** ones) must be kept. During a non-generational collection, the sweep
** phase may break the invariant, as objects turned white may point to ** phase may break the invariant, as objects turned white may point to
** still-black objects. The invariant is restored when sweep ends and ** still-black objects. The invariant is restored when sweep ends and
** all objects are white again. During a generational collection, the ** all objects are white again. During a generational collection, the
** invariant must be kept all times. ** invariant must be kept all times.
*/ */
#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic) #define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic)
/*
** Outside the collector, the state in generational mode is kept in
** 'propagate', so 'keepinvariant' is always true.
*/
#define keepinvariantout(g) \
check_exp(g->gcstate == GCSpropagate || !isgenerational(g), \
g->gcstate <= GCSatomic)
/* /*
** some useful bit tricks ** some useful bit tricks
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: llex.h,v 1.72 2011/11/30 12:43:51 roberto Exp $ ** $Id: llex.h,v 1.72.1.1 2013/04/12 18:48:47 roberto Exp $
** Lexical Analyzer ** Lexical Analyzer
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: llimits.h,v 1.99 2012/05/28 20:32:28 roberto Exp $ ** $Id: llimits.h,v 1.103.1.1 2013/04/12 18:48:47 roberto Exp $
** Limits, basic types, and some other `installation-dependent' definitions ** Limits, basic types, and some other `installation-dependent' definitions
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -200,7 +200,7 @@ typedef lu_int32 Instruction;
** both small and large values (outside the range of integers). ** both small and large values (outside the range of integers).
*/ */
#if defined(MS_ASMTRICK) /* { */ #if defined(MS_ASMTRICK) || defined(LUA_MSASMTRICK) /* { */
/* trick with Microsoft assembler for X86 */ /* trick with Microsoft assembler for X86 */
#define lua_number2int(i,n) __asm {__asm fld n __asm fistp i} #define lua_number2int(i,n) __asm {__asm fld n __asm fistp i}
@ -256,7 +256,7 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
#if !defined(lua_number2unsigned) /* { */ #if !defined(lua_number2unsigned) /* { */
/* the following definition assures proper modulo behavior */ /* the following definition assures proper modulo behavior */
#if defined(LUA_NUMBER_DOUBLE) #if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT)
#include <math.h> #include <math.h>
#define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1) #define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1)
#define lua_number2unsigned(i,n) \ #define lua_number2unsigned(i,n) \
@ -282,7 +282,7 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
#include <math.h> #include <math.h>
#define luai_hashnum(i,n) { int e; \ #define luai_hashnum(i,n) { int e; \
n = frexp(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ n = l_mathop(frexp)(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \
lua_number2int(i, n); i += e; } lua_number2int(i, n); i += e; }
#endif #endif

@ -1,5 +1,5 @@
/* /*
** $Id: lmem.h,v 1.38 2011/12/02 13:26:54 roberto Exp $ ** $Id: lmem.h,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $
** Interface to Memory Manager ** Interface to Memory Manager
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -14,9 +14,16 @@
#include "lua.h" #include "lua.h"
/*
** This macro avoids the runtime division MAX_SIZET/(e), as 'e' is
** always constant.
** The macro is somewhat complex to avoid warnings:
** +1 avoids warnings of "comparison has constant result";
** cast to 'void' avoids warnings of "value unused".
*/
#define luaM_reallocv(L,b,on,n,e) \ #define luaM_reallocv(L,b,on,n,e) \
((cast(size_t, (n)+1) > MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \ (cast(void, \
(luaM_toobig(L), (void *)0) : \ (cast(size_t, (n)+1) > MAX_SIZET/(e)) ? (luaM_toobig(L), 0) : 0), \
luaM_realloc_(L, (b), (on)*(e), (n)*(e))) luaM_realloc_(L, (b), (on)*(e), (n)*(e)))
#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0)

@ -1,5 +1,5 @@
/* /*
** $Id: lobject.h,v 2.70 2012/05/11 14:10:50 roberto Exp $ ** $Id: lobject.h,v 2.71.1.1 2013/04/12 18:48:47 roberto Exp $
** Type definitions for Lua objects ** Type definitions for Lua objects
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -52,8 +52,7 @@
#define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */ #define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */
/* /* Variant tags for strings */
** LUA_TSTRING variants */
#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */ #define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */
#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ #define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */
@ -188,8 +187,6 @@ typedef struct lua_TValue TValue;
#define setnvalue(obj,x) \ #define setnvalue(obj,x) \
{ TValue *io=(obj); num_(io)=(x); settt_(io, LUA_TNUMBER); } { TValue *io=(obj); num_(io)=(x); settt_(io, LUA_TNUMBER); }
#define changenvalue(o,x) check_exp(ttisnumber(o), num_(o)=(x))
#define setnilvalue(obj) settt_(obj, LUA_TNIL) #define setnilvalue(obj) settt_(obj, LUA_TNIL)
#define setfvalue(obj,x) \ #define setfvalue(obj,x) \

@ -1,5 +1,5 @@
/* /*
** $Id: lopcodes.h,v 1.142 2011/07/15 12:50:29 roberto Exp $ ** $Id: lopcodes.h,v 1.142.1.1 2013/04/12 18:48:47 roberto Exp $
** Opcodes for Lua virtual machine ** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lparser.h,v 1.70 2012/05/08 13:53:33 roberto Exp $ ** $Id: lparser.h,v 1.70.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua Parser ** Lua Parser
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lstate.h,v 2.81 2012/06/08 15:14:04 roberto Exp $ ** $Id: lstate.h,v 2.82.1.1 2013/04/12 18:48:47 roberto Exp $
** Global State ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -137,7 +137,7 @@ typedef struct global_State {
UpVal uvhead; /* head of double-linked list of all open upvalues */ UpVal uvhead; /* head of double-linked list of all open upvalues */
Mbuffer buff; /* temporary buffer for string concatenation */ Mbuffer buff; /* temporary buffer for string concatenation */
int gcpause; /* size of pause between successive GCs */ int gcpause; /* size of pause between successive GCs */
int gcmajorinc; /* how much to wait for a major GC (only in gen. mode) */ int gcmajorinc; /* pause between major collections (only in gen. mode) */
int gcstepmul; /* GC `granularity' */ int gcstepmul; /* GC `granularity' */
lua_CFunction panic; /* to be called in unprotected errors */ lua_CFunction panic; /* to be called in unprotected errors */
struct lua_State *mainthread; struct lua_State *mainthread;

@ -1,5 +1,5 @@
/* /*
** $Id: lstring.h,v 1.49 2012/02/01 21:57:15 roberto Exp $ ** $Id: lstring.h,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $
** String table (keep all strings handled by Lua) ** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: ltable.h,v 2.16 2011/08/17 20:26:47 roberto Exp $ ** $Id: ltable.h,v 2.16.1.2 2013/08/30 15:49:41 roberto Exp $
** Lua tables (hash) ** Lua tables (hash)
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -17,6 +17,10 @@
#define invalidateTMcache(t) ((t)->flags = 0) #define invalidateTMcache(t) ((t)->flags = 0)
/* returns the key, given the value of a table entry */
#define keyfromval(v) \
(gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
LUAI_FUNC const TValue *luaH_getint (Table *t, int key); LUAI_FUNC const TValue *luaH_getint (Table *t, int key);
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, int key, TValue *value); LUAI_FUNC void luaH_setint (lua_State *L, Table *t, int key, TValue *value);

@ -1,5 +1,5 @@
/* /*
** $Id: ltm.h,v 2.11 2011/02/28 17:32:10 roberto Exp $ ** $Id: ltm.h,v 2.11.1.1 2013/04/12 18:48:47 roberto Exp $
** Tag methods ** Tag methods
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lua.h,v 1.283 2012/04/20 13:18:26 roberto Exp $ ** $Id: lua.h,v 1.285.1.2 2013/11/11 12:09:16 roberto Exp $
** Lua - A Scripting Language ** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file ** See Copyright Notice at the end of this file
@ -19,11 +19,11 @@
#define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "2" #define LUA_VERSION_MINOR "2"
#define LUA_VERSION_NUM 502 #define LUA_VERSION_NUM 502
#define LUA_VERSION_RELEASE "1" #define LUA_VERSION_RELEASE "3"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2012 Lua.org, PUC-Rio" #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2013 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@ -119,6 +119,11 @@ typedef LUA_UNSIGNED lua_Unsigned;
#endif #endif
/*
** RCS ident string
*/
extern const char lua_ident[];
/* /*
** state manipulation ** state manipulation
@ -413,7 +418,7 @@ struct lua_Debug {
/****************************************************************************** /******************************************************************************
* Copyright (C) 1994-2012 Lua.org, PUC-Rio. * Copyright (C) 1994-2013 Lua.org, PUC-Rio.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

@ -1,5 +1,5 @@
/* /*
** $Id: luaconf.h,v 1.172 2012/05/11 14:14:42 roberto Exp $ ** $Id: luaconf.h,v 1.176.1.1 2013/04/12 18:48:47 roberto Exp $
** Configuration file for Lua ** Configuration file for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -44,7 +44,7 @@
#define LUA_USE_POSIX #define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ #define LUA_USE_DLOPEN /* needs an extra library: -ldl */
#define LUA_USE_READLINE /* needs some extra libraries */ #define LUA_USE_READLINE /* needs some extra libraries */
#define LUA_USE_STRTODHEX /* assume 'strtod' handles hexa formats */ #define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */
#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ #define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */
#define LUA_USE_LONGLONG /* assume support for long long */ #define LUA_USE_LONGLONG /* assume support for long long */
#endif #endif
@ -53,7 +53,7 @@
#define LUA_USE_POSIX #define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* does not need -ldl */ #define LUA_USE_DLOPEN /* does not need -ldl */
#define LUA_USE_READLINE /* needs an extra library: -lreadline */ #define LUA_USE_READLINE /* needs an extra library: -lreadline */
#define LUA_USE_STRTODHEX /* assume 'strtod' handles hexa formats */ #define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */
#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ #define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */
#define LUA_USE_LONGLONG /* assume support for long long */ #define LUA_USE_LONGLONG /* assume support for long long */
#endif #endif
@ -106,6 +106,8 @@
LUA_CDIR"?.so;" "./?.so" LUA_CDIR"?.so;" "./?.so"
#endif /* } */ #endif /* } */
#define LUA_PATH "DFHACK_LUA_PATH"
#define LUA_CPATH "DFHACK_LUA_CPATH"
/* /*
@@ LUA_DIRSEP is the directory separator (for submodules). @@ LUA_DIRSEP is the directory separator (for submodules).
@ -405,10 +407,16 @@
#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ #define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */
/*
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations
*/
#define l_mathop(x) (x)
/* /*
@@ lua_str2number converts a decimal numeric string to a number. @@ lua_str2number converts a decimal numeric string to a number.
@@ lua_strx2number converts an hexadecimal numeric string to a number. @@ lua_strx2number converts an hexadecimal numeric string to a number.
** In C99, 'strtod' do both conversions. C89, however, has no function ** In C99, 'strtod' does both conversions. C89, however, has no function
** to convert floating hexadecimal strings to numbers. For these ** to convert floating hexadecimal strings to numbers. For these
** systems, you can leave 'lua_strx2number' undefined and Lua will ** systems, you can leave 'lua_strx2number' undefined and Lua will
** provide its own implementation. ** provide its own implementation.
@ -427,8 +435,8 @@
/* the following operations need the math library */ /* the following operations need the math library */
#if defined(lobject_c) || defined(lvm_c) #if defined(lobject_c) || defined(lvm_c)
#include <math.h> #include <math.h>
#define luai_nummod(L,a,b) ((a) - floor((a)/(b))*(b)) #define luai_nummod(L,a,b) ((a) - l_mathop(floor)((a)/(b))*(b))
#define luai_numpow(L,a,b) (pow(a,b)) #define luai_numpow(L,a,b) (l_mathop(pow)(a,b))
#endif #endif
/* these are quite standard operations */ /* these are quite standard operations */
@ -465,13 +473,12 @@
** Some tricks with doubles ** Some tricks with doubles
*/ */
#if defined(LUA_CORE) && \ #if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */
defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */
/* /*
** The next definitions activate some tricks to speed up the ** The next definitions activate some tricks to speed up the
** conversion from doubles to integer types, mainly to LUA_UNSIGNED. ** conversion from doubles to integer types, mainly to LUA_UNSIGNED.
** **
@@ MS_ASMTRICK uses Microsoft assembler to avoid clashes with a @@ LUA_MSASMTRICK uses Microsoft assembler to avoid clashes with a
** DirectX idiosyncrasy. ** DirectX idiosyncrasy.
** **
@@ LUA_IEEE754TRICK uses a trick that should work on any machine @@ LUA_IEEE754TRICK uses a trick that should work on any machine
@ -495,7 +502,7 @@
/* Microsoft compiler on a Pentium (32 bit) ? */ /* Microsoft compiler on a Pentium (32 bit) ? */
#if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */ #if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */
#define MS_ASMTRICK #define LUA_MSASMTRICK
#define LUA_IEEEENDIAN 0 #define LUA_IEEEENDIAN 0
#define LUA_NANTRICK #define LUA_NANTRICK

@ -1,5 +1,5 @@
/* /*
** $Id: lualib.h,v 1.43 2011/12/08 12:11:37 roberto Exp $ ** $Id: lualib.h,v 1.43.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua standard libraries ** Lua standard libraries
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lundump.h,v 1.39 2012/05/08 13:53:33 roberto Exp $ ** $Id: lundump.h,v 1.39.1.1 2013/04/12 18:48:47 roberto Exp $
** load precompiled Lua chunks ** load precompiled Lua chunks
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lvm.h,v 2.17 2011/05/31 18:27:56 roberto Exp $ ** $Id: lvm.h,v 2.18.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -19,8 +19,7 @@
#define equalobj(L,o1,o2) (ttisequal(o1, o2) && luaV_equalobj_(L, o1, o2)) #define equalobj(L,o1,o2) (ttisequal(o1, o2) && luaV_equalobj_(L, o1, o2))
#define luaV_rawequalobj(t1,t2) \ #define luaV_rawequalobj(o1,o2) equalobj(NULL,o1,o2)
(ttisequal(t1,t2) && luaV_equalobj_(NULL,t1,t2))
/* not to called directly */ /* not to called directly */

@ -1,5 +1,5 @@
/* /*
** $Id: lzio.h,v 1.26 2011/07/15 12:48:03 roberto Exp $ ** $Id: lzio.h,v 1.26.1.1 2013/04/12 18:48:47 roberto Exp $
** Buffered streams ** Buffered streams
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lapi.c,v 2.164 2012/06/08 15:14:04 roberto Exp $ ** $Id: lapi.c,v 2.171.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua API ** Lua API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -40,7 +40,16 @@ const char lua_ident[] =
/* corresponding test */ /* corresponding test */
#define isvalid(o) ((o) != luaO_nilobject) #define isvalid(o) ((o) != luaO_nilobject)
#define api_checkvalidindex(L, i) api_check(L, isvalid(i), "invalid index") /* test for pseudo index */
#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX)
/* test for valid but not pseudo index */
#define isstackindex(i, o) (isvalid(o) && !ispseudo(i))
#define api_checkvalidindex(L, o) api_check(L, isvalid(o), "invalid index")
#define api_checkstackindex(L, i, o) \
api_check(L, isstackindex(i, o), "index not in the stack")
static TValue *index2addr (lua_State *L, int idx) { static TValue *index2addr (lua_State *L, int idx) {
@ -51,7 +60,7 @@ static TValue *index2addr (lua_State *L, int idx) {
if (o >= L->top) return NONVALIDVALUE; if (o >= L->top) return NONVALIDVALUE;
else return o; else return o;
} }
else if (idx > LUA_REGISTRYINDEX) { else if (!ispseudo(idx)) { /* negative index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
return L->top + idx; return L->top + idx;
} }
@ -142,7 +151,7 @@ LUA_API const lua_Number *lua_version (lua_State *L) {
** convert an acceptable stack index into an absolute index ** convert an acceptable stack index into an absolute index
*/ */
LUA_API int lua_absindex (lua_State *L, int idx) { LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || idx <= LUA_REGISTRYINDEX) return (idx > 0 || ispseudo(idx))
? idx ? idx
: cast_int(L->top - L->ci->func + idx); : cast_int(L->top - L->ci->func + idx);
} }
@ -174,7 +183,7 @@ LUA_API void lua_remove (lua_State *L, int idx) {
StkId p; StkId p;
lua_lock(L); lua_lock(L);
p = index2addr(L, idx); p = index2addr(L, idx);
api_checkvalidindex(L, p); api_checkstackindex(L, idx, p);
while (++p < L->top) setobjs2s(L, p-1, p); while (++p < L->top) setobjs2s(L, p-1, p);
L->top--; L->top--;
lua_unlock(L); lua_unlock(L);
@ -186,8 +195,9 @@ LUA_API void lua_insert (lua_State *L, int idx) {
StkId q; StkId q;
lua_lock(L); lua_lock(L);
p = index2addr(L, idx); p = index2addr(L, idx);
api_checkvalidindex(L, p); api_checkstackindex(L, idx, p);
for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); for (q = L->top; q > p; q--) /* use L->top as a temporary */
setobjs2s(L, q, q - 1);
setobjs2s(L, p, L->top); setobjs2s(L, p, L->top);
lua_unlock(L); lua_unlock(L);
} }
@ -217,7 +227,6 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
TValue *fr; TValue *fr;
lua_lock(L); lua_lock(L);
fr = index2addr(L, fromidx); fr = index2addr(L, fromidx);
api_checkvalidindex(L, fr);
moveto(L, fr, toidx); moveto(L, fr, toidx);
lua_unlock(L); lua_unlock(L);
} }
@ -295,7 +304,7 @@ LUA_API void lua_arith (lua_State *L, int op) {
o1 = L->top - 2; o1 = L->top - 2;
o2 = L->top - 1; o2 = L->top - 1;
if (ttisnumber(o1) && ttisnumber(o2)) { if (ttisnumber(o1) && ttisnumber(o2)) {
changenvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2))); setnvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2)));
} }
else else
luaV_arith(L, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD)); luaV_arith(L, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD));
@ -611,7 +620,6 @@ LUA_API void lua_gettable (lua_State *L, int idx) {
StkId t; StkId t;
lua_lock(L); lua_lock(L);
t = index2addr(L, idx); t = index2addr(L, idx);
api_checkvalidindex(L, t);
luaV_gettable(L, t, L->top - 1, L->top - 1); luaV_gettable(L, t, L->top - 1, L->top - 1);
lua_unlock(L); lua_unlock(L);
} }
@ -621,7 +629,6 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
StkId t; StkId t;
lua_lock(L); lua_lock(L);
t = index2addr(L, idx); t = index2addr(L, idx);
api_checkvalidindex(L, t);
setsvalue2s(L, L->top, luaS_new(L, k)); setsvalue2s(L, L->top, luaS_new(L, k));
api_incr_top(L); api_incr_top(L);
luaV_gettable(L, t, L->top - 1, L->top - 1); luaV_gettable(L, t, L->top - 1, L->top - 1);
@ -709,7 +716,6 @@ LUA_API void lua_getuservalue (lua_State *L, int idx) {
StkId o; StkId o;
lua_lock(L); lua_lock(L);
o = index2addr(L, idx); o = index2addr(L, idx);
api_checkvalidindex(L, o);
api_check(L, ttisuserdata(o), "userdata expected"); api_check(L, ttisuserdata(o), "userdata expected");
if (uvalue(o)->env) { if (uvalue(o)->env) {
sethvalue(L, L->top, uvalue(o)->env); sethvalue(L, L->top, uvalue(o)->env);
@ -743,7 +749,6 @@ LUA_API void lua_settable (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 2); api_checknelems(L, 2);
t = index2addr(L, idx); t = index2addr(L, idx);
api_checkvalidindex(L, t);
luaV_settable(L, t, L->top - 2, L->top - 1); luaV_settable(L, t, L->top - 2, L->top - 1);
L->top -= 2; /* pop index and value */ L->top -= 2; /* pop index and value */
lua_unlock(L); lua_unlock(L);
@ -755,7 +760,6 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = index2addr(L, idx); t = index2addr(L, idx);
api_checkvalidindex(L, t);
setsvalue2s(L, L->top++, luaS_new(L, k)); setsvalue2s(L, L->top++, luaS_new(L, k));
luaV_settable(L, t, L->top - 1, L->top - 2); luaV_settable(L, t, L->top - 1, L->top - 2);
L->top -= 2; /* pop value and key */ L->top -= 2; /* pop value and key */
@ -811,7 +815,6 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
obj = index2addr(L, objindex); obj = index2addr(L, objindex);
api_checkvalidindex(L, obj);
if (ttisnil(L->top - 1)) if (ttisnil(L->top - 1))
mt = NULL; mt = NULL;
else { else {
@ -821,9 +824,10 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
switch (ttypenv(obj)) { switch (ttypenv(obj)) {
case LUA_TTABLE: { case LUA_TTABLE: {
hvalue(obj)->metatable = mt; hvalue(obj)->metatable = mt;
if (mt) if (mt) {
luaC_objbarrierback(L, gcvalue(obj), mt); luaC_objbarrierback(L, gcvalue(obj), mt);
luaC_checkfinalizer(L, gcvalue(obj), mt); luaC_checkfinalizer(L, gcvalue(obj), mt);
}
break; break;
} }
case LUA_TUSERDATA: { case LUA_TUSERDATA: {
@ -850,7 +854,6 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
o = index2addr(L, idx); o = index2addr(L, idx);
api_checkvalidindex(L, o);
api_check(L, ttisuserdata(o), "userdata expected"); api_check(L, ttisuserdata(o), "userdata expected");
if (ttisnil(L->top - 1)) if (ttisnil(L->top - 1))
uvalue(o)->env = NULL; uvalue(o)->env = NULL;
@ -937,7 +940,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
func = 0; func = 0;
else { else {
StkId o = index2addr(L, errfunc); StkId o = index2addr(L, errfunc);
api_checkvalidindex(L, o); api_checkstackindex(L, errfunc, o);
func = savestack(L, o); func = savestack(L, o);
} }
c.func = L->top - (nargs+1); /* function to be called */ c.func = L->top - (nargs+1); /* function to be called */
@ -1103,7 +1106,7 @@ LUA_API int lua_error (lua_State *L) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
luaG_errormsg(L); luaG_errormsg(L);
lua_unlock(L); /* code unreachable; will unlock when control actually leaves the kernel */
return 0; /* to avoid warnings */ return 0; /* to avoid warnings */
} }

@ -1,5 +1,5 @@
/* /*
** $Id: lauxlib.c,v 1.244 2012/05/31 20:28:45 roberto Exp $ ** $Id: lauxlib.c,v 1.248.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions for building Lua libraries ** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -84,7 +84,7 @@ static void pushfuncname (lua_State *L, lua_Debug *ar) {
if (*ar->namewhat != '\0') /* is there a name? */ if (*ar->namewhat != '\0') /* is there a name? */
lua_pushfstring(L, "function " LUA_QS, ar->name); lua_pushfstring(L, "function " LUA_QS, ar->name);
else if (*ar->what == 'm') /* main? */ else if (*ar->what == 'm') /* main? */
lua_pushfstring(L, "main chunk"); lua_pushliteral(L, "main chunk");
else if (*ar->what == 'C') { else if (*ar->what == 'C') {
if (pushglobalfuncname(L, ar)) { if (pushglobalfuncname(L, ar)) {
lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));
@ -158,7 +158,8 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
if (strcmp(ar.namewhat, "method") == 0) { if (strcmp(ar.namewhat, "method") == 0) {
narg--; /* do not count `self' */ narg--; /* do not count `self' */
if (narg == 0) /* error is in the self argument itself? */ if (narg == 0) /* error is in the self argument itself? */
return luaL_error(L, "calling " LUA_QS " on bad self", ar.name); return luaL_error(L, "calling " LUA_QS " on bad self (%s)",
ar.name, extramsg);
} }
if (ar.name == NULL) if (ar.name == NULL)
ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
@ -214,7 +215,7 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
if (fname) if (fname)
lua_pushfstring(L, "%s: %s", fname, strerror(en)); lua_pushfstring(L, "%s: %s", fname, strerror(en));
else else
lua_pushfstring(L, "%s", strerror(en)); lua_pushstring(L, strerror(en));
lua_pushinteger(L, en); lua_pushinteger(L, en);
return 3; return 3;
} }
@ -438,7 +439,7 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
if (B->size - B->n < sz) { /* not enough space? */ if (B->size - B->n < sz) { /* not enough space? */
char *newbuff; char *newbuff;
size_t newsize = B->size * 2; /* double buffer size */ size_t newsize = B->size * 2; /* double buffer size */
if (newsize - B->n < sz) /* not bit enough? */ if (newsize - B->n < sz) /* not big enough? */
newsize = B->n + sz; newsize = B->n + sz;
if (newsize < B->n || newsize - B->n < sz) if (newsize < B->n || newsize - B->n < sz)
luaL_error(L, "buffer too large"); luaL_error(L, "buffer too large");
@ -598,7 +599,7 @@ static int skipBOM (LoadF *lf) {
lf->n = 0; lf->n = 0;
do { do {
c = getc(lf->f); c = getc(lf->f);
if (c == EOF || c != *(unsigned char *)p++) return c; if (c == EOF || c != *(const unsigned char *)p++) return c;
lf->buff[lf->n++] = c; /* to be read by the parser */ lf->buff[lf->n++] = c; /* to be read by the parser */
} while (*p != '\0'); } while (*p != '\0');
lf->n = 0; /* prefix matched; discard it */ lf->n = 0; /* prefix matched; discard it */

@ -1,5 +1,5 @@
/* /*
** $Id: lbaselib.c,v 1.274 2012/04/27 14:13:19 roberto Exp $ ** $Id: lbaselib.c,v 1.276.1.1 2013/04/12 18:48:47 roberto Exp $
** Basic library ** Basic library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -242,10 +242,16 @@ static int luaB_ipairs (lua_State *L) {
} }
static int load_aux (lua_State *L, int status) { static int load_aux (lua_State *L, int status, int envidx) {
if (status == LUA_OK) if (status == LUA_OK) {
if (envidx != 0) { /* 'env' parameter? */
lua_pushvalue(L, envidx); /* environment for loaded function */
if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */
lua_pop(L, 1); /* remove 'env' if not used by previous call */
}
return 1; return 1;
else { }
else { /* error (message is on top of the stack) */
lua_pushnil(L); lua_pushnil(L);
lua_insert(L, -2); /* put before error message */ lua_insert(L, -2); /* put before error message */
return 2; /* return nil plus error message */ return 2; /* return nil plus error message */
@ -256,13 +262,9 @@ static int load_aux (lua_State *L, int status) {
static int luaB_loadfile (lua_State *L) { static int luaB_loadfile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL); const char *fname = luaL_optstring(L, 1, NULL);
const char *mode = luaL_optstring(L, 2, NULL); const char *mode = luaL_optstring(L, 2, NULL);
int env = !lua_isnone(L, 3); /* 'env' parameter? */ int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */
int status = luaL_loadfilex(L, fname, mode); int status = luaL_loadfilex(L, fname, mode);
if (status == LUA_OK && env) { /* 'env' parameter? */ return load_aux(L, status, env);
lua_pushvalue(L, 3);
lua_setupvalue(L, -2, 1); /* set it as 1st upvalue of loaded chunk */
}
return load_aux(L, status);
} }
@ -307,9 +309,9 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
static int luaB_load (lua_State *L) { static int luaB_load (lua_State *L) {
int status; int status;
size_t l; size_t l;
int top = lua_gettop(L);
const char *s = lua_tolstring(L, 1, &l); const char *s = lua_tolstring(L, 1, &l);
const char *mode = luaL_optstring(L, 3, "bt"); const char *mode = luaL_optstring(L, 3, "bt");
int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
if (s != NULL) { /* loading a string? */ if (s != NULL) { /* loading a string? */
const char *chunkname = luaL_optstring(L, 2, s); const char *chunkname = luaL_optstring(L, 2, s);
status = luaL_loadbufferx(L, s, l, chunkname, mode); status = luaL_loadbufferx(L, s, l, chunkname, mode);
@ -320,11 +322,7 @@ static int luaB_load (lua_State *L) {
lua_settop(L, RESERVEDSLOT); /* create reserved slot */ lua_settop(L, RESERVEDSLOT); /* create reserved slot */
status = lua_load(L, generic_reader, NULL, chunkname, mode); status = lua_load(L, generic_reader, NULL, chunkname, mode);
} }
if (status == LUA_OK && top >= 4) { /* is there an 'env' argument */ return load_aux(L, status, env);
lua_pushvalue(L, 4); /* environment for loaded function */
lua_setupvalue(L, -2, 1); /* set it as 1st upvalue */
}
return load_aux(L, status);
} }
/* }====================================================== */ /* }====================================================== */
@ -338,7 +336,8 @@ static int dofilecont (lua_State *L) {
static int luaB_dofile (lua_State *L) { static int luaB_dofile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL); const char *fname = luaL_optstring(L, 1, NULL);
lua_settop(L, 1); lua_settop(L, 1);
if (luaL_loadfile(L, fname) != LUA_OK) lua_error(L); if (luaL_loadfile(L, fname) != LUA_OK)
return lua_error(L);
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
return dofilecont(L); return dofilecont(L);
} }

@ -1,5 +1,5 @@
/* /*
** $Id: lbitlib.c,v 1.16 2011/06/20 16:35:23 roberto Exp $ ** $Id: lbitlib.c,v 1.18.1.2 2013/07/09 18:01:41 roberto Exp $
** Standard library for bitwise operations ** Standard library for bitwise operations
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -129,6 +129,7 @@ static int b_rot (lua_State *L, int i) {
b_uint r = luaL_checkunsigned(L, 1); b_uint r = luaL_checkunsigned(L, 1);
i &= (LUA_NBITS - 1); /* i = i % NBITS */ i &= (LUA_NBITS - 1); /* i = i % NBITS */
r = trim(r); r = trim(r);
if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
r = (r << i) | (r >> (LUA_NBITS - i)); r = (r << i) | (r >> (LUA_NBITS - i));
lua_pushunsigned(L, trim(r)); lua_pushunsigned(L, trim(r));
return 1; return 1;
@ -147,7 +148,9 @@ static int b_rrot (lua_State *L) {
/* /*
** get field and width arguments for field-manipulation functions, ** get field and width arguments for field-manipulation functions,
** checking whether they are valid ** checking whether they are valid.
** ('luaL_error' called without 'return' to avoid later warnings about
** 'width' being used uninitialized.)
*/ */
static int fieldargs (lua_State *L, int farg, int *width) { static int fieldargs (lua_State *L, int farg, int *width) {
int f = luaL_checkint(L, farg); int f = luaL_checkint(L, farg);

@ -1,5 +1,5 @@
/* /*
** $Id: lcode.c,v 2.60 2011/08/30 16:26:41 roberto Exp $ ** $Id: lcode.c,v 2.62.1.1 2013/04/12 18:48:47 roberto Exp $
** Code generator for Lua ** Code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -330,8 +330,7 @@ int luaK_numberK (FuncState *fs, lua_Number r) {
setnvalue(&o, r); setnvalue(&o, r);
if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */ if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */
/* use raw representation as key to avoid numeric problems */ /* use raw representation as key to avoid numeric problems */
setsvalue(L, L->top, luaS_newlstr(L, (char *)&r, sizeof(r))); setsvalue(L, L->top++, luaS_newlstr(L, (char *)&r, sizeof(r)));
incr_top(L);
n = addk(fs, L->top - 1, &o); n = addk(fs, L->top - 1, &o);
L->top--; L->top--;
} }

@ -1,5 +1,5 @@
/* /*
** $Id: lcorolib.c,v 1.4 2012/04/27 18:59:04 roberto Exp $ ** $Id: lcorolib.c,v 1.5.1.1 2013/04/12 18:48:47 roberto Exp $
** Coroutine Library ** Coroutine Library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -73,7 +73,7 @@ static int luaB_auxwrap (lua_State *L) {
lua_insert(L, -2); lua_insert(L, -2);
lua_concat(L, 2); lua_concat(L, 2);
} }
lua_error(L); /* propagate error */ return lua_error(L); /* propagate error */
} }
return r; return r;
} }

@ -1,5 +1,5 @@
/* /*
** $Id: lctype.c,v 1.11 2011/10/03 16:19:23 roberto Exp $ ** $Id: lctype.c,v 1.11.1.1 2013/04/12 18:48:47 roberto Exp $
** 'ctype' functions for Lua ** 'ctype' functions for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: ldblib.c,v 1.132 2012/01/19 20:14:44 roberto Exp $ ** $Id: ldblib.c,v 1.132.1.1 2013/04/12 18:48:47 roberto Exp $
** Interface from Lua to its debug API ** Interface from Lua to its debug API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: ldebug.c,v 2.89 2012/01/20 22:05:50 roberto Exp $ ** $Id: ldebug.c,v 2.90.1.3 2013/05/16 16:04:15 roberto Exp $
** Debug Interface ** Debug Interface
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -196,7 +196,7 @@ static void funcinfo (lua_Debug *ar, Closure *cl) {
static void collectvalidlines (lua_State *L, Closure *f) { static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) { if (noLuaClosure(f)) {
setnilvalue(L->top); setnilvalue(L->top);
incr_top(L); api_incr_top(L);
} }
else { else {
int i; int i;
@ -204,7 +204,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
int *lineinfo = f->l.p->lineinfo; int *lineinfo = f->l.p->lineinfo;
Table *t = luaH_new(L); /* new table to store active lines */ Table *t = luaH_new(L); /* new table to store active lines */
sethvalue(L, L->top, t); /* push it on stack */ sethvalue(L, L->top, t); /* push it on stack */
incr_top(L); api_incr_top(L);
setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */ setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */
for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */ for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */
luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */ luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */
@ -285,7 +285,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
status = auxgetinfo(L, what, ar, cl, ci); status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) { if (strchr(what, 'f')) {
setobjs2s(L, L->top, func); setobjs2s(L, L->top, func);
incr_top(L); api_incr_top(L);
} }
if (strchr(what, 'L')) if (strchr(what, 'L'))
collectvalidlines(L, cl); collectvalidlines(L, cl);
@ -327,12 +327,20 @@ static void kname (Proto *p, int pc, int c, const char **name) {
} }
static int filterpc (int pc, int jmptarget) {
if (pc < jmptarget) /* is code conditional (inside a jump)? */
return -1; /* cannot know who sets that register */
else return pc; /* current position sets that register */
}
/* /*
** try to find last instruction before 'lastpc' that modified register 'reg' ** try to find last instruction before 'lastpc' that modified register 'reg'
*/ */
static int findsetreg (Proto *p, int lastpc, int reg) { static int findsetreg (Proto *p, int lastpc, int reg) {
int pc; int pc;
int setreg = -1; /* keep last instruction that changed 'reg' */ int setreg = -1; /* keep last instruction that changed 'reg' */
int jmptarget = 0; /* any code before this address is conditional */
for (pc = 0; pc < lastpc; pc++) { for (pc = 0; pc < lastpc; pc++) {
Instruction i = p->code[pc]; Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i); OpCode op = GET_OPCODE(i);
@ -341,33 +349,38 @@ static int findsetreg (Proto *p, int lastpc, int reg) {
case OP_LOADNIL: { case OP_LOADNIL: {
int b = GETARG_B(i); int b = GETARG_B(i);
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
setreg = pc; setreg = filterpc(pc, jmptarget);
break; break;
} }
case OP_TFORCALL: { case OP_TFORCALL: {
if (reg >= a + 2) setreg = pc; /* affect all regs above its base */ if (reg >= a + 2) /* affect all regs above its base */
setreg = filterpc(pc, jmptarget);
break; break;
} }
case OP_CALL: case OP_CALL:
case OP_TAILCALL: { case OP_TAILCALL: {
if (reg >= a) setreg = pc; /* affect all registers above base */ if (reg >= a) /* affect all registers above base */
setreg = filterpc(pc, jmptarget);
break; break;
} }
case OP_JMP: { case OP_JMP: {
int b = GETARG_sBx(i); int b = GETARG_sBx(i);
int dest = pc + 1 + b; int dest = pc + 1 + b;
/* jump is forward and do not skip `lastpc'? */ /* jump is forward and do not skip `lastpc'? */
if (pc < dest && dest <= lastpc) if (pc < dest && dest <= lastpc) {
pc += b; /* do the jump */ if (dest > jmptarget)
jmptarget = dest; /* update 'jmptarget' */
}
break; break;
} }
case OP_TEST: { case OP_TEST: {
if (reg == a) setreg = pc; /* jumped code can change 'a' */ if (reg == a) /* jumped code can change 'a' */
setreg = filterpc(pc, jmptarget);
break; break;
} }
default: default:
if (testAMode(op) && reg == a) /* any instruction that set A */ if (testAMode(op) && reg == a) /* any instruction that set A */
setreg = pc; setreg = filterpc(pc, jmptarget);
break; break;
} }
} }
@ -518,7 +531,7 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) { l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
lua_assert(!ttisstring(p1) && !ttisnumber(p2)); lua_assert(!ttisstring(p1) && !ttisnumber(p1));
luaG_typeerror(L, p1, "concatenate"); luaG_typeerror(L, p1, "concatenate");
} }
@ -563,7 +576,7 @@ l_noret luaG_errormsg (lua_State *L) {
if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top, L->top - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */ setobjs2s(L, L->top - 1, errfunc); /* push function */
incr_top(L); L->top++;
luaD_call(L, L->top - 2, 1, 0); /* call it */ luaD_call(L, L->top - 2, 1, 0); /* call it */
} }
luaD_throw(L, LUA_ERRRUN); luaD_throw(L, LUA_ERRRUN);

@ -1,5 +1,5 @@
/* /*
** $Id: ldo.c,v 2.105 2012/06/08 15:14:04 roberto Exp $ ** $Id: ldo.c,v 2.108.1.3 2013/11/08 18:22:50 roberto Exp $
** Stack and Call structure of Lua ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -260,6 +260,7 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
StkId base, fixed; StkId base, fixed;
lua_assert(actual >= nfixargs); lua_assert(actual >= nfixargs);
/* move fixed parameters to final position */ /* move fixed parameters to final position */
luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */
fixed = L->top - actual; /* first fixed argument */ fixed = L->top - actual; /* first fixed argument */
base = L->top; /* final position of first argument */ base = L->top; /* final position of first argument */
for (i=0; i<nfixargs; i++) { for (i=0; i<nfixargs; i++) {
@ -311,6 +312,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
ci->top = L->top + LUA_MINSTACK; ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top <= L->stack_last);
ci->callstatus = 0; ci->callstatus = 0;
luaC_checkGC(L); /* stack grow uses memory */
if (L->hookmask & LUA_MASKCALL) if (L->hookmask & LUA_MASKCALL)
luaD_hook(L, LUA_HOOKCALL, -1); luaD_hook(L, LUA_HOOKCALL, -1);
lua_unlock(L); lua_unlock(L);
@ -323,12 +325,18 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
case LUA_TLCL: { /* Lua function: prepare its call */ case LUA_TLCL: { /* Lua function: prepare its call */
StkId base; StkId base;
Proto *p = clLvalue(func)->p; Proto *p = clLvalue(func)->p;
luaD_checkstack(L, p->maxstacksize);
func = restorestack(L, funcr);
n = cast_int(L->top - func) - 1; /* number of real arguments */ n = cast_int(L->top - func) - 1; /* number of real arguments */
luaD_checkstack(L, p->maxstacksize);
for (; n < p->numparams; n++) for (; n < p->numparams; n++)
setnilvalue(L->top++); /* complete missing arguments */ setnilvalue(L->top++); /* complete missing arguments */
base = (!p->is_vararg) ? func + 1 : adjust_varargs(L, p, n); if (!p->is_vararg) {
func = restorestack(L, funcr);
base = func + 1;
}
else {
base = adjust_varargs(L, p, n);
func = restorestack(L, funcr); /* previous call can change stack */
}
ci = next_ci(L); /* now 'enter' new function */ ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults; ci->nresults = nresults;
ci->func = func; ci->func = func;
@ -338,6 +346,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus = CIST_LUA; ci->callstatus = CIST_LUA;
L->top = ci->top; L->top = ci->top;
luaC_checkGC(L); /* stack grow uses memory */
if (L->hookmask & LUA_MASKCALL) if (L->hookmask & LUA_MASKCALL)
callhook(L, ci); callhook(L, ci);
return 0; return 0;
@ -393,7 +402,6 @@ void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
luaV_execute(L); /* call it */ luaV_execute(L); /* call it */
if (!allowyield) L->nny--; if (!allowyield) L->nny--;
L->nCcalls--; L->nCcalls--;
luaC_checkGC(L);
} }
@ -402,10 +410,11 @@ static void finishCcall (lua_State *L) {
int n; int n;
lua_assert(ci->u.c.k != NULL); /* must have a continuation */ lua_assert(ci->u.c.k != NULL); /* must have a continuation */
lua_assert(L->nny == 0); lua_assert(L->nny == 0);
/* finish 'lua_pcallk' */ if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
if (ci->callstatus & CIST_YPCALL) ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */
L->errfunc = ci->u.c.old_errfunc; L->errfunc = ci->u.c.old_errfunc;
/* finish 'lua_callk' */ }
/* finish 'lua_callk'/'lua_pcall' */
adjustresults(L, ci->nresults); adjustresults(L, ci->nresults);
/* call continuation function */ /* call continuation function */
if (!(ci->callstatus & CIST_STAT)) /* no call status? */ if (!(ci->callstatus & CIST_STAT)) /* no call status? */
@ -476,7 +485,7 @@ static int recover (lua_State *L, int status) {
static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
L->top = firstArg; /* remove args from the stack */ L->top = firstArg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
incr_top(L); api_incr_top(L);
luaD_throw(L, -1); /* jump back to 'lua_resume' */ luaD_throw(L, -1); /* jump back to 'lua_resume' */
} }
@ -525,6 +534,7 @@ static void resume (lua_State *L, void *ud) {
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
int status; int status;
int oldnny = L->nny; /* save 'nny' */
lua_lock(L); lua_lock(L);
luai_userstateresume(L, nargs); luai_userstateresume(L, nargs);
L->nCcalls = (from) ? from->nCcalls + 1 : 1; L->nCcalls = (from) ? from->nCcalls + 1 : 1;
@ -546,7 +556,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
} }
lua_assert(status == L->status); lua_assert(status == L->status);
} }
L->nny = 1; /* do not allow yields */ L->nny = oldnny; /* restore 'nny' */
L->nCcalls--; L->nCcalls--;
lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));
lua_unlock(L); lua_unlock(L);
@ -561,7 +571,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
api_checknelems(L, nresults); api_checknelems(L, nresults);
if (L->nny > 0) { if (L->nny > 0) {
if (L != G(L)->mainthread) if (L != G(L)->mainthread)
luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); luaG_runerror(L, "attempt to yield across a C-call boundary");
else else
luaG_runerror(L, "attempt to yield from outside a coroutine"); luaG_runerror(L, "attempt to yield from outside a coroutine");
} }

@ -1,5 +1,5 @@
/* /*
** $Id: ldump.c,v 2.17 2012/01/23 23:02:10 roberto Exp $ ** $Id: ldump.c,v 2.17.1.1 2013/04/12 18:48:47 roberto Exp $
** save precompiled Lua chunks ** save precompiled Lua chunks
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lfunc.c,v 2.29 2012/05/08 13:53:33 roberto Exp $ ** $Id: lfunc.c,v 2.30.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures ** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -52,12 +52,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { while (*pp != NULL && (p = gco2uv(*pp))->v >= level) {
GCObject *o = obj2gco(p); GCObject *o = obj2gco(p);
lua_assert(p->v != &p->u.value); lua_assert(p->v != &p->u.value);
lua_assert(!isold(o) || isold(obj2gco(L)));
if (p->v == level) { /* found a corresponding upvalue? */ if (p->v == level) { /* found a corresponding upvalue? */
if (isdead(g, o)) /* is it dead? */ if (isdead(g, o)) /* is it dead? */
changewhite(o); /* resurrect it */ changewhite(o); /* resurrect it */
return p; return p;
} }
resetoldbit(o); /* may create a newer upval after this one */
pp = &p->next; pp = &p->next;
} }
/* not found: create a new one */ /* not found: create a new one */

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.c,v 2.133 2012/05/31 21:28:59 roberto Exp $ ** $Id: lgc.c,v 2.140.1.2 2013/04/26 18:22:05 roberto Exp $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -43,21 +43,12 @@
*/ */
#define STEPMULADJ 200 #define STEPMULADJ 200
/* /*
** macro to adjust 'pause': 'pause' is actually used like ** macro to adjust 'pause': 'pause' is actually used like
** 'pause / PAUSEADJ' (value chosen by tests) ** 'pause / PAUSEADJ' (value chosen by tests)
*/ */
#define PAUSEADJ 200 #define PAUSEADJ 100
/*
** standard negative debt for GC; a reasonable "time" to wait before
** starting a new cycle
*/
#define stddebtest(g,e) (-cast(l_mem, (e)/PAUSEADJ) * g->gcpause)
#define stddebt(g) stddebtest(g, gettotalbytes(g))
/* /*
@ -144,9 +135,9 @@ static int iscleared (global_State *g, const TValue *o) {
void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
global_State *g = G(L); global_State *g = G(L);
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
lua_assert(isgenerational(g) || g->gcstate != GCSpause); lua_assert(g->gcstate != GCSpause);
lua_assert(gch(o)->tt != LUA_TTABLE); lua_assert(gch(o)->tt != LUA_TTABLE);
if (keepinvariant(g)) /* must keep invariant? */ if (keepinvariantout(g)) /* must keep invariant? */
reallymarkobject(g, v); /* restore invariant */ reallymarkobject(g, v); /* restore invariant */
else { /* sweep phase */ else { /* sweep phase */
lua_assert(issweepphase(g)); lua_assert(issweepphase(g));
@ -343,7 +334,7 @@ static void remarkupvals (global_State *g) {
** mark root set and reset all gray lists, to start a new ** mark root set and reset all gray lists, to start a new
** incremental (or full) collection ** incremental (or full) collection
*/ */
static void markroot (global_State *g) { static void restartcollection (global_State *g) {
g->gray = g->grayagain = NULL; g->gray = g->grayagain = NULL;
g->weak = g->allweak = g->ephemeron = NULL; g->weak = g->allweak = g->ephemeron = NULL;
markobject(g, g->mainthread); markobject(g, g->mainthread);
@ -459,7 +450,7 @@ static lu_mem traversetable (global_State *g, Table *h) {
else /* not weak */ else /* not weak */
traversestrongtable(g, h); traversestrongtable(g, h);
return sizeof(Table) + sizeof(TValue) * h->sizearray + return sizeof(Table) + sizeof(TValue) * h->sizearray +
sizeof(Node) * sizenode(h); sizeof(Node) * cast(size_t, sizenode(h));
} }
@ -502,17 +493,24 @@ static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
static lu_mem traversestack (global_State *g, lua_State *th) { static lu_mem traversestack (global_State *g, lua_State *th) {
int n = 0;
StkId o = th->stack; StkId o = th->stack;
if (o == NULL) if (o == NULL)
return 1; /* stack not completely built yet */ return 1; /* stack not completely built yet */
for (; o < th->top; o++) for (; o < th->top; o++) /* mark live elements in the stack */
markvalue(g, o); markvalue(g, o);
if (g->gcstate == GCSatomic) { /* final traversal? */ if (g->gcstate == GCSatomic) { /* final traversal? */
StkId lim = th->stack + th->stacksize; /* real end of stack */ StkId lim = th->stack + th->stacksize; /* real end of stack */
for (; o < lim; o++) /* clear not-marked stack slice */ for (; o < lim; o++) /* clear not-marked stack slice */
setnilvalue(o); setnilvalue(o);
} }
return sizeof(lua_State) + sizeof(TValue) * th->stacksize; else { /* count call infos to compute size */
CallInfo *ci;
for (ci = &th->base_ci; ci != th->ci; ci = ci->next)
n++;
}
return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
sizeof(CallInfo) * n;
} }
@ -796,7 +794,7 @@ static GCObject *udata2finalize (global_State *g) {
g->allgc = o; g->allgc = o;
resetbit(gch(o)->marked, SEPARATED); /* mark that it is not in 'tobefnz' */ resetbit(gch(o)->marked, SEPARATED); /* mark that it is not in 'tobefnz' */
lua_assert(!isold(o)); /* see MOVE OLD rule */ lua_assert(!isold(o)); /* see MOVE OLD rule */
if (!keepinvariant(g)) /* not keeping invariant? */ if (!keepinvariantout(g)) /* not keeping invariant? */
makewhite(g, o); /* "sweep" object */ makewhite(g, o); /* "sweep" object */
return o; return o;
} }
@ -855,7 +853,7 @@ static void separatetobefnz (lua_State *L, int all) {
while ((curr = *p) != NULL) { /* traverse all finalizable objects */ while ((curr = *p) != NULL) { /* traverse all finalizable objects */
lua_assert(!isfinalized(curr)); lua_assert(!isfinalized(curr));
lua_assert(testbit(gch(curr)->marked, SEPARATED)); lua_assert(testbit(gch(curr)->marked, SEPARATED));
if (!(all || iswhite(curr))) /* not being collected? */ if (!(iswhite(curr) || all)) /* not being collected? */
p = &gch(curr)->next; /* don't bother with it */ p = &gch(curr)->next; /* don't bother with it */
else { else {
l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
@ -891,7 +889,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
ho->next = g->finobj; /* link it in list 'finobj' */ ho->next = g->finobj; /* link it in list 'finobj' */
g->finobj = o; g->finobj = o;
l_setbit(ho->marked, SEPARATED); /* mark it as such */ l_setbit(ho->marked, SEPARATED); /* mark it as such */
if (!keepinvariant(g)) /* not keeping invariant? */ if (!keepinvariantout(g)) /* not keeping invariant? */
makewhite(g, o); /* "sweep" object */ makewhite(g, o); /* "sweep" object */
else else
resetoldbit(o); /* see MOVE OLD rule */ resetoldbit(o); /* see MOVE OLD rule */
@ -908,6 +906,21 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
*/ */
/*
** set a reasonable "time" to wait before starting a new GC cycle;
** cycle will start when memory use hits threshold
*/
static void setpause (global_State *g, l_mem estimate) {
l_mem debt, threshold;
estimate = estimate / PAUSEADJ; /* adjust 'estimate' */
threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */
? estimate * g->gcpause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = -cast(l_mem, threshold - gettotalbytes(g));
luaE_setdebt(g, debt);
}
#define sweepphases \ #define sweepphases \
(bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep)) (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep))
@ -918,7 +931,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
** object inside the list (instead of to the header), so that the real ** object inside the list (instead of to the header), so that the real
** sweep do not need to skip objects created between "now" and the start ** sweep do not need to skip objects created between "now" and the start
** of the real sweep. ** of the real sweep.
** Returns how many objects it sweeped. ** Returns how many objects it swept.
*/ */
static int entersweep (lua_State *L) { static int entersweep (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
@ -985,7 +998,7 @@ void luaC_freeallobjects (lua_State *L) {
static l_mem atomic (lua_State *L) { static l_mem atomic (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
l_mem work = -g->GCmemtrav; /* start counting work */ l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */
GCObject *origweak, *origall; GCObject *origweak, *origall;
lua_assert(!iswhite(obj2gco(g->mainthread))); lua_assert(!iswhite(obj2gco(g->mainthread)));
markobject(g, L); /* mark running thread */ markobject(g, L); /* mark running thread */
@ -1028,12 +1041,10 @@ static lu_mem singlestep (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
switch (g->gcstate) { switch (g->gcstate) {
case GCSpause: { case GCSpause: {
g->GCmemtrav = 0; /* start to count memory traversed */ /* start to count memory traversed */
if (!isgenerational(g)) g->GCmemtrav = g->strt.size * sizeof(GCObject*);
markroot(g); /* start a new collection */ lua_assert(!isgenerational(g));
/* in any case, root must be marked at this point */ restartcollection(g);
lua_assert(!iswhite(obj2gco(g->mainthread))
&& !iswhite(gcvalue(&g->l_registry)));
g->gcstate = GCSpropagate; g->gcstate = GCSpropagate;
return g->GCmemtrav; return g->GCmemtrav;
} }
@ -1105,18 +1116,23 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
static void generationalcollection (lua_State *L) { static void generationalcollection (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
lua_assert(g->gcstate == GCSpropagate);
if (g->GCestimate == 0) { /* signal for another major collection? */ if (g->GCestimate == 0) { /* signal for another major collection? */
luaC_fullgc(L, 0); /* perform a full regular collection */ luaC_fullgc(L, 0); /* perform a full regular collection */
g->GCestimate = gettotalbytes(g); /* update control */ g->GCestimate = gettotalbytes(g); /* update control */
} }
else { else {
lu_mem estimate = g->GCestimate; lu_mem estimate = g->GCestimate;
luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */ luaC_runtilstate(L, bitmask(GCSpause)); /* run complete (minor) cycle */
luaC_runtilstate(L, bitmask(GCSpause)); g->gcstate = GCSpropagate; /* skip restart */
if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc) if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc)
g->GCestimate = 0; /* signal for a major collection */ g->GCestimate = 0; /* signal for a major collection */
else
g->GCestimate = estimate; /* keep estimate from last major coll. */
} }
luaE_setdebt(g, stddebt(g)); setpause(g, gettotalbytes(g));
lua_assert(g->gcstate == GCSpropagate);
} }
@ -1124,7 +1140,7 @@ static void incstep (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
l_mem debt = g->GCdebt; l_mem debt = g->GCdebt;
int stepmul = g->gcstepmul; int stepmul = g->gcstepmul;
if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values */ if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values (and 0) */
/* convert debt from Kb to 'work units' (avoid zero debt and overflows) */ /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */
debt = (debt / STEPMULADJ) + 1; debt = (debt / STEPMULADJ) + 1;
debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
@ -1133,10 +1149,11 @@ static void incstep (lua_State *L) {
debt -= work; debt -= work;
} while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
if (g->gcstate == GCSpause) if (g->gcstate == GCSpause)
debt = stddebtest(g, g->GCestimate); /* pause until next cycle */ setpause(g, g->GCestimate); /* pause until next cycle */
else else {
debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */ debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */
luaE_setdebt(g, debt); luaE_setdebt(g, debt);
}
} }
@ -1172,7 +1189,6 @@ void luaC_step (lua_State *L) {
void luaC_fullgc (lua_State *L, int isemergency) { void luaC_fullgc (lua_State *L, int isemergency) {
global_State *g = G(L); global_State *g = G(L);
int origkind = g->gckind; int origkind = g->gckind;
int someblack = keepinvariant(g);
lua_assert(origkind != KGC_EMERGENCY); lua_assert(origkind != KGC_EMERGENCY);
if (isemergency) /* do not run finalizers during emergency GC */ if (isemergency) /* do not run finalizers during emergency GC */
g->gckind = KGC_EMERGENCY; g->gckind = KGC_EMERGENCY;
@ -1180,22 +1196,21 @@ void luaC_fullgc (lua_State *L, int isemergency) {
g->gckind = KGC_NORMAL; g->gckind = KGC_NORMAL;
callallpendingfinalizers(L, 1); callallpendingfinalizers(L, 1);
} }
if (someblack) { /* may there be some black objects? */ if (keepinvariant(g)) { /* may there be some black objects? */
/* must sweep all objects to turn them back to white /* must sweep all objects to turn them back to white
(as white has not changed, nothing will be collected) */ (as white has not changed, nothing will be collected) */
entersweep(L); entersweep(L);
} }
/* finish any pending sweep phase to start a new cycle */ /* finish any pending sweep phase to start a new cycle */
luaC_runtilstate(L, bitmask(GCSpause)); luaC_runtilstate(L, bitmask(GCSpause));
/* run entire collector */ luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */
luaC_runtilstate(L, ~bitmask(GCSpause)); luaC_runtilstate(L, bitmask(GCSpause)); /* run entire collection */
luaC_runtilstate(L, bitmask(GCSpause));
if (origkind == KGC_GEN) { /* generational mode? */ if (origkind == KGC_GEN) { /* generational mode? */
/* generational mode must always start in propagate phase */ /* generational mode must be kept in propagate phase */
luaC_runtilstate(L, bitmask(GCSpropagate)); luaC_runtilstate(L, bitmask(GCSpropagate));
} }
g->gckind = origkind; g->gckind = origkind;
luaE_setdebt(g, stddebt(g)); setpause(g, gettotalbytes(g));
if (!isemergency) /* do not run finalizers during emergency GC */ if (!isemergency) /* do not run finalizers during emergency GC */
callallpendingfinalizers(L, 1); callallpendingfinalizers(L, 1);
} }

@ -1,5 +1,5 @@
/* /*
** $Id: linit.c,v 1.32 2011/04/08 19:17:36 roberto Exp $ ** $Id: linit.c,v 1.32.1.1 2013/04/12 18:48:47 roberto Exp $
** Initialization of libraries for lua.c and other clients ** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,16 +1,16 @@
/* /*
** $Id: liolib.c,v 2.108 2011/11/25 12:50:03 roberto Exp $ ** $Id: liolib.c,v 2.112.1.1 2013/04/12 18:48:47 roberto Exp $
** Standard I/O (and system) library ** Standard I/O (and system) library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
/* /*
** POSIX idiosyncrasy!
** This definition must come before the inclusion of 'stdio.h'; it ** This definition must come before the inclusion of 'stdio.h'; it
** should not affect non-POSIX systems ** should not affect non-POSIX systems
*/ */
#if !defined(_FILE_OFFSET_BITS) #if !defined(_FILE_OFFSET_BITS)
#define _LARGEFILE_SOURCE 1
#define _FILE_OFFSET_BITS 64 #define _FILE_OFFSET_BITS 64
#endif #endif
@ -29,6 +29,20 @@
#include "lualib.h" #include "lualib.h"
#if !defined(lua_checkmode)
/*
** Check whether 'mode' matches '[rwa]%+?b?'.
** Change this macro to accept other modes for 'fopen' besides
** the standard ones.
*/
#define lua_checkmode(mode) \
(*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \
(*mode != '+' || ++mode) && /* skip if char is '+' */ \
(*mode != 'b' || ++mode) && /* skip if char is 'b' */ \
(*mode == '\0'))
#endif
/* /*
** {====================================================== ** {======================================================
@ -66,36 +80,37 @@
/* /*
** {====================================================== ** {======================================================
** lua_fseek/lua_ftell: configuration for longer offsets ** lua_fseek: configuration for longer offsets
** ======================================================= ** =======================================================
*/ */
#if !defined(lua_fseek) /* { */ #if !defined(lua_fseek) && !defined(LUA_ANSI) /* { */
#if defined(LUA_USE_POSIX) #if defined(LUA_USE_POSIX) /* { */
#define l_fseek(f,o,w) fseeko(f,o,w) #define l_fseek(f,o,w) fseeko(f,o,w)
#define l_ftell(f) ftello(f) #define l_ftell(f) ftello(f)
#define l_seeknum off_t #define l_seeknum off_t
#elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \ #elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \
&& defined(_MSC_VER) && (_MSC_VER >= 1400) && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */
/* Windows (but not DDK) and Visual C++ 2005 or higher */ /* Windows (but not DDK) and Visual C++ 2005 or higher */
#define l_fseek(f,o,w) _fseeki64(f,o,w) #define l_fseek(f,o,w) _fseeki64(f,o,w)
#define l_ftell(f) _ftelli64(f) #define l_ftell(f) _ftelli64(f)
#define l_seeknum __int64 #define l_seeknum __int64
#else #endif /* } */
#endif /* } */
#if !defined(l_fseek) /* default definitions */
#define l_fseek(f,o,w) fseek(f,o,w) #define l_fseek(f,o,w) fseek(f,o,w)
#define l_ftell(f) ftell(f) #define l_ftell(f) ftell(f)
#define l_seeknum long #define l_seeknum long
#endif #endif
#endif /* } */
/* }====================================================== */ /* }====================================================== */
@ -212,14 +227,8 @@ static int io_open (lua_State *L) {
const char *filename = luaL_checkstring(L, 1); const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r"); const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newfile(L); LStream *p = newfile(L);
int i = 0; const char *md = mode; /* to traverse/check mode */
/* check whether 'mode' matches '[rwa]%+?b?' */ luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode");
if (!(mode[i] != '\0' && strchr("rwa", mode[i++]) != NULL &&
(mode[i] != '+' || ++i) && /* skip if char is '+' */
(mode[i] != 'b' || ++i) && /* skip if char is 'b' */
(mode[i] == '\0')))
return luaL_error(L, "invalid mode " LUA_QS
" (should match " LUA_QL("[rwa]%%+?b?") ")", mode);
p->f = fopen(filename, mode); p->f = fopen(filename, mode);
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
} }

@ -1,5 +1,5 @@
/* /*
** $Id: llex.c,v 2.61 2012/01/23 23:05:51 roberto Exp $ ** $Id: llex.c,v 2.63.1.2 2013/08/30 15:49:41 roberto Exp $
** Lexical Analyzer ** Lexical Analyzer
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -73,16 +73,16 @@ void luaX_init (lua_State *L) {
const char *luaX_token2str (LexState *ls, int token) { const char *luaX_token2str (LexState *ls, int token) {
if (token < FIRST_RESERVED) { if (token < FIRST_RESERVED) { /* single-byte symbols? */
lua_assert(token == cast(unsigned char, token)); lua_assert(token == cast(unsigned char, token));
return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) : return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) :
luaO_pushfstring(ls->L, "char(%d)", token); luaO_pushfstring(ls->L, "char(%d)", token);
} }
else { else {
const char *s = luaX_tokens[token - FIRST_RESERVED]; const char *s = luaX_tokens[token - FIRST_RESERVED];
if (token < TK_EOS) if (token < TK_EOS) /* fixed format (symbols and reserved words)? */
return luaO_pushfstring(ls->L, LUA_QS, s); return luaO_pushfstring(ls->L, LUA_QS, s);
else else /* names, strings, and numerals */
return s; return s;
} }
} }
@ -133,6 +133,9 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
setbvalue(o, 1); /* t[string] = true */ setbvalue(o, 1); /* t[string] = true */
luaC_checkGC(L); luaC_checkGC(L);
} }
else { /* string already present */
ts = rawtsvalue(keyfromval(o)); /* re-use value previously stored */
}
L->top--; /* remove string from stack */ L->top--; /* remove string from stack */
return ts; return ts;
} }
@ -313,7 +316,7 @@ static int readhexaesc (LexState *ls) {
int c[3], i; /* keep input for error message */ int c[3], i; /* keep input for error message */
int r = 0; /* result accumulator */ int r = 0; /* result accumulator */
c[0] = 'x'; /* for error message */ c[0] = 'x'; /* for error message */
for (i = 1; i < 3; i++) { /* read two hexa digits */ for (i = 1; i < 3; i++) { /* read two hexadecimal digits */
c[i] = next(ls); c[i] = next(ls);
if (!lisxdigit(c[i])) if (!lisxdigit(c[i]))
escerror(ls, c, i + 1, "hexadecimal digit expected"); escerror(ls, c, i + 1, "hexadecimal digit expected");

@ -1,5 +1,5 @@
/* /*
** $Id: lmathlib.c,v 1.81 2012/05/18 17:47:53 roberto Exp $ ** $Id: lmathlib.c,v 1.83.1.1 2013/04/12 18:48:47 roberto Exp $
** Standard mathematical library ** Standard mathematical library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -17,106 +17,101 @@
#include "lualib.h" #include "lualib.h"
/* macro 'l_tg' allows the addition of an 'l' or 'f' to all math operations */
#if !defined(l_tg)
#define l_tg(x) (x)
#endif
#undef PI #undef PI
#define PI (l_tg(3.1415926535897932384626433832795)) #define PI ((lua_Number)(3.1415926535897932384626433832795))
#define RADIANS_PER_DEGREE (PI/180.0) #define RADIANS_PER_DEGREE ((lua_Number)(PI/180.0))
static int math_abs (lua_State *L) { static int math_abs (lua_State *L) {
lua_pushnumber(L, l_tg(fabs)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_sin (lua_State *L) { static int math_sin (lua_State *L) {
lua_pushnumber(L, l_tg(sin)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_sinh (lua_State *L) { static int math_sinh (lua_State *L) {
lua_pushnumber(L, l_tg(sinh)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_cos (lua_State *L) { static int math_cos (lua_State *L) {
lua_pushnumber(L, l_tg(cos)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_cosh (lua_State *L) { static int math_cosh (lua_State *L) {
lua_pushnumber(L, l_tg(cosh)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_tan (lua_State *L) { static int math_tan (lua_State *L) {
lua_pushnumber(L, l_tg(tan)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_tanh (lua_State *L) { static int math_tanh (lua_State *L) {
lua_pushnumber(L, l_tg(tanh)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_asin (lua_State *L) { static int math_asin (lua_State *L) {
lua_pushnumber(L, l_tg(asin)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_acos (lua_State *L) { static int math_acos (lua_State *L) {
lua_pushnumber(L, l_tg(acos)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_atan (lua_State *L) { static int math_atan (lua_State *L) {
lua_pushnumber(L, l_tg(atan)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(atan)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_atan2 (lua_State *L) { static int math_atan2 (lua_State *L) {
lua_pushnumber(L, l_tg(atan2)(luaL_checknumber(L, 1), lua_pushnumber(L, l_mathop(atan2)(luaL_checknumber(L, 1),
luaL_checknumber(L, 2))); luaL_checknumber(L, 2)));
return 1; return 1;
} }
static int math_ceil (lua_State *L) { static int math_ceil (lua_State *L) {
lua_pushnumber(L, l_tg(ceil)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(ceil)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_floor (lua_State *L) { static int math_floor (lua_State *L) {
lua_pushnumber(L, l_tg(floor)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(floor)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_fmod (lua_State *L) { static int math_fmod (lua_State *L) {
lua_pushnumber(L, l_tg(fmod)(luaL_checknumber(L, 1), lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1),
luaL_checknumber(L, 2))); luaL_checknumber(L, 2)));
return 1; return 1;
} }
static int math_modf (lua_State *L) { static int math_modf (lua_State *L) {
lua_Number ip; lua_Number ip;
lua_Number fp = l_tg(modf)(luaL_checknumber(L, 1), &ip); lua_Number fp = l_mathop(modf)(luaL_checknumber(L, 1), &ip);
lua_pushnumber(L, ip); lua_pushnumber(L, ip);
lua_pushnumber(L, fp); lua_pushnumber(L, fp);
return 2; return 2;
} }
static int math_sqrt (lua_State *L) { static int math_sqrt (lua_State *L) {
lua_pushnumber(L, l_tg(sqrt)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
static int math_pow (lua_State *L) { static int math_pow (lua_State *L) {
lua_pushnumber(L, l_tg(pow)(luaL_checknumber(L, 1), lua_Number x = luaL_checknumber(L, 1);
luaL_checknumber(L, 2))); lua_Number y = luaL_checknumber(L, 2);
lua_pushnumber(L, l_mathop(pow)(x, y));
return 1; return 1;
} }
@ -124,11 +119,11 @@ static int math_log (lua_State *L) {
lua_Number x = luaL_checknumber(L, 1); lua_Number x = luaL_checknumber(L, 1);
lua_Number res; lua_Number res;
if (lua_isnoneornil(L, 2)) if (lua_isnoneornil(L, 2))
res = l_tg(log)(x); res = l_mathop(log)(x);
else { else {
lua_Number base = luaL_checknumber(L, 2); lua_Number base = luaL_checknumber(L, 2);
if (base == 10.0) res = l_tg(log10)(x); if (base == (lua_Number)10.0) res = l_mathop(log10)(x);
else res = l_tg(log)(x)/l_tg(log)(base); else res = l_mathop(log)(x)/l_mathop(log)(base);
} }
lua_pushnumber(L, res); lua_pushnumber(L, res);
return 1; return 1;
@ -136,13 +131,13 @@ static int math_log (lua_State *L) {
#if defined(LUA_COMPAT_LOG10) #if defined(LUA_COMPAT_LOG10)
static int math_log10 (lua_State *L) { static int math_log10 (lua_State *L) {
lua_pushnumber(L, l_tg(log10)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
#endif #endif
static int math_exp (lua_State *L) { static int math_exp (lua_State *L) {
lua_pushnumber(L, l_tg(exp)(luaL_checknumber(L, 1))); lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));
return 1; return 1;
} }
@ -158,14 +153,15 @@ static int math_rad (lua_State *L) {
static int math_frexp (lua_State *L) { static int math_frexp (lua_State *L) {
int e; int e;
lua_pushnumber(L, l_tg(frexp)(luaL_checknumber(L, 1), &e)); lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e));
lua_pushinteger(L, e); lua_pushinteger(L, e);
return 2; return 2;
} }
static int math_ldexp (lua_State *L) { static int math_ldexp (lua_State *L) {
lua_pushnumber(L, l_tg(ldexp)(luaL_checknumber(L, 1), lua_Number x = luaL_checknumber(L, 1);
luaL_checkint(L, 2))); int ep = luaL_checkint(L, 2);
lua_pushnumber(L, l_mathop(ldexp)(x, ep));
return 1; return 1;
} }
@ -210,15 +206,15 @@ static int math_random (lua_State *L) {
} }
case 1: { /* only upper limit */ case 1: { /* only upper limit */
lua_Number u = luaL_checknumber(L, 1); lua_Number u = luaL_checknumber(L, 1);
luaL_argcheck(L, 1.0 <= u, 1, "interval is empty"); luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty");
lua_pushnumber(L, l_tg(floor)(r*u) + 1.0); /* int in [1, u] */ lua_pushnumber(L, l_mathop(floor)(r*u) + (lua_Number)(1.0)); /* [1, u] */
break; break;
} }
case 2: { /* lower and upper limits */ case 2: { /* lower and upper limits */
lua_Number l = luaL_checknumber(L, 1); lua_Number l = luaL_checknumber(L, 1);
lua_Number u = luaL_checknumber(L, 2); lua_Number u = luaL_checknumber(L, 2);
luaL_argcheck(L, l <= u, 2, "interval is empty"); luaL_argcheck(L, l <= u, 2, "interval is empty");
lua_pushnumber(L, l_tg(floor)(r*(u-l+1)) + l); /* int in [l, u] */ lua_pushnumber(L, l_mathop(floor)(r*(u-l+1)) + l); /* [l, u] */
break; break;
} }
default: return luaL_error(L, "wrong number of arguments"); default: return luaL_error(L, "wrong number of arguments");

@ -1,5 +1,5 @@
/* /*
** $Id: lmem.c,v 1.84 2012/05/23 15:41:53 roberto Exp $ ** $Id: lmem.c,v 1.84.1.1 2013/04/12 18:48:47 roberto Exp $
** Interface to Memory Manager ** Interface to Memory Manager
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: loadlib.c,v 1.111 2012/05/30 12:33:44 roberto Exp $ ** $Id: loadlib.c,v 1.111.1.1 2013/04/12 18:48:47 roberto Exp $
** Dynamic library loader for Lua ** Dynamic library loader for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
** **

@ -1,5 +1,5 @@
/* /*
** $Id: lobject.c,v 2.55 2011/11/30 19:30:16 roberto Exp $ ** $Id: lobject.c,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $
** Some generic functions over Lua objects ** Some generic functions over Lua objects
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -104,7 +104,7 @@ static int isneg (const char **s) {
static lua_Number readhexa (const char **s, lua_Number r, int *count) { static lua_Number readhexa (const char **s, lua_Number r, int *count) {
for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */ for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */
r = (r * 16.0) + cast_num(luaO_hexavalue(cast_uchar(**s))); r = (r * cast_num(16.0)) + cast_num(luaO_hexavalue(cast_uchar(**s)));
(*count)++; (*count)++;
} }
return r; return r;
@ -149,7 +149,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
*endptr = cast(char *, s); /* valid up to here */ *endptr = cast(char *, s); /* valid up to here */
ret: ret:
if (neg) r = -r; if (neg) r = -r;
return ldexp(r, e); return l_mathop(ldexp)(r, e);
} }
#endif #endif
@ -171,8 +171,7 @@ int luaO_str2d (const char *s, size_t len, lua_Number *result) {
static void pushstr (lua_State *L, const char *str, size_t l) { static void pushstr (lua_State *L, const char *str, size_t l) {
setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); setsvalue2s(L, L->top++, luaS_newlstr(L, str, l));
incr_top(L);
} }
@ -182,8 +181,8 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
for (;;) { for (;;) {
const char *e = strchr(fmt, '%'); const char *e = strchr(fmt, '%');
if (e == NULL) break; if (e == NULL) break;
setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); luaD_checkstack(L, 2); /* fmt + item */
incr_top(L); pushstr(L, fmt, e - fmt);
switch (*(e+1)) { switch (*(e+1)) {
case 's': { case 's': {
const char *s = va_arg(argp, char *); const char *s = va_arg(argp, char *);
@ -198,13 +197,11 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
break; break;
} }
case 'd': { case 'd': {
setnvalue(L->top, cast_num(va_arg(argp, int))); setnvalue(L->top++, cast_num(va_arg(argp, int)));
incr_top(L);
break; break;
} }
case 'f': { case 'f': {
setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); setnvalue(L->top++, cast_num(va_arg(argp, l_uacNumber)));
incr_top(L);
break; break;
} }
case 'p': { case 'p': {
@ -226,6 +223,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
n += 2; n += 2;
fmt = e+2; fmt = e+2;
} }
luaD_checkstack(L, 1);
pushstr(L, fmt, strlen(fmt)); pushstr(L, fmt, strlen(fmt));
if (n > 0) luaV_concat(L, n + 1); if (n > 0) luaV_concat(L, n + 1);
return svalue(L->top - 1); return svalue(L->top - 1);

@ -1,5 +1,5 @@
/* /*
** $Id: lopcodes.c,v 1.49 2012/05/14 13:34:18 roberto Exp $ ** $Id: lopcodes.c,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $
** Opcodes for Lua virtual machine ** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: loslib.c,v 1.39 2012/05/23 15:37:09 roberto Exp $ ** $Id: loslib.c,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $
** Standard Operating System library ** Standard Operating System library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -98,7 +98,7 @@ static int os_remove (lua_State *L) {
static int os_rename (lua_State *L) { static int os_rename (lua_State *L) {
const char *fromname = luaL_checkstring(L, 1); const char *fromname = luaL_checkstring(L, 1);
const char *toname = luaL_checkstring(L, 2); const char *toname = luaL_checkstring(L, 2);
return luaL_fileresult(L, rename(fromname, toname) == 0, fromname); return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
} }

@ -1,5 +1,5 @@
/* /*
** $Id: lparser.c,v 2.128 2012/05/20 14:51:23 roberto Exp $ ** $Id: lparser.c,v 2.130.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua Parser ** Lua Parser
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -245,7 +245,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
static int searchvar (FuncState *fs, TString *n) { static int searchvar (FuncState *fs, TString *n) {
int i; int i;
for (i=fs->nactvar-1; i >= 0; i--) { for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
if (luaS_eqstr(n, getlocvar(fs, i)->varname)) if (luaS_eqstr(n, getlocvar(fs, i)->varname))
return i; return i;
} }
@ -512,12 +512,15 @@ static Proto *addprototype (LexState *ls) {
/* /*
** codes instruction to create new closure in parent function ** codes instruction to create new closure in parent function.
** The OP_CLOSURE instruction must use the last available register,
** so that, if it invokes the GC, the GC knows which registers
** are in use at that time.
*/ */
static void codeclosure (LexState *ls, expdesc *v) { static void codeclosure (LexState *ls, expdesc *v) {
FuncState *fs = ls->fs->prev; FuncState *fs = ls->fs->prev;
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1));
luaK_exp2nextreg(fs, v); /* fix it at stack top (for GC) */ luaK_exp2nextreg(fs, v); /* fix it at the last register */
} }

@ -1,5 +1,5 @@
/* /*
** $Id: lstate.c,v 2.98 2012/05/30 12:33:44 roberto Exp $ ** $Id: lstate.c,v 2.99.1.2 2013/11/08 17:45:31 roberto Exp $
** Global State ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -48,7 +48,7 @@
*/ */
#if !defined(luai_makeseed) #if !defined(luai_makeseed)
#include <time.h> #include <time.h>
#define luai_makeseed() cast(size_t, time(NULL)) #define luai_makeseed() cast(unsigned int, time(NULL))
#endif #endif
@ -192,6 +192,8 @@ static void f_luaopen (lua_State *L, void *ud) {
g->memerrmsg = luaS_newliteral(L, MEMERRMSG); g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
luaS_fix(g->memerrmsg); /* it should never be collected */ luaS_fix(g->memerrmsg); /* it should never be collected */
g->gcrunning = 1; /* allow gc */ g->gcrunning = 1; /* allow gc */
g->version = lua_version(NULL);
luai_userstateopen(L);
} }
@ -222,6 +224,8 @@ static void close_state (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
luaF_close(L, L->stack); /* close all upvalues for this thread */ luaF_close(L, L->stack); /* close all upvalues for this thread */
luaC_freeallobjects(L); /* collect all objects */ luaC_freeallobjects(L); /* collect all objects */
if (g->version) /* closing a fully built state? */
luai_userstateclose(L);
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
luaZ_freebuffer(L, &g->buff); luaZ_freebuffer(L, &g->buff);
freestack(L); freestack(L);
@ -287,7 +291,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
setnilvalue(&g->l_registry); setnilvalue(&g->l_registry);
luaZ_initbuffer(L, &g->buff); luaZ_initbuffer(L, &g->buff);
g->panic = NULL; g->panic = NULL;
g->version = lua_version(NULL); g->version = NULL;
g->gcstate = GCSpause; g->gcstate = GCSpause;
g->allgc = NULL; g->allgc = NULL;
g->finobj = NULL; g->finobj = NULL;
@ -306,8 +310,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
close_state(L); close_state(L);
L = NULL; L = NULL;
} }
else
luai_userstateopen(L);
return L; return L;
} }
@ -315,7 +317,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
LUA_API void lua_close (lua_State *L) { LUA_API void lua_close (lua_State *L) {
L = G(L)->mainthread; /* only the main thread can be closed */ L = G(L)->mainthread; /* only the main thread can be closed */
lua_lock(L); lua_lock(L);
luai_userstateclose(L);
close_state(L); close_state(L);
} }

@ -1,5 +1,5 @@
/* /*
** $Id: lstring.c,v 2.24 2012/05/11 14:14:42 roberto Exp $ ** $Id: lstring.c,v 2.26.1.1 2013/04/12 18:48:47 roberto Exp $
** String table (keeps all strings handled by Lua) ** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -49,7 +49,7 @@ int luaS_eqstr (TString *a, TString *b) {
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
unsigned int h = seed ^ l; unsigned int h = seed ^ cast(unsigned int, l);
size_t l1; size_t l1;
size_t step = (l >> LUAI_HASHLIMIT) + 1; size_t step = (l >> LUAI_HASHLIMIT) + 1;
for (l1 = l; l1 >= step; l1 -= step) for (l1 = l; l1 >= step; l1 -= step)
@ -139,7 +139,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
o = gch(o)->next) { o = gch(o)->next) {
TString *ts = rawgco2ts(o); TString *ts = rawgco2ts(o);
if (h == ts->tsv.hash && if (h == ts->tsv.hash &&
ts->tsv.len == l && l == ts->tsv.len &&
(memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */ if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */
changewhite(o); /* resurrect it */ changewhite(o); /* resurrect it */

@ -1,5 +1,5 @@
/* /*
** $Id: lstrlib.c,v 1.176 2012/05/23 15:37:09 roberto Exp $ ** $Id: lstrlib.c,v 1.178.1.1 2013/04/12 18:48:47 roberto Exp $
** Standard library for string operations and pattern-matching ** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -194,7 +194,9 @@ static int str_dump (lua_State *L) {
#define CAP_UNFINISHED (-1) #define CAP_UNFINISHED (-1)
#define CAP_POSITION (-2) #define CAP_POSITION (-2)
typedef struct MatchState { typedef struct MatchState {
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
const char *src_init; /* init of source string */ const char *src_init; /* init of source string */
const char *src_end; /* end ('\0') of source string */ const char *src_end; /* end ('\0') of source string */
const char *p_end; /* end ('\0') of pattern */ const char *p_end; /* end ('\0') of pattern */
@ -207,6 +209,16 @@ typedef struct MatchState {
} MatchState; } MatchState;
/* recursive function */
static const char *match (MatchState *ms, const char *s, const char *p);
/* maximum recursion depth for 'match' */
#if !defined(MAXCCALLS)
#define MAXCCALLS 200
#endif
#define L_ESC '%' #define L_ESC '%'
#define SPECIALS "^$*+?.([%-" #define SPECIALS "^$*+?.([%-"
@ -294,19 +306,22 @@ static int matchbracketclass (int c, const char *p, const char *ec) {
} }
static int singlematch (int c, const char *p, const char *ep) { static int singlematch (MatchState *ms, const char *s, const char *p,
const char *ep) {
if (s >= ms->src_end)
return 0;
else {
int c = uchar(*s);
switch (*p) { switch (*p) {
case '.': return 1; /* matches any char */ case '.': return 1; /* matches any char */
case L_ESC: return match_class(c, uchar(*(p+1))); case L_ESC: return match_class(c, uchar(*(p+1)));
case '[': return matchbracketclass(c, p, ep-1); case '[': return matchbracketclass(c, p, ep-1);
default: return (uchar(*p) == c); default: return (uchar(*p) == c);
} }
}
} }
static const char *match (MatchState *ms, const char *s, const char *p);
static const char *matchbalance (MatchState *ms, const char *s, static const char *matchbalance (MatchState *ms, const char *s,
const char *p) { const char *p) {
if (p >= ms->p_end - 1) if (p >= ms->p_end - 1)
@ -331,7 +346,7 @@ static const char *matchbalance (MatchState *ms, const char *s,
static const char *max_expand (MatchState *ms, const char *s, static const char *max_expand (MatchState *ms, const char *s,
const char *p, const char *ep) { const char *p, const char *ep) {
ptrdiff_t i = 0; /* counts maximum expand for item */ ptrdiff_t i = 0; /* counts maximum expand for item */
while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep)) while (singlematch(ms, s + i, p, ep))
i++; i++;
/* keeps trying to match with the maximum repetitions */ /* keeps trying to match with the maximum repetitions */
while (i>=0) { while (i>=0) {
@ -349,7 +364,7 @@ static const char *min_expand (MatchState *ms, const char *s,
const char *res = match(ms, s, ep+1); const char *res = match(ms, s, ep+1);
if (res != NULL) if (res != NULL)
return res; return res;
else if (s<ms->src_end && singlematch(uchar(*s), p, ep)) else if (singlematch(ms, s, p, ep))
s++; /* try with one more repetition */ s++; /* try with one more repetition */
else return NULL; else return NULL;
} }
@ -393,30 +408,36 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
static const char *match (MatchState *ms, const char *s, const char *p) { static const char *match (MatchState *ms, const char *s, const char *p) {
if (ms->matchdepth-- == 0)
luaL_error(ms->L, "pattern too complex");
init: /* using goto's to optimize tail recursion */ init: /* using goto's to optimize tail recursion */
if (p == ms->p_end) /* end of pattern? */ if (p != ms->p_end) { /* end of pattern? */
return s; /* match succeeded */
switch (*p) { switch (*p) {
case '(': { /* start capture */ case '(': { /* start capture */
if (*(p+1) == ')') /* position capture? */ if (*(p + 1) == ')') /* position capture? */
return start_capture(ms, s, p+2, CAP_POSITION); s = start_capture(ms, s, p + 2, CAP_POSITION);
else else
return start_capture(ms, s, p+1, CAP_UNFINISHED); s = start_capture(ms, s, p + 1, CAP_UNFINISHED);
break;
} }
case ')': { /* end capture */ case ')': { /* end capture */
return end_capture(ms, s, p+1); s = end_capture(ms, s, p + 1);
break;
} }
case '$': { case '$': {
if ((p+1) == ms->p_end) /* is the `$' the last char in pattern? */ if ((p + 1) != ms->p_end) /* is the `$' the last char in pattern? */
return (s == ms->src_end) ? s : NULL; /* check end of string */ goto dflt; /* no; go to default */
else goto dflt; s = (s == ms->src_end) ? s : NULL; /* check end of string */
break;
} }
case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ case L_ESC: { /* escaped sequences not in the format class[*+?-]? */
switch (*(p+1)) { switch (*(p + 1)) {
case 'b': { /* balanced string? */ case 'b': { /* balanced string? */
s = matchbalance(ms, s, p+2); s = matchbalance(ms, s, p + 2);
if (s == NULL) return NULL; if (s != NULL) {
p+=4; goto init; /* else return match(ms, s, p+4); */ p += 4; goto init; /* return match(ms, s, p + 4); */
} /* else fail (s == NULL) */
break;
} }
case 'f': { /* frontier? */ case 'f': { /* frontier? */
const char *ep; char previous; const char *ep; char previous;
@ -425,47 +446,67 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
luaL_error(ms->L, "missing " LUA_QL("[") " after " luaL_error(ms->L, "missing " LUA_QL("[") " after "
LUA_QL("%%f") " in pattern"); LUA_QL("%%f") " in pattern");
ep = classend(ms, p); /* points to what is next */ ep = classend(ms, p); /* points to what is next */
previous = (s == ms->src_init) ? '\0' : *(s-1); previous = (s == ms->src_init) ? '\0' : *(s - 1);
if (matchbracketclass(uchar(previous), p, ep-1) || if (!matchbracketclass(uchar(previous), p, ep - 1) &&
!matchbracketclass(uchar(*s), p, ep-1)) return NULL; matchbracketclass(uchar(*s), p, ep - 1)) {
p=ep; goto init; /* else return match(ms, s, ep); */ p = ep; goto init; /* return match(ms, s, ep); */
}
s = NULL; /* match failed */
break;
} }
case '0': case '1': case '2': case '3': case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7': case '4': case '5': case '6': case '7':
case '8': case '9': { /* capture results (%0-%9)? */ case '8': case '9': { /* capture results (%0-%9)? */
s = match_capture(ms, s, uchar(*(p+1))); s = match_capture(ms, s, uchar(*(p + 1)));
if (s == NULL) return NULL; if (s != NULL) {
p+=2; goto init; /* else return match(ms, s, p+2) */ p += 2; goto init; /* return match(ms, s, p + 2) */
}
break;
} }
default: goto dflt; default: goto dflt;
} }
break;
} }
default: dflt: { /* pattern class plus optional suffix */ default: dflt: { /* pattern class plus optional suffix */
const char *ep = classend(ms, p); /* points to what is next */ const char *ep = classend(ms, p); /* points to optional suffix */
int m = s < ms->src_end && singlematch(uchar(*s), p, ep); /* does not match at least once? */
switch (*ep) { if (!singlematch(ms, s, p, ep)) {
if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */
p = ep + 1; goto init; /* return match(ms, s, ep + 1); */
}
else /* '+' or no suffix */
s = NULL; /* fail */
}
else { /* matched once */
switch (*ep) { /* handle optional suffix */
case '?': { /* optional */ case '?': { /* optional */
const char *res; const char *res;
if (m && ((res=match(ms, s+1, ep+1)) != NULL)) if ((res = match(ms, s + 1, ep + 1)) != NULL)
return res; s = res;
p=ep+1; goto init; /* else return match(ms, s, ep+1); */ else {
} p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */
case '*': { /* 0 or more repetitions */
return max_expand(ms, s, p, ep);
} }
case '+': { /* 1 or more repetitions */ break;
return (m ? max_expand(ms, s+1, p, ep) : NULL);
} }
case '-': { /* 0 or more repetitions (minimum) */ case '+': /* 1 or more repetitions */
return min_expand(ms, s, p, ep); s++; /* 1 match already done */
/* go through */
case '*': /* 0 or more repetitions */
s = max_expand(ms, s, p, ep);
break;
case '-': /* 0 or more repetitions (minimum) */
s = min_expand(ms, s, p, ep);
break;
default: /* no suffix */
s++; p = ep; goto init; /* return match(ms, s + 1, ep); */
} }
default: {
if (!m) return NULL;
s++; p=ep; goto init; /* else return match(ms, s+1, ep); */
} }
break;
} }
} }
} }
ms->matchdepth++;
return s;
} }
@ -561,12 +602,14 @@ static int str_find_aux (lua_State *L, int find) {
p++; lp--; /* skip anchor character */ p++; lp--; /* skip anchor character */
} }
ms.L = L; ms.L = L;
ms.matchdepth = MAXCCALLS;
ms.src_init = s; ms.src_init = s;
ms.src_end = s + ls; ms.src_end = s + ls;
ms.p_end = p + lp; ms.p_end = p + lp;
do { do {
const char *res; const char *res;
ms.level = 0; ms.level = 0;
lua_assert(ms.matchdepth == MAXCCALLS);
if ((res=match(&ms, s1, p)) != NULL) { if ((res=match(&ms, s1, p)) != NULL) {
if (find) { if (find) {
lua_pushinteger(L, s1 - s + 1); /* start */ lua_pushinteger(L, s1 - s + 1); /* start */
@ -600,6 +643,7 @@ static int gmatch_aux (lua_State *L) {
const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp); const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp);
const char *src; const char *src;
ms.L = L; ms.L = L;
ms.matchdepth = MAXCCALLS;
ms.src_init = s; ms.src_init = s;
ms.src_end = s+ls; ms.src_end = s+ls;
ms.p_end = p + lp; ms.p_end = p + lp;
@ -608,6 +652,7 @@ static int gmatch_aux (lua_State *L) {
src++) { src++) {
const char *e; const char *e;
ms.level = 0; ms.level = 0;
lua_assert(ms.matchdepth == MAXCCALLS);
if ((e = match(&ms, src, p)) != NULL) { if ((e = match(&ms, src, p)) != NULL) {
lua_Integer newstart = e-s; lua_Integer newstart = e-s;
if (e == src) newstart++; /* empty match? go at least one position */ if (e == src) newstart++; /* empty match? go at least one position */
@ -705,12 +750,14 @@ static int str_gsub (lua_State *L) {
p++; lp--; /* skip anchor character */ p++; lp--; /* skip anchor character */
} }
ms.L = L; ms.L = L;
ms.matchdepth = MAXCCALLS;
ms.src_init = src; ms.src_init = src;
ms.src_end = src+srcl; ms.src_end = src+srcl;
ms.p_end = p + lp; ms.p_end = p + lp;
while (n < max_s) { while (n < max_s) {
const char *e; const char *e;
ms.level = 0; ms.level = 0;
lua_assert(ms.matchdepth == MAXCCALLS);
e = match(&ms, src, p); e = match(&ms, src, p);
if (e) { if (e) {
n++; n++;

@ -1,5 +1,5 @@
/* /*
** $Id: ltable.c,v 2.71 2012/05/23 15:37:09 roberto Exp $ ** $Id: ltable.c,v 2.72.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua tables (hash) ** Lua tables (hash)
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -480,13 +480,13 @@ const TValue *luaH_getstr (Table *t, TString *key) {
*/ */
const TValue *luaH_get (Table *t, const TValue *key) { const TValue *luaH_get (Table *t, const TValue *key) {
switch (ttype(key)) { switch (ttype(key)) {
case LUA_TNIL: return luaO_nilobject;
case LUA_TSHRSTR: return luaH_getstr(t, rawtsvalue(key)); case LUA_TSHRSTR: return luaH_getstr(t, rawtsvalue(key));
case LUA_TNIL: return luaO_nilobject;
case LUA_TNUMBER: { case LUA_TNUMBER: {
int k; int k;
lua_Number n = nvalue(key); lua_Number n = nvalue(key);
lua_number2int(k, n); lua_number2int(k, n);
if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ if (luai_numeq(cast_num(k), n)) /* index is int? */
return luaH_getint(t, k); /* use specialized version */ return luaH_getint(t, k); /* use specialized version */
/* else go through */ /* else go through */
} }

@ -1,5 +1,5 @@
/* /*
** $Id: ltablib.c,v 1.63 2011/11/28 17:26:30 roberto Exp $ ** $Id: ltablib.c,v 1.65.1.1 2013/04/12 18:48:47 roberto Exp $
** Library for Table Manipulation ** Library for Table Manipulation
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -16,8 +16,8 @@
#include "lualib.h" #include "lualib.h"
#define aux_getn(L,n) \ #define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n))
(luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n))
#if defined(LUA_COMPAT_MAXN) #if defined(LUA_COMPAT_MAXN)
@ -49,7 +49,7 @@ static int tinsert (lua_State *L) {
case 3: { case 3: {
int i; int i;
pos = luaL_checkint(L, 2); /* 2nd argument is the position */ pos = luaL_checkint(L, 2); /* 2nd argument is the position */
if (pos > e) e = pos; /* `grow' array if necessary */ luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
for (i = e; i > pos; i--) { /* move up elements */ for (i = e; i > pos; i--) { /* move up elements */
lua_rawgeti(L, 1, i-1); lua_rawgeti(L, 1, i-1);
lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ lua_rawseti(L, 1, i); /* t[i] = t[i-1] */
@ -66,17 +66,17 @@ static int tinsert (lua_State *L) {
static int tremove (lua_State *L) { static int tremove (lua_State *L) {
int e = aux_getn(L, 1); int size = aux_getn(L, 1);
int pos = luaL_optint(L, 2, e); int pos = luaL_optint(L, 2, size);
if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ if (pos != size) /* validate 'pos' if given */
return 0; /* nothing to remove */ luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
lua_rawgeti(L, 1, pos); /* result = t[pos] */ lua_rawgeti(L, 1, pos); /* result = t[pos] */
for ( ;pos<e; pos++) { for ( ; pos < size; pos++) {
lua_rawgeti(L, 1, pos+1); lua_rawgeti(L, 1, pos+1);
lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */ lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */
} }
lua_pushnil(L); lua_pushnil(L);
lua_rawseti(L, 1, e); /* t[e] = nil */ lua_rawseti(L, 1, pos); /* t[pos] = nil */
return 1; return 1;
} }

@ -1,5 +1,5 @@
/* /*
** $Id: ltm.c,v 2.14 2011/06/02 19:31:40 roberto Exp $ ** $Id: ltm.c,v 2.14.1.1 2013/04/12 18:48:47 roberto Exp $
** Tag methods ** Tag methods
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lua.c,v 1.205 2012/05/23 15:37:09 roberto Exp $ ** $Id: lua.c,v 1.206.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua stand-alone interpreter ** Lua stand-alone interpreter
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -237,7 +237,6 @@ static const char *get_prompt (lua_State *L, int firstline) {
lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
p = lua_tostring(L, -1); p = lua_tostring(L, -1);
if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
lua_pop(L, 1); /* remove global */
return p; return p;
} }
@ -263,7 +262,9 @@ static int pushline (lua_State *L, int firstline) {
char *b = buffer; char *b = buffer;
size_t l; size_t l;
const char *prmt = get_prompt(L, firstline); const char *prmt = get_prompt(L, firstline);
if (lua_readline(L, b, prmt) == 0) int readstatus = lua_readline(L, b, prmt);
lua_pop(L, 1); /* remove result from 'get_prompt' */
if (readstatus == 0)
return 0; /* no input */ return 0; /* no input */
l = strlen(b); l = strlen(b);
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ if (l > 0 && b[l-1] == '\n') /* line ends with newline? */

@ -203,7 +203,7 @@ int main(int argc, char* argv[])
} }
/* /*
** $Id: print.c,v 1.68 2011/09/30 10:21:20 lhf Exp $ ** $Id: print.c,v 1.69 2013/07/04 01:03:46 lhf Exp $
** print bytecodes ** print bytecodes
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -251,7 +251,7 @@ static void PrintString(const TString* ts)
static void PrintConstant(const Proto* f, int i) static void PrintConstant(const Proto* f, int i)
{ {
const TValue* o=&f->k[i]; const TValue* o=&f->k[i];
switch (ttype(o)) switch (ttypenv(o))
{ {
case LUA_TNIL: case LUA_TNIL:
printf("nil"); printf("nil");

@ -1,5 +1,5 @@
/* /*
** $Id: lundump.c,v 2.22 2012/05/08 13:53:33 roberto Exp $ ** $Id: lundump.c,v 2.22.1.1 2013/04/12 18:48:47 roberto Exp $
** load precompiled Lua chunks ** load precompiled Lua chunks
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -1,5 +1,5 @@
/* /*
** $Id: lvm.c,v 2.152 2012/06/08 15:14:04 roberto Exp $ ** $Id: lvm.c,v 2.155.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -83,7 +83,7 @@ static void traceexec (lua_State *L) {
if (counthook) if (counthook)
L->hookcount = 1; /* undo decrement to zero */ L->hookcount = 1; /* undo decrement to zero */
ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yieled */ ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
ci->func = L->top - 1; /* protect stack below results */ ci->func = L->top - 1; /* protect stack below results */
luaD_throw(L, LUA_YIELD); luaD_throw(L, LUA_YIELD);
} }
@ -98,7 +98,6 @@ static void callTM (lua_State *L, const TValue *f, const TValue *p1,
setobj2s(L, L->top++, p2); /* 2nd argument */ setobj2s(L, L->top++, p2); /* 2nd argument */
if (!hasres) /* no result? 'p3' is third argument */ if (!hasres) /* no result? 'p3' is third argument */
setobj2s(L, L->top++, p3); /* 3rd argument */ setobj2s(L, L->top++, p3); /* 3rd argument */
luaD_checkstack(L, 0);
/* metamethod may yield only when called from Lua code */ /* metamethod may yield only when called from Lua code */
luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci)); luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci));
if (hasres) { /* if has result, move it to its place */ if (hasres) { /* if has result, move it to its place */

@ -1,5 +1,5 @@
/* /*
** $Id: lzio.c,v 1.35 2012/05/14 13:34:18 roberto Exp $ ** $Id: lzio.c,v 1.35.1.1 2013/04/12 18:48:47 roberto Exp $
** Buffered streams ** Buffered streams
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */

@ -31,6 +31,9 @@ keybinding add Ctrl-Alt-S@dwarfmode/Default quicksave
keybinding add Ctrl-Shift-N gui/rename keybinding add Ctrl-Shift-N gui/rename
keybinding add Ctrl-Shift-T "gui/rename unit-profession" keybinding add Ctrl-Shift-T "gui/rename unit-profession"
# a dfhack prompt in df. Sublime text like.
keybinding add Ctrl-Shift-P command-prompt
############################## ##############################
# Generic adv mode bindings # # Generic adv mode bindings #
############################## ##############################
@ -90,6 +93,9 @@ keybinding add Alt-A@dwarfmode/QueryBuilding/Some/SiegeEngine gui/siege-engine
# military weapon auto-select # military weapon auto-select
keybinding add Ctrl-W@layer_military/Equip/Customize/View gui/choose-weapons keybinding add Ctrl-W@layer_military/Equip/Customize/View gui/choose-weapons
# military copy uniform
keybinding add Ctrl-C@layer_military/Uniforms gui/clone-uniform
# minecart Guide path # minecart Guide path
keybinding add Alt-P@dwarfmode/Hauling/DefineStop/Cond/Guide gui/guide-path keybinding add Alt-P@dwarfmode/Hauling/DefineStop/Cond/Guide gui/guide-path

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

@ -811,6 +811,15 @@ bool Core::loadScriptFile(color_ostream &out, string fname, bool silent)
} }
} }
// Load dfhack.init in a dedicated thread (non-interactive console mode)
void fInitthread(void * iodata)
{
IODATA * iod = ((IODATA*) iodata);
Core * core = iod->core;
color_ostream_proxy out(core->getConsole());
core->loadScriptFile(out, "dfhack.init", true);
}
// A thread function... for the interactive console. // A thread function... for the interactive console.
void fIOthread(void * iodata) void fIOthread(void * iodata)
{ {
@ -822,7 +831,7 @@ void fIOthread(void * iodata)
main_history.load("dfhack.history"); main_history.load("dfhack.history");
Console & con = core->getConsole(); Console & con = core->getConsole();
if(plug_mgr == 0 || core == 0) if (plug_mgr == 0)
{ {
con.printerr("Something horrible happened in Core's constructor...\n"); con.printerr("Something horrible happened in Core's constructor...\n");
return; return;
@ -1008,16 +1017,24 @@ bool Core::Init()
IODATA *temp = new IODATA; IODATA *temp = new IODATA;
temp->core = this; temp->core = this;
temp->plug_mgr = plug_mgr; temp->plug_mgr = plug_mgr;
HotkeyMutex = new mutex();
HotkeyCond = new condition_variable();
if (!is_text_mode) if (!is_text_mode)
{ {
cerr << "Starting IO thread.\n"; cerr << "Starting IO thread.\n";
// create IO thread // create IO thread
thread * IO = new thread(fIOthread, (void *) temp); thread * IO = new thread(fIOthread, (void *) temp);
} }
else
{
cerr << "Starting dfhack.init thread.\n";
thread * init = new thread(fInitthread, (void *) temp);
}
cerr << "Starting DF input capture thread.\n"; cerr << "Starting DF input capture thread.\n";
// set up hotkey capture // set up hotkey capture
HotkeyMutex = new mutex();
HotkeyCond = new condition_variable();
thread * HK = new thread(fHKthread, (void *) temp); thread * HK = new thread(fHKthread, (void *) temp);
screen_window = new Windows::top_level_window(); screen_window = new Windows::top_level_window();
screen_window->addChild(new Windows::dfhack_dummy(5,10)); screen_window->addChild(new Windows::dfhack_dummy(5,10));

@ -565,7 +565,7 @@ static int dfhack_matinfo_find(lua_State *state)
{ {
std::vector<std::string> tokens; std::vector<std::string> tokens;
for (int i = 1; i < argc; i++) for (int i = 1; i <= argc; i++)
tokens.push_back(luaL_checkstring(state, i)); tokens.push_back(luaL_checkstring(state, i));
info.find(tokens); info.find(tokens);
@ -1279,6 +1279,9 @@ static std::string getHackPath() { return Core::getInstance().getHackPath(); }
static bool isWorldLoaded() { return Core::getInstance().isWorldLoaded(); } static bool isWorldLoaded() { return Core::getInstance().isWorldLoaded(); }
static bool isMapLoaded() { return Core::getInstance().isMapLoaded(); } static bool isMapLoaded() { return Core::getInstance().isMapLoaded(); }
static std::string df2utf(std::string s) { return DF2UTF(s); }
static std::string utf2df(std::string s) { return UTF2DF(s); }
static const LuaWrapper::FunctionReg dfhack_module[] = { static const LuaWrapper::FunctionReg dfhack_module[] = {
WRAP(getOSType), WRAP(getOSType),
WRAP(getDFVersion), WRAP(getDFVersion),
@ -1288,6 +1291,8 @@ static const LuaWrapper::FunctionReg dfhack_module[] = {
WRAP(isWorldLoaded), WRAP(isWorldLoaded),
WRAP(isMapLoaded), WRAP(isMapLoaded),
WRAPM(Translation, TranslateName), WRAPM(Translation, TranslateName),
WRAP(df2utf),
WRAP(utf2df),
{ NULL, NULL } { NULL, NULL }
}; };
@ -1302,6 +1307,10 @@ static const LuaWrapper::FunctionReg dfhack_gui_module[] = {
WRAPM(Gui, getSelectedUnit), WRAPM(Gui, getSelectedUnit),
WRAPM(Gui, getSelectedItem), WRAPM(Gui, getSelectedItem),
WRAPM(Gui, getSelectedBuilding), WRAPM(Gui, getSelectedBuilding),
WRAPM(Gui, writeToGamelog),
WRAPM(Gui, makeAnnouncement),
WRAPM(Gui, addCombatReport),
WRAPM(Gui, addCombatReportAuto),
WRAPM(Gui, showAnnouncement), WRAPM(Gui, showAnnouncement),
WRAPM(Gui, showZoomAnnouncement), WRAPM(Gui, showZoomAnnouncement),
WRAPM(Gui, showPopupAnnouncement), WRAPM(Gui, showPopupAnnouncement),
@ -1322,10 +1331,13 @@ static const LuaWrapper::FunctionReg dfhack_job_module[] = {
WRAPM(Job,getSpecificRef), WRAPM(Job,getSpecificRef),
WRAPM(Job,getHolder), WRAPM(Job,getHolder),
WRAPM(Job,getWorker), WRAPM(Job,getWorker),
WRAPM(Job,setJobCooldown),
WRAPM(Job,removeWorker),
WRAPM(Job,checkBuildingsNow), WRAPM(Job,checkBuildingsNow),
WRAPM(Job,checkDesignationsNow), WRAPM(Job,checkDesignationsNow),
WRAPM(Job,isSuitableItem), WRAPM(Job,isSuitableItem),
WRAPM(Job,isSuitableMaterial), WRAPM(Job,isSuitableMaterial),
WRAPM(Job,getName),
WRAPN(is_equal, jobEqual), WRAPN(is_equal, jobEqual),
WRAPN(is_item_equal, jobItemEqual), WRAPN(is_item_equal, jobItemEqual),
{ NULL, NULL } { NULL, NULL }
@ -1363,6 +1375,9 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, getVisibleName), WRAPM(Units, getVisibleName),
WRAPM(Units, getIdentity), WRAPM(Units, getIdentity),
WRAPM(Units, getNemesis), WRAPM(Units, getNemesis),
WRAPM(Units, isHidingCurse),
WRAPM(Units, getPhysicalAttrValue),
WRAPM(Units, getMentalAttrValue),
WRAPM(Units, isCrazed), WRAPM(Units, isCrazed),
WRAPM(Units, isOpposedToLife), WRAPM(Units, isOpposedToLife),
WRAPM(Units, hasExtravision), WRAPM(Units, hasExtravision),
@ -1379,6 +1394,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, getEffectiveSkill), WRAPM(Units, getEffectiveSkill),
WRAPM(Units, getExperience), WRAPM(Units, getExperience),
WRAPM(Units, computeMovementSpeed), WRAPM(Units, computeMovementSpeed),
WRAPM(Units, computeSlowdownFactor),
WRAPM(Units, getProfessionName), WRAPM(Units, getProfessionName),
WRAPM(Units, getCasteProfessionName), WRAPM(Units, getCasteProfessionName),
WRAPM(Units, getProfessionColor), WRAPM(Units, getProfessionColor),
@ -1460,6 +1476,8 @@ static const LuaWrapper::FunctionReg dfhack_items_module[] = {
WRAPM(Items, isCasteMaterial), WRAPM(Items, isCasteMaterial),
WRAPM(Items, getSubtypeCount), WRAPM(Items, getSubtypeCount),
WRAPM(Items, getSubtypeDef), WRAPM(Items, getSubtypeDef),
WRAPM(Items, getItemBaseValue),
WRAPM(Items, getValue),
WRAPN(moveToGround, items_moveToGround), WRAPN(moveToGround, items_moveToGround),
WRAPN(moveToContainer, items_moveToContainer), WRAPN(moveToContainer, items_moveToContainer),
WRAPN(moveToBuilding, items_moveToBuilding), WRAPN(moveToBuilding, items_moveToBuilding),
@ -2194,7 +2212,21 @@ static int internal_diffscan(lua_State *L)
lua_pushnil(L); lua_pushnil(L);
return 1; return 1;
} }
static int internal_getDir(lua_State *L)
{
luaL_checktype(L,1,LUA_TSTRING);
std::string dir=lua_tostring(L,1);
std::vector<std::string> files;
DFHack::getdir(dir,files);
lua_newtable(L);
for(int i=0;i<files.size();i++)
{
lua_pushinteger(L,i+1);
lua_pushstring(L,files[i].c_str());
lua_settable(L,-3);
}
return 1;
}
static const luaL_Reg dfhack_internal_funcs[] = { static const luaL_Reg dfhack_internal_funcs[] = {
{ "getAddress", internal_getAddress }, { "getAddress", internal_getAddress },
{ "setAddress", internal_setAddress }, { "setAddress", internal_setAddress },
@ -2207,6 +2239,7 @@ static const luaL_Reg dfhack_internal_funcs[] = {
{ "memcmp", internal_memcmp }, { "memcmp", internal_memcmp },
{ "memscan", internal_memscan }, { "memscan", internal_memscan },
{ "diffscan", internal_diffscan }, { "diffscan", internal_diffscan },
{ "getDir", internal_getDir },
{ NULL, NULL } { NULL, NULL }
}; };

@ -246,28 +246,6 @@ static int getdir (string dir, vector<string> &files)
return 0; 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;
}
uint32_t Process::getTickCount() uint32_t Process::getTickCount()
{ {
struct timeval tp; struct timeval tp;

@ -181,28 +181,6 @@ static int getdir (string dir, vector<string> &files)
return 0; 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;
}
uint32_t Process::getTickCount() uint32_t Process::getTickCount()
{ {
struct timeval tp; struct timeval tp;

@ -24,63 +24,12 @@ distribution.
#include "Internal.h" #include "Internal.h"
#define _WIN32_WINNT 0x0501 // needed for INPUT struct #define _WIN32_WINNT 0x0501
#define WINVER 0x0501 // OpenThread(), PSAPI, Toolhelp32 #define WINVER 0x0501
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <psapi.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 <cstring>
#include <cstdio> #include <cstdio>
@ -106,8 +55,6 @@ namespace DFHack
sections = 0; sections = 0;
}; };
HANDLE my_handle; HANDLE my_handle;
vector <HANDLE> threads;
vector <HANDLE> stoppedthreads;
uint32_t my_pid; uint32_t my_pid;
IMAGE_NT_HEADERS pe_header; IMAGE_NT_HEADERS pe_header;
IMAGE_SECTION_HEADER * sections; IMAGE_SECTION_HEADER * sections;
@ -138,7 +85,7 @@ Process::Process(VersionInfoFactory * factory)
// read from this process // read from this process
try try
{ {
uint32_t pe_offset = Process::readDWord(d->base+0x3C); uint32_t pe_offset = readDWord(d->base+0x3C);
read(d->base + pe_offset, sizeof(d->pe_header), (uint8_t *)&(d->pe_header)); 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; const size_t sectionsSize = sizeof(IMAGE_SECTION_HEADER) * d->pe_header.FileHeader.NumberOfSections;
d->sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize); d->sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize);
@ -151,24 +98,10 @@ Process::Process(VersionInfoFactory * factory)
VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(d->pe_header.FileHeader.TimeDateStamp); VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(d->pe_header.FileHeader.TimeDateStamp);
if(vinfo) if(vinfo)
{ {
vector<uint32_t> threads_ids;
if(!getThreadIDs( threads_ids ))
{
// thread enumeration failed.
return;
}
identified = true; identified = true;
// give the process a data model and memory layout fixed for the base of first module // give the process a data model and memory layout fixed for the base of first module
my_descriptor = new VersionInfo(*vinfo); my_descriptor = new VersionInfo(*vinfo);
my_descriptor->rebaseTo(getBase()); my_descriptor->rebaseTo(getBase());
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;
}
} }
} }
@ -176,41 +109,10 @@ Process::~Process()
{ {
// destroy our rebased copy of the memory descriptor // destroy our rebased copy of the memory descriptor
delete my_descriptor; delete my_descriptor;
for(size_t i = 0; i < d->threads.size(); i++)
CloseHandle(d->threads[i]);
if(d->sections != NULL) if(d->sections != NULL)
free(d->sections); 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 typedef struct _MEMORY_BASIC_INFORMATION
{ {

@ -55,6 +55,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include "modules/Units.h" #include "modules/Units.h"
#include "modules/World.h" #include "modules/World.h"
#include "LuaTools.h"
#include "DataDefs.h" #include "DataDefs.h"
#include "df/ui.h" #include "df/ui.h"
#include "df/ui_advmode.h" #include "df/ui_advmode.h"
@ -656,6 +658,8 @@ CoreService::CoreService() {
addMethod("CoreSuspend", &CoreService::CoreSuspend, SF_DONT_SUSPEND); addMethod("CoreSuspend", &CoreService::CoreSuspend, SF_DONT_SUSPEND);
addMethod("CoreResume", &CoreService::CoreResume, SF_DONT_SUSPEND); addMethod("CoreResume", &CoreService::CoreResume, SF_DONT_SUSPEND);
addMethod("RunLua", &CoreService::RunLua);
// Functions: // Functions:
addFunction("GetVersion", GetVersion, SF_DONT_SUSPEND); addFunction("GetVersion", GetVersion, SF_DONT_SUSPEND);
addFunction("GetDFVersion", GetDFVersion, SF_DONT_SUSPEND); addFunction("GetDFVersion", GetDFVersion, SF_DONT_SUSPEND);
@ -730,3 +734,85 @@ command_result CoreService::CoreResume(color_ostream &stream, const EmptyMessage
cnt->set_value(--suspend_depth); cnt->set_value(--suspend_depth);
return CR_OK; return CR_OK;
} }
namespace {
struct LuaFunctionData {
command_result rv;
const dfproto::CoreRunLuaRequest *in;
StringListMessage *out;
};
}
command_result CoreService::RunLua(color_ostream &stream,
const dfproto::CoreRunLuaRequest *in,
StringListMessage *out)
{
auto L = Lua::Core::State;
LuaFunctionData data = { CR_FAILURE, in, out };
lua_pushcfunction(L, doRunLuaFunction);
lua_pushlightuserdata(L, &data);
if (!Lua::Core::SafeCall(stream, 1, 0))
return CR_FAILURE;
return data.rv;
}
int CoreService::doRunLuaFunction(lua_State *L)
{
color_ostream &out = *Lua::GetOutput(L);
auto &args = *(LuaFunctionData*)lua_touserdata(L, 1);
// Verify module name
std::string module = args.in->module();
size_t len = module.size();
bool valid = false;
if (len > 4)
{
if (module.substr(0,4) == "rpc.")
valid = true;
else if ((module[len-4] == '.' || module[len-4] == '-') && module.substr(len-3) != "rpc")
valid = true;
}
if (!valid)
{
args.rv = CR_WRONG_USAGE;
out.printerr("Only modules named rpc.* or *.rpc or *-rpc may be called.\n");
return 0;
}
// Prepare function and arguments
lua_settop(L, 0);
if (!Lua::PushModulePublic(out, L, module.c_str(), args.in->function().c_str())
|| lua_isnil(L, 1))
{
args.rv = CR_NOT_FOUND;
return 0;
}
luaL_checkstack(L, args.in->arguments_size(), "too many arguments");
for (int i = 0; i < args.in->arguments_size(); i++)
lua_pushstring(L, args.in->arguments(i).c_str());
// Call
lua_call(L, args.in->arguments_size(), LUA_MULTRET);
// Store results
int nresults = lua_gettop(L);
for (int i = 1; i <= nresults; i++)
{
size_t len;
const char *data = lua_tolstring(L, i, &len);
args.out->add_value(std::string(data, len));
}
args.rv = CR_OK;
return 0;
}

@ -72,20 +72,54 @@ int main (int argc, char *argv[])
if (!client.connect()) if (!client.connect())
return 2; return 2;
command_result rv;
if (strcmp(argv[1], "--lua") == 0)
{
if (argc <= 3)
{
fprintf(stderr, "Usage: dfhack-run --lua <module> <function> [args...]\n");
return 2;
}
RemoteFunction<dfproto::CoreRunLuaRequest,dfproto::StringListMessage> run_call;
if (!run_call.bind(&client, "RunLua"))
{
fprintf(stderr, "No RunLua protocol function found.");
return 3;
}
run_call.in()->set_module(argv[2]);
run_call.in()->set_function(argv[3]);
for (int i = 4; i < argc; i++)
run_call.in()->add_arguments(argv[i]);
rv = run_call();
out.flush();
if (rv == CR_OK)
{
for (int i = 0; i < run_call.out()->value_size(); i++)
printf("%s%s", (i>0?"\t":""), run_call.out()->value(i).c_str());
printf("\n");
}
}
else
{
// Call the command // Call the command
std::vector<std::string> args; std::vector<std::string> args;
for (int i = 2; i < argc; i++) for (int i = 2; i < argc; i++)
args.push_back(argv[i]); args.push_back(argv[i]);
command_result rv = client.run_command(argv[1], args); rv = client.run_command(argv[1], args);
}
if (rv != CR_OK) { out.flush();
if (rv == CR_NOT_IMPLEMENTED)
out.printerr("%s is not a recognized command.\n", argv[1]);
if (rv != CR_OK)
return 1; return 1;
}
out.flush();
return 0; return 0;
} }

@ -390,7 +390,7 @@ namespace df
} }
virtual bool resize(void *ptr, int size) { virtual bool resize(void *ptr, int size) {
((container*)ptr)->resize(size*8); ((container*)ptr)->resize((size+7)/8);
return true; return true;
} }

@ -43,29 +43,6 @@ namespace DFHack
class VersionInfoFactory; class VersionInfoFactory;
class PlatformSpecific; class PlatformSpecific;
/**
* 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 * Structure describing a section of virtual memory inside a process
* \ingroup grp_context * \ingroup grp_context
@ -265,8 +242,6 @@ namespace DFHack
{ {
return identified; return identified;
}; };
/// find the thread IDs of the process
bool getThreadIDs(std::vector<uint32_t> & threads );
/// get virtual memory ranges of the process (what is mapped where) /// get virtual memory ranges of the process (what is mapped where)
void getMemRanges(std::vector<t_memrange> & ranges ); void getMemRanges(std::vector<t_memrange> & ranges );

@ -48,6 +48,8 @@ namespace DFHack
DFHACK_EXPORT void strVectorToRepeatedField(RepeatedPtrField<std::string> *pf, DFHACK_EXPORT void strVectorToRepeatedField(RepeatedPtrField<std::string> *pf,
const std::vector<std::string> &vec); const std::vector<std::string> &vec);
using dfproto::StringListMessage;
/** /**
* Represent bitfield bits as a repeated string field. * Represent bitfield bits as a repeated string field.
*/ */
@ -131,6 +133,8 @@ namespace DFHack
class CoreService : public RPCService { class CoreService : public RPCService {
int suspend_depth; int suspend_depth;
static int doRunLuaFunction(lua_State *L);
public: public:
CoreService(); CoreService();
~CoreService(); ~CoreService();
@ -144,5 +148,9 @@ namespace DFHack
// For batching // For batching
command_result CoreSuspend(color_ostream &stream, const EmptyMessage*, IntMessage *cnt); command_result CoreSuspend(color_ostream &stream, const EmptyMessage*, IntMessage *cnt);
command_result CoreResume(color_ostream &stream, const EmptyMessage*, IntMessage *cnt); command_result CoreResume(color_ostream &stream, const EmptyMessage*, IntMessage *cnt);
command_result RunLua(color_ostream &stream,
const dfproto::CoreRunLuaRequest *in,
StringListMessage *out);
}; };
} }

@ -0,0 +1 @@
friend struct df::interfacest;

@ -35,6 +35,8 @@ distribution.
#include "df/init.h" #include "df/init.h"
#include "df/ui.h" #include "df/ui.h"
#include "df/announcement_type.h" #include "df/announcement_type.h"
#include "df/announcement_flags.h"
#include "df/unit_report_type.h"
namespace df { namespace df {
struct viewscreen; struct viewscreen;
@ -97,13 +99,20 @@ namespace DFHack
DFHACK_EXPORT bool any_building_hotkey(df::viewscreen *top); DFHACK_EXPORT bool any_building_hotkey(df::viewscreen *top);
DFHACK_EXPORT df::building *getSelectedBuilding(color_ostream &out, bool quiet = false); DFHACK_EXPORT df::building *getSelectedBuilding(color_ostream &out, bool quiet = false);
// Low-level API that gives full control over announcements and reports
DFHACK_EXPORT void writeToGamelog(std::string message);
DFHACK_EXPORT int makeAnnouncement(df::announcement_type type, df::announcement_flags mode, df::coord pos, std::string message, int color = 7, bool bright = true);
DFHACK_EXPORT bool addCombatReport(df::unit *unit, df::unit_report_type slot, int report_index);
DFHACK_EXPORT bool addCombatReportAuto(df::unit *unit, df::announcement_flags mode, int report_index);
// Show a plain announcement, or a titan-style popup message // Show a plain announcement, or a titan-style popup message
DFHACK_EXPORT void showAnnouncement(std::string message, int color = 7, bool bright = true); DFHACK_EXPORT void showAnnouncement(std::string message, int color = 7, bool bright = true);
DFHACK_EXPORT void showZoomAnnouncement(df::announcement_type type, df::coord pos, std::string message, int color = 7, bool bright = true); DFHACK_EXPORT void showZoomAnnouncement(df::announcement_type type, df::coord pos, std::string message, int color = 7, bool bright = true);
DFHACK_EXPORT void showPopupAnnouncement(std::string message, int color = 7, bool bright = true); DFHACK_EXPORT void showPopupAnnouncement(std::string message, int color = 7, bool bright = true);
// Show an announcement with effects determined by announcements.txt // Show an announcement with effects determined by announcements.txt
DFHACK_EXPORT void showAutoAnnouncement(df::announcement_type type, df::coord pos, std::string message, int color = 7, bool bright = true); DFHACK_EXPORT void showAutoAnnouncement(df::announcement_type type, df::coord pos, std::string message, int color = 7, bool bright = true, df::unit *unit1 = NULL, df::unit *unit2 = NULL);
/* /*
* Cursor and window coords * Cursor and window coords

@ -173,5 +173,11 @@ DFHACK_EXPORT bool remove(MapExtras::MapCache &mc, df::item *item, bool no_uncat
/// Detaches the items from its current location and turns it into a projectile /// Detaches the items from its current location and turns it into a projectile
DFHACK_EXPORT df::proj_itemst *makeProjectile(MapExtras::MapCache &mc, df::item *item); DFHACK_EXPORT df::proj_itemst *makeProjectile(MapExtras::MapCache &mc, df::item *item);
/// Gets value of base-quality item with specified type and material
DFHACK_EXPORT int getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat_type, int32_t mat_subtype);
/// Gets the value of a specific item, ignoring civ values and trade agreements
DFHACK_EXPORT int getValue(df::item *item);
} }
} }

@ -63,6 +63,9 @@ namespace DFHack
DFHACK_EXPORT df::building *getHolder(df::job *job); DFHACK_EXPORT df::building *getHolder(df::job *job);
DFHACK_EXPORT df::unit *getWorker(df::job *job); DFHACK_EXPORT df::unit *getWorker(df::job *job);
DFHACK_EXPORT void setJobCooldown(df::building *workshop, df::unit *worker, int cooldown = 100);
DFHACK_EXPORT bool removeWorker(df::job *job, int cooldown = 100);
// Instruct the game to check and assign workers // Instruct the game to check and assign workers
DFHACK_EXPORT void checkBuildingsNow(); DFHACK_EXPORT void checkBuildingsNow();
DFHACK_EXPORT void checkDesignationsNow(); DFHACK_EXPORT void checkDesignationsNow();
@ -78,6 +81,7 @@ namespace DFHack
DFHACK_EXPORT bool isSuitableItem(df::job_item *item, df::item_type itype, int isubtype); DFHACK_EXPORT bool isSuitableItem(df::job_item *item, df::item_type itype, int isubtype);
DFHACK_EXPORT bool isSuitableMaterial(df::job_item *item, int mat_type, int mat_index); DFHACK_EXPORT bool isSuitableMaterial(df::job_item *item, int mat_type, int mat_index);
DFHACK_EXPORT std::string getName(df::job *job);
} }
DFHACK_EXPORT bool operator== (const df::job_item &a, const df::job_item &b); DFHACK_EXPORT bool operator== (const df::job_item &a, const df::job_item &b);

@ -102,8 +102,8 @@ namespace Random
}; };
#ifndef DFHACK_RANDOM_CPP #ifndef DFHACK_RANDOM_CPP
extern template void MersenneRNG::unitvector<float>(float *p, int size); extern template void DFHACK_IMPORT MersenneRNG::unitvector<float>(float *p, int size);
extern template void MersenneRNG::unitvector<double>(double *p, int size); extern template void DFHACK_IMPORT MersenneRNG::unitvector<double>(double *p, int size);
#endif #endif
/* /*

@ -241,6 +241,7 @@ DFHACK_EXPORT int getEffectiveSkill(df::unit *unit, df::job_skill skill_id);
DFHACK_EXPORT int getExperience(df::unit *unit, df::job_skill skill_id, bool total = false); DFHACK_EXPORT int getExperience(df::unit *unit, df::job_skill skill_id, bool total = false);
DFHACK_EXPORT int computeMovementSpeed(df::unit *unit); DFHACK_EXPORT int computeMovementSpeed(df::unit *unit);
DFHACK_EXPORT float computeSlowdownFactor(df::unit *unit);
struct NoblePosition { struct NoblePosition {
df::historical_entity *entity; df::historical_entity *entity;

@ -366,11 +366,28 @@ function dfhack.getSavePath()
end end
if dfhack.is_core_context then if dfhack.is_core_context then
local function loadInitFile(path, name)
local env = setmetatable({ SAVE_PATH = path }, { __index = base_env })
local f,perr = loadfile(name, 't', env)
if f == nil then
if not string.match(perr, 'No such file or directory') then
dfhack.printerr(perr)
end
elseif safecall(f) then
if not internal.save_init then
internal.save_init = {}
end
table.insert(internal.save_init, env)
end
end
dfhack.onStateChange.DFHACK_PER_SAVE = function(op) dfhack.onStateChange.DFHACK_PER_SAVE = function(op)
if op == SC_WORLD_LOADED or op == SC_WORLD_UNLOADED then if op == SC_WORLD_LOADED or op == SC_WORLD_UNLOADED then
if internal.save_init then if internal.save_init then
if internal.save_init.onUnload then for k,v in ipairs(internal.save_init) do
safecall(internal.save_init.onUnload) if v.onUnload then
safecall(v.onUnload)
end
end end
internal.save_init = nil internal.save_init = nil
end end
@ -378,18 +395,24 @@ if dfhack.is_core_context then
local path = dfhack.getSavePath() local path = dfhack.getSavePath()
if path and op == SC_WORLD_LOADED then if path and op == SC_WORLD_LOADED then
local env = setmetatable({ SAVE_PATH = path }, { __index = base_env }) loadInitFile(path, path..'/raw/init.lua')
local f,perr = loadfile(path..'/raw/init.lua', 't', env)
if f == nil then local dirlist = dfhack.internal.getDir(path..'/raw/init.d/')
if not string.match(perr, 'No such file or directory') then if dirlist then
dfhack.printerr(perr) table.sort(dirlist)
for i,name in ipairs(dirlist) do
if string.match(name,'%.lua$') then
loadInitFile(path, path..'/raw/init.d/'..name)
end end
elseif safecall(f) then
internal.save_init = env
end end
end end
elseif internal.save_init and internal.save_init.onStateChange then end
safecall(internal.save_init.onStateChange, op) elseif internal.save_init then
for k,v in ipairs(internal.save_init) do
if v.onStateChange then
safecall(v.onStateChange, op)
end
end
end end
end end
end end

Some files were not shown because too many files have changed in this diff Show More