Conflicts:
	library/xml
develop
Japa 2014-04-26 09:23:21 +05:30
commit b74d0da872
151 changed files with 5062 additions and 1396 deletions

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>
<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> </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% }

@ -1119,6 +1119,12 @@ 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="#id20">Gui module</a></h3>
@ -1154,6 +1160,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,9 +1190,9 @@ 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>
@ -1194,6 +1220,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>
@ -1300,6 +1334,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>
@ -1904,6 +1942,10 @@ 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>
@ -2115,6 +2157,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
@ -3260,8 +3305,9 @@ The <tt class="docutils literal">name</tt> argument should be the name stem, as
<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="#id62">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 +3317,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>

@ -812,6 +812,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 +862,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 +901,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 +938,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.
@ -1033,6 +1077,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*.
@ -1760,6 +1809,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 +2045,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.
@ -3187,8 +3244,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 +3258,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``.

28
NEWS

@ -1,6 +1,32 @@
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.
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)
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
@ -2357,12 +2414,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 +2473,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 +2515,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 +2650,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 +2814,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 +2829,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 +2863,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,11 +1149,12 @@ 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,7 +306,12 @@ 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)));
@ -302,9 +319,7 @@ static int singlematch (int c, const char *p, const char *ep) {
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,
@ -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;
@ -426,46 +447,66 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
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;
else {
p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */
} }
case '*': { /* 0 or more repetitions */ break;
return max_expand(ms, s, p, ep);
}
case '+': { /* 1 or more repetitions */
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,6 +1331,8 @@ 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),
@ -1363,6 +1374,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 +1393,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),
@ -2194,7 +2209,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 +2236,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);
}; };
} }

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

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

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

@ -147,6 +147,21 @@ function make_sort_order(data,ordering)
return index return index
end end
--[[
Iterate a 'list' structure, e.g. df.global.world.job_list
--]]
local function next_df_list(s,link)
link = link.next
if link then
return link, link.item
end
end
function listpairs(list)
return next_df_list, nil, list
end
--[[ --[[
Recursively assign data into a table. Recursively assign data into a table.
--]] --]]
@ -457,6 +472,14 @@ function getBuildingCenter(building)
return xyz2pos(building.centerx, building.centery, building.z) return xyz2pos(building.centerx, building.centery, building.z)
end end
function getItemDescription(item,mode)
return call_with_string(item, 'getItemDescription', mode or 0)
end
function getItemDescriptionPrefix(item,mode)
return call_with_string(item, 'getItemDescriptionPrefix', mode or 0)
end
-- Split the string by the given delimiter -- Split the string by the given delimiter
function split_string(self, delimiter) function split_string(self, delimiter)
local result = { } local result = { }

@ -87,6 +87,8 @@ using namespace DFHack;
#include "df/announcements.h" #include "df/announcements.h"
#include "df/stop_depart_condition.h" #include "df/stop_depart_condition.h"
#include "df/route_stockpile_link.h" #include "df/route_stockpile_link.h"
#include "df/game_mode.h"
#include "df/unit.h"
using namespace df::enums; using namespace df::enums;
using df::global::gview; using df::global::gview;
@ -97,6 +99,7 @@ using df::global::world;
using df::global::selection_rect; using df::global::selection_rect;
using df::global::ui_menu_width; using df::global::ui_menu_width;
using df::global::ui_area_map_width; using df::global::ui_area_map_width;
using df::global::gamemode;
static df::layer_object_listst *getLayerList(df::viewscreen_layer *layer, int idx) static df::layer_object_listst *getLayerList(df::viewscreen_layer *layer, int idx)
{ {
@ -1080,13 +1083,26 @@ df::building *Gui::getSelectedBuilding(color_ostream &out, bool quiet)
// //
static void doShowAnnouncement( DFHACK_EXPORT void Gui::writeToGamelog(std::string message)
df::announcement_type type, df::coord pos, std::string message, int color, bool bright {
) { if (message.empty())
return;
std::ofstream fseed("gamelog.txt", std::ios::out | std::ios::app);
if(fseed.is_open())
fseed << message << std::endl;
fseed.close();
}
DFHACK_EXPORT int Gui::makeAnnouncement(df::announcement_type type, df::announcement_flags flags, df::coord pos, std::string message, int color, bool bright)
{
using df::global::world; using df::global::world;
using df::global::cur_year; using df::global::cur_year;
using df::global::cur_year_tick; using df::global::cur_year_tick;
if (message.empty())
return -1;
int year = 0, year_time = 0; int year = 0, year_time = 0;
if (cur_year && cur_year_tick) if (cur_year && cur_year_tick)
@ -1102,6 +1118,31 @@ static void doShowAnnouncement(
year_time = last->time; year_time = last->time;
} }
// Apply the requested effects
writeToGamelog(message);
if (flags.bits.DO_MEGA || flags.bits.PAUSE || flags.bits.RECENTER)
{
resetDwarfmodeView(flags.bits.DO_MEGA || flags.bits.PAUSE);
if (flags.bits.RECENTER && pos.isValid())
revealInDwarfmodeMap(pos, true);
if (flags.bits.DO_MEGA)
showPopupAnnouncement(message, color, bright);
}
bool display = false;
if (gamemode == NULL)
display = flags.bits.A_DISPLAY || flags.bits.D_DISPLAY;
else if (*gamemode == game_mode::ADVENTURE)
display = flags.bits.A_DISPLAY;
else
display = flags.bits.D_DISPLAY;
// Generate the report objects
int report_idx = world->status.reports.size();
bool continued = false; bool continued = false;
while (!message.empty()) while (!message.empty())
@ -1117,7 +1158,6 @@ static void doShowAnnouncement(
new_rep->time = year_time; new_rep->time = year_time;
new_rep->flags.bits.continuation = continued; new_rep->flags.bits.continuation = continued;
new_rep->flags.bits.announcement = true;
int size = std::min(message.size(), (size_t)73); int size = std::min(message.size(), (size_t)73);
new_rep->text = message.substr(0, size); new_rep->text = message.substr(0, size);
@ -1129,20 +1169,114 @@ static void doShowAnnouncement(
new_rep->id = world->status.next_report_id++; new_rep->id = world->status.next_report_id++;
world->status.reports.push_back(new_rep); world->status.reports.push_back(new_rep);
if (display)
{
new_rep->flags.bits.announcement = true;
world->status.announcements.push_back(new_rep); world->status.announcements.push_back(new_rep);
world->status.display_timer = 2000; world->status.display_timer = 2000;
} }
} }
return report_idx;
}
bool Gui::addCombatReport(df::unit *unit, df::unit_report_type slot, int report_index)
{
using df::global::world;
CHECK_INVALID_ARGUMENT(is_valid_enum_item(slot));
auto &vec = world->status.reports;
auto report = vector_get(vec, report_index);
if (!unit || !report)
return false;
// Check that it is a new report
auto &rvec = unit->reports.log[slot];
if (!rvec.empty() && rvec.back() >= report->id)
return false;
// Add the report
rvec.push_back(report->id);
unit->reports.last_year[slot] = report->year;
unit->reports.last_year_tick[slot] = report->time;
switch (slot) {
case unit_report_type::Combat:
world->status.flags.bits.combat = true;
break;
case unit_report_type::Hunting:
world->status.flags.bits.hunting = true;
break;
case unit_report_type::Sparring:
world->status.flags.bits.sparring = true;
break;
}
// And all the continuation lines
for (size_t i = report_index+1; i < vec.size() && vec[i]->flags.bits.continuation; i++)
rvec.push_back(vec[i]->id);
return true;
}
bool Gui::addCombatReportAuto(df::unit *unit, df::announcement_flags mode, int report_index)
{
using df::global::world;
auto &vec = world->status.reports;
auto report = vector_get(vec, report_index);
if (!unit || !report)
return false;
bool ok = false;
if (mode.bits.UNIT_COMBAT_REPORT)
{
if (unit->flags2.bits.sparring)
ok |= addCombatReport(unit, unit_report_type::Sparring, report_index);
else if (unit->job.current_job && unit->job.current_job->job_type == job_type::Hunt)
ok |= addCombatReport(unit, unit_report_type::Hunting, report_index);
else
ok |= addCombatReport(unit, unit_report_type::Combat, report_index);
}
if (mode.bits.UNIT_COMBAT_REPORT_ALL_ACTIVE)
{
FOR_ENUM_ITEMS(unit_report_type, slot)
{
if (!unit->reports.log[slot].empty() &&
unit->reports.last_year[slot] == report->year &&
(report->time - unit->reports.last_year_tick[slot]) <= 500)
{
ok |= addCombatReport(unit, slot, report_index);
}
}
}
return ok;
}
void Gui::showAnnouncement(std::string message, int color, bool bright) void Gui::showAnnouncement(std::string message, int color, bool bright)
{ {
doShowAnnouncement(df::announcement_type(0), df::coord(), message, color, bright); df::announcement_flags mode(0);
mode.bits.D_DISPLAY = mode.bits.A_DISPLAY = true;
makeAnnouncement(df::announcement_type(0), mode, df::coord(), message, color, bright);
} }
void Gui::showZoomAnnouncement( void Gui::showZoomAnnouncement(
df::announcement_type type, df::coord pos, std::string message, int color, bool bright df::announcement_type type, df::coord pos, std::string message, int color, bool bright
) { ) {
doShowAnnouncement(type, pos, message, color, bright); df::announcement_flags mode(0);
mode.bits.D_DISPLAY = mode.bits.A_DISPLAY = true;
makeAnnouncement(type, mode, pos, message, color, bright);
} }
void Gui::showPopupAnnouncement(std::string message, int color, bool bright) void Gui::showPopupAnnouncement(std::string message, int color, bool bright)
@ -1157,26 +1291,21 @@ void Gui::showPopupAnnouncement(std::string message, int color, bool bright)
} }
void Gui::showAutoAnnouncement( void Gui::showAutoAnnouncement(
df::announcement_type type, df::coord pos, std::string message, int color, bool bright df::announcement_type type, df::coord pos, std::string message, int color, bool bright,
df::unit *unit1, df::unit *unit2
) { ) {
using df::global::announcements; using df::global::announcements;
df::announcement_flags flags; df::announcement_flags flags(0);
flags.bits.D_DISPLAY = flags.bits.A_DISPLAY = true;
if (is_valid_enum_item(type) && announcements) if (is_valid_enum_item(type) && announcements)
flags = announcements->flags[type]; flags = announcements->flags[type];
doShowAnnouncement(type, pos, message, color, bright); int id = makeAnnouncement(type, flags, pos, message, color, bright);
if (flags.bits.DO_MEGA || flags.bits.PAUSE || flags.bits.RECENTER) addCombatReportAuto(unit1, flags, id);
{ addCombatReportAuto(unit2, flags, id);
resetDwarfmodeView(flags.bits.DO_MEGA || flags.bits.PAUSE);
if (flags.bits.RECENTER && pos.isValid())
revealInDwarfmodeMap(pos, true);
}
if (flags.bits.DO_MEGA)
showPopupAnnouncement(message, color, bright);
} }
df::viewscreen *Gui::getCurViewscreen(bool skip_dismissed) df::viewscreen *Gui::getCurViewscreen(bool skip_dismissed)

@ -705,7 +705,7 @@ static void resetUnitInvFlags(df::unit *unit, df::unit_inventory_item *inv_item)
} }
else if (inv_item->mode == df::unit_inventory_item::StuckIn) else if (inv_item->mode == df::unit_inventory_item::StuckIn)
{ {
unit->flags3.bits.unk2 = false; unit->flags3.bits.stuck_weapon_computed = false;
} }
} }

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